mirror of
https://github.com/vector-im/element-android.git
synced 2024-11-15 01:35:07 +08:00
Room list: rework invitations
This commit is contained in:
parent
b25098c52d
commit
07309c90e1
@ -29,7 +29,7 @@ import im.vector.riotredesign.features.themes.ThemeUtils
|
||||
/**
|
||||
* Set a text in the TextView, or set visibility to GONE if the text is null
|
||||
*/
|
||||
fun TextView.setTextOrHide(newText: String?, hideWhenBlank: Boolean = true) {
|
||||
fun TextView.setTextOrHide(newText: CharSequence?, hideWhenBlank: Boolean = true) {
|
||||
if (newText == null
|
||||
|| (newText.isBlank() && hideWhenBlank)) {
|
||||
isVisible = false
|
||||
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2019 New Vector Ltd
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotredesign.features.home.room.list
|
||||
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
import com.airbnb.epoxy.EpoxyModelClass
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.epoxy.VectorEpoxyHolder
|
||||
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.riotredesign.core.extensions.setTextOrHide
|
||||
import im.vector.riotredesign.features.home.AvatarRenderer
|
||||
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_room_invitation)
|
||||
abstract class RoomInvitationItem : VectorEpoxyModel<RoomInvitationItem.Holder>() {
|
||||
|
||||
@EpoxyAttribute lateinit var avatarRenderer: AvatarRenderer
|
||||
@EpoxyAttribute lateinit var roomName: CharSequence
|
||||
@EpoxyAttribute lateinit var roomId: String
|
||||
@EpoxyAttribute var secondLine: CharSequence? = null
|
||||
@EpoxyAttribute var avatarUrl: String? = null
|
||||
@EpoxyAttribute var listener: (() -> Unit)? = null
|
||||
@EpoxyAttribute var acceptListener: (() -> Unit)? = null
|
||||
@EpoxyAttribute var rejectListener: (() -> Unit)? = null
|
||||
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
holder.rootView.setOnClickListener { listener?.invoke() }
|
||||
holder.acceptView.setOnClickListener { acceptListener?.invoke() }
|
||||
holder.rejectView.setOnClickListener { rejectListener?.invoke() }
|
||||
holder.titleView.text = roomName
|
||||
holder.subtitleView.setTextOrHide(secondLine)
|
||||
avatarRenderer.render(avatarUrl, roomId, roomName.toString(), holder.avatarImageView)
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val titleView by bind<TextView>(R.id.roomInvitationNameView)
|
||||
val subtitleView by bind<TextView>(R.id.roomInvitationSubTitle)
|
||||
val acceptView by bind<Button>(R.id.roomInvitationAccept)
|
||||
val rejectView by bind<Button>(R.id.roomInvitationReject)
|
||||
val avatarImageView by bind<ImageView>(R.id.roomInvitationAvatarImageView)
|
||||
val rootView by bind<ViewGroup>(R.id.itemRoomInvitationLayout)
|
||||
}
|
||||
|
||||
}
|
@ -45,7 +45,7 @@ data class RoomListParams(
|
||||
) : Parcelable
|
||||
|
||||
|
||||
class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Callback, OnBackPressed, FabMenuView.Listener {
|
||||
class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Listener, OnBackPressed, FabMenuView.Listener {
|
||||
|
||||
enum class DisplayMode(@StringRes val titleRes: Int) {
|
||||
HOME(R.string.bottom_action_home),
|
||||
@ -135,7 +135,7 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Callback, O
|
||||
val stateRestorer = LayoutManagerStateRestorer(layoutManager).register()
|
||||
epoxyRecyclerView.layoutManager = layoutManager
|
||||
epoxyRecyclerView.itemAnimator = RoomListAnimator()
|
||||
roomController.callback = this
|
||||
roomController.listener = this
|
||||
roomController.addModelBuildListener { it.dispatchTo(stateRestorer) }
|
||||
stateView.contentView = epoxyRecyclerView
|
||||
epoxyRecyclerView.setController(roomController)
|
||||
@ -233,6 +233,14 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Callback, O
|
||||
roomListViewModel.accept(RoomListActions.SelectRoom(room))
|
||||
}
|
||||
|
||||
override fun onAcceptRoomInvitation(room: RoomSummary) {
|
||||
vectorBaseActivity.notImplemented("Accept room invitation")
|
||||
}
|
||||
|
||||
override fun onRejectRoomInvitation(room: RoomSummary) {
|
||||
vectorBaseActivity.notImplemented("Reject room invitation")
|
||||
}
|
||||
|
||||
override fun onToggleRoomCategory(roomCategory: RoomCategory) {
|
||||
roomListViewModel.accept(RoomListActions.ToggleCategory(roomCategory))
|
||||
}
|
||||
|
@ -26,7 +26,7 @@ class RoomSummaryController @Inject constructor(private val stringProvider: Stri
|
||||
private val roomSummaryItemFactory: RoomSummaryItemFactory
|
||||
) : TypedEpoxyController<RoomListViewState>() {
|
||||
|
||||
var callback: Callback? = null
|
||||
var listener: Listener? = null
|
||||
|
||||
override fun buildModels(viewState: RoomListViewState) {
|
||||
val roomSummaries = viewState.asyncFilteredRooms()
|
||||
@ -36,7 +36,7 @@ class RoomSummaryController @Inject constructor(private val stringProvider: Stri
|
||||
} else {
|
||||
val isExpanded = viewState.isCategoryExpanded(category)
|
||||
buildRoomCategory(viewState, summaries, category.titleRes, viewState.isCategoryExpanded(category)) {
|
||||
callback?.onToggleRoomCategory(category)
|
||||
listener?.onToggleRoomCategory(category)
|
||||
}
|
||||
if (isExpanded) {
|
||||
buildRoomModels(summaries)
|
||||
@ -76,14 +76,16 @@ class RoomSummaryController @Inject constructor(private val stringProvider: Stri
|
||||
private fun buildRoomModels(summaries: List<RoomSummary>) {
|
||||
summaries.forEach { roomSummary ->
|
||||
roomSummaryItemFactory
|
||||
.create(roomSummary) { callback?.onRoomSelected(it) }
|
||||
.create(roomSummary, listener)
|
||||
.addTo(this)
|
||||
}
|
||||
}
|
||||
|
||||
interface Callback {
|
||||
interface Listener {
|
||||
fun onToggleRoomCategory(roomCategory: RoomCategory)
|
||||
fun onRoomSelected(room: RoomSummary)
|
||||
fun onRejectRoomInvitation(room: RoomSummary)
|
||||
fun onAcceptRoomInvitation(room: RoomSummary)
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,12 +18,15 @@ package im.vector.riotredesign.features.home.room.list
|
||||
|
||||
import im.vector.matrix.android.api.session.events.model.EventType
|
||||
import im.vector.matrix.android.api.session.events.model.toModel
|
||||
import im.vector.matrix.android.api.session.room.model.Membership
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.model.message.MessageContent
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.epoxy.VectorEpoxyModel
|
||||
import im.vector.riotredesign.core.extensions.localDateTime
|
||||
import im.vector.riotredesign.core.resources.ColorProvider
|
||||
import im.vector.riotredesign.core.resources.DateProvider
|
||||
import im.vector.riotredesign.core.resources.StringProvider
|
||||
import im.vector.riotredesign.features.home.AvatarRenderer
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.format.NoticeEventFormatter
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter
|
||||
@ -34,9 +37,39 @@ import javax.inject.Inject
|
||||
class RoomSummaryItemFactory @Inject constructor(private val noticeEventFormatter: NoticeEventFormatter,
|
||||
private val timelineDateFormatter: TimelineDateFormatter,
|
||||
private val colorProvider: ColorProvider,
|
||||
private val stringProvider: StringProvider,
|
||||
private val avatarRenderer: AvatarRenderer) {
|
||||
|
||||
fun create(roomSummary: RoomSummary, onRoomSelected: (RoomSummary) -> Unit): RoomSummaryItem {
|
||||
fun create(roomSummary: RoomSummary, listener: RoomSummaryController.Listener?): VectorEpoxyModel<*> {
|
||||
return when (roomSummary.membership) {
|
||||
Membership.INVITE -> createInvitationItem(roomSummary, listener)
|
||||
else -> createRoomItem(roomSummary, listener)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun createInvitationItem(roomSummary: RoomSummary, listener: RoomSummaryController.Listener?): VectorEpoxyModel<*> {
|
||||
val secondLine = if (roomSummary.isDirect) {
|
||||
roomSummary.latestEvent?.root?.senderId
|
||||
} else {
|
||||
roomSummary.latestEvent?.root?.senderId?.let {
|
||||
stringProvider.getString(R.string.invited_by, it)
|
||||
}
|
||||
}
|
||||
|
||||
return RoomInvitationItem_()
|
||||
.id(roomSummary.roomId)
|
||||
.avatarRenderer(avatarRenderer)
|
||||
.roomId(roomSummary.roomId)
|
||||
.secondLine(secondLine)
|
||||
.acceptListener { listener?.onAcceptRoomInvitation(roomSummary) }
|
||||
.rejectListener { listener?.onRejectRoomInvitation(roomSummary) }
|
||||
.roomName(roomSummary.displayName)
|
||||
.avatarUrl(roomSummary.avatarUrl)
|
||||
.listener { listener?.onRoomSelected(roomSummary) }
|
||||
}
|
||||
|
||||
private fun createRoomItem(roomSummary: RoomSummary, listener: RoomSummaryController.Listener?): VectorEpoxyModel<*> {
|
||||
val unreadCount = roomSummary.notificationCount
|
||||
val showHighlighted = roomSummary.highlightCount > 0
|
||||
|
||||
@ -84,6 +117,7 @@ class RoomSummaryItemFactory @Inject constructor(private val noticeEventFormatte
|
||||
.avatarUrl(roomSummary.avatarUrl)
|
||||
.showHighlighted(showHighlighted)
|
||||
.unreadCount(unreadCount)
|
||||
.listener { onRoomSelected(roomSummary) }
|
||||
.listener { listener?.onRoomSelected(roomSummary) }
|
||||
}
|
||||
|
||||
}
|
||||
|
111
vector/src/main/res/layout/item_room_invitation.xml
Normal file
111
vector/src/main/res/layout/item_room_invitation.xml
Normal file
@ -0,0 +1,111 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/itemRoomInvitationLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?riotx_background"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/roomInvitationAvatarImageView"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginTop="12dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<!-- Margin bottom does not work, so I use space -->
|
||||
<Space
|
||||
android:id="@+id/roomInvitationAvatarBottomSpace"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="12dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/roomInvitationAvatarImageView"
|
||||
tools:layout_marginStart="20dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/roomInvitationNameView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||
android:layout_marginLeft="@dimen/layout_horizontal_margin"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:layout_marginRight="20dp"
|
||||
android:drawableEnd="@drawable/ic_arrow_right"
|
||||
android:drawablePadding="8dp"
|
||||
android:duplicateParentState="true"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?riotx_text_primary"
|
||||
android:textSize="15sp"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toEndOf="@id/roomInvitationAvatarImageView"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="@sample/matrix.json/data/displayName" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/roomInvitationSubTitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="3dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="2"
|
||||
android:textColor="?riotx_text_secondary"
|
||||
android:textSize="15sp"
|
||||
app:layout_constraintEnd_toEndOf="@+id/roomInvitationNameView"
|
||||
app:layout_constraintStart_toStartOf="@+id/roomInvitationNameView"
|
||||
app:layout_constraintTop_toBottomOf="@+id/roomInvitationNameView"
|
||||
tools:text="@sample/matrix.json/data/message" />
|
||||
|
||||
<!-- Margin bottom does not work, so I use space -->
|
||||
<Space
|
||||
android:id="@+id/roomLastEventBottomSpace"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="7dp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/roomInvitationSubTitle"
|
||||
tools:layout_marginStart="120dp" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/roomInvitationAccept"
|
||||
style="@style/VectorButtonStyle"
|
||||
android:layout_marginTop="8dp"
|
||||
android:minWidth="122dp"
|
||||
android:text="@string/accept"
|
||||
app:layout_constraintEnd_toEndOf="@+id/roomInvitationNameView"
|
||||
app:layout_constraintTop_toBottomOf="@+id/roomLastEventBottomSpace" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/roomInvitationReject"
|
||||
style="@style/VectorButtonStyleOutlined"
|
||||
android:layout_marginEnd="@dimen/layout_vertical_margin"
|
||||
android:minWidth="122dp"
|
||||
android:text="@string/reject"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="?riotx_text_primary"
|
||||
app:layout_constraintEnd_toStartOf="@+id/roomInvitationAccept"
|
||||
app:layout_constraintTop_toTopOf="@+id/roomInvitationAccept" />
|
||||
|
||||
<View
|
||||
android:id="@+id/roomInvitationDividerView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="1dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:background="?riotx_header_panel_border_mobile"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/roomInvitationAccept" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -142,6 +142,16 @@
|
||||
<item name="colorControlHighlight">?colorAccent</item>
|
||||
</style>
|
||||
|
||||
<style name="VectorButtonStyleOutlined" parent="Widget.MaterialComponents.Button.OutlinedButton">
|
||||
<item name="android:textStyle">bold</item>
|
||||
<item name="android:textAllCaps">false</item>
|
||||
<item name="android:layout_width">wrap_content</item>
|
||||
<item name="android:layout_height">wrap_content</item>
|
||||
<item name="android:background">@null</item>
|
||||
<!--item name="android:textColor">?colorAccent</item-->
|
||||
<item name="colorControlHighlight">?colorAccent</item>
|
||||
</style>
|
||||
|
||||
<style name="AlerterButton" parent="Widget.AppCompat.Button.Borderless.Colored">
|
||||
<item name="colorAccent">@android:color/white</item>
|
||||
<item name="android:textColor">@android:color/white</item>
|
||||
|
Loading…
Reference in New Issue
Block a user