Home: change some UI in room list

This commit is contained in:
ganfra 2019-05-20 17:13:12 +02:00 committed by Benoit Marty
parent 1691537a1e
commit 9f9f4c0755
15 changed files with 166 additions and 86 deletions

View File

@ -1,66 +1,68 @@
/* /*
* Copyright 2019 New Vector Ltd
* *
* * 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.
* * Licensed under the Apache License, Version 2.0 (the "License"); * You may obtain a copy of the License at
* * 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.
* *
* 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.group package im.vector.riotredesign.features.home


import android.os.Bundle import android.os.Bundle
import android.os.Parcelable import android.os.Parcelable
import android.view.LayoutInflater
import androidx.core.view.forEachIndexed
import com.airbnb.mvrx.args import com.airbnb.mvrx.args
import com.google.android.material.bottomnavigation.BottomNavigationItemView
import com.google.android.material.bottomnavigation.BottomNavigationMenuView
import im.vector.riotredesign.R import im.vector.riotredesign.R
import im.vector.riotredesign.core.platform.ToolbarConfigurable import im.vector.riotredesign.core.platform.ToolbarConfigurable
import im.vector.riotredesign.core.platform.VectorBaseFragment import im.vector.riotredesign.core.platform.VectorBaseFragment
import im.vector.riotredesign.features.home.AvatarRenderer
import im.vector.riotredesign.features.home.room.list.RoomListFragment import im.vector.riotredesign.features.home.room.list.RoomListFragment
import im.vector.riotredesign.features.home.room.list.RoomListParams import im.vector.riotredesign.features.home.room.list.RoomListParams
import im.vector.riotredesign.features.home.room.list.UnreadCounterBadgeView
import kotlinx.android.parcel.Parcelize import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.fragment_selected_group.* import kotlinx.android.synthetic.main.fragment_home_detail.*



@Parcelize @Parcelize
data class SelectedGroupParams( data class HomeDetailParams(
val groupId: String, val groupId: String,
val groupName: String, val groupName: String,
val groupAvatar: String val groupAvatar: String
) : Parcelable ) : Parcelable



private const val CURRENT_DISPLAY_MODE = "CURRENT_DISPLAY_MODE" private const val CURRENT_DISPLAY_MODE = "CURRENT_DISPLAY_MODE"


class SelectedGroupFragment : VectorBaseFragment() { class HomeDetailFragment : VectorBaseFragment() {


private val selectedGroupParams: SelectedGroupParams by args() private val params: HomeDetailParams by args()
private val unreadCounterBadgeViews = arrayListOf<UnreadCounterBadgeView>()
private lateinit var currentDisplayMode: RoomListFragment.DisplayMode private lateinit var currentDisplayMode: RoomListFragment.DisplayMode


override fun getLayoutResId(): Int { override fun getLayoutResId(): Int {
return R.layout.fragment_selected_group return R.layout.fragment_home_detail
} }


override fun onActivityCreated(savedInstanceState: Bundle?) { override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState) super.onActivityCreated(savedInstanceState)
if (savedInstanceState == null) { currentDisplayMode = savedInstanceState?.getSerializable(CURRENT_DISPLAY_MODE) as? RoomListFragment.DisplayMode
currentDisplayMode = RoomListFragment.DisplayMode.HOME
} else {
currentDisplayMode = savedInstanceState.getSerializable(CURRENT_DISPLAY_MODE) as? RoomListFragment.DisplayMode
?: RoomListFragment.DisplayMode.HOME ?: RoomListFragment.DisplayMode.HOME
} switchDisplayMode(currentDisplayMode)
renderState(currentDisplayMode)
setupBottomNavigationView() setupBottomNavigationView()
setupToolbar() setupToolbar()
} }



override fun onSaveInstanceState(outState: Bundle) { override fun onSaveInstanceState(outState: Bundle) {
outState.putSerializable(CURRENT_DISPLAY_MODE, currentDisplayMode) outState.putSerializable(CURRENT_DISPLAY_MODE, currentDisplayMode)
super.onSaveInstanceState(outState) super.onSaveInstanceState(outState)
@ -73,9 +75,9 @@ class SelectedGroupFragment : VectorBaseFragment() {
} }
groupToolbar.title = "" groupToolbar.title = ""
AvatarRenderer.render( AvatarRenderer.render(
selectedGroupParams.groupAvatar, params.groupAvatar,
selectedGroupParams.groupId, params.groupId,
selectedGroupParams.groupName, params.groupName,
groupToolbarAvatarImageView groupToolbarAvatarImageView
) )
groupToolbarAvatarImageView.setOnClickListener { groupToolbarAvatarImageView.setOnClickListener {
@ -92,13 +94,21 @@ class SelectedGroupFragment : VectorBaseFragment() {
} }
if (currentDisplayMode != displayMode) { if (currentDisplayMode != displayMode) {
currentDisplayMode = displayMode currentDisplayMode = displayMode
renderState(displayMode) switchDisplayMode(displayMode)
} }
true true
} }
val menuView = bottomNavigationView.getChildAt(0) as BottomNavigationMenuView
menuView.forEachIndexed { index, view ->
val itemView = view as BottomNavigationItemView
val badgeLayout = LayoutInflater.from(requireContext()).inflate(R.layout.vector_unread_layout, menuView, false)
val unreadCounterBadgeView: UnreadCounterBadgeView = badgeLayout.findViewById(R.id.actionUnreadCounterBadgeView)
itemView.addView(badgeLayout)
unreadCounterBadgeViews.add(index, unreadCounterBadgeView)
}
} }


private fun renderState(displayMode: RoomListFragment.DisplayMode) { private fun switchDisplayMode(displayMode: RoomListFragment.DisplayMode) {
groupToolbarTitleView.setText(displayMode.titleRes) groupToolbarTitleView.setText(displayMode.titleRes)
updateSelectedFragment(displayMode) updateSelectedFragment(displayMode)
} }
@ -117,8 +127,8 @@ class SelectedGroupFragment : VectorBaseFragment() {


companion object { companion object {


fun newInstance(args: SelectedGroupParams): SelectedGroupFragment { fun newInstance(args: HomeDetailParams): HomeDetailFragment {
return SelectedGroupFragment().apply { return HomeDetailFragment().apply {
setArguments(args) setArguments(args)
} }
} }

View File

@ -21,8 +21,6 @@ import androidx.fragment.app.FragmentManager
import im.vector.matrix.android.api.session.group.model.GroupSummary import im.vector.matrix.android.api.session.group.model.GroupSummary
import im.vector.riotredesign.R import im.vector.riotredesign.R
import im.vector.riotredesign.core.extensions.replaceFragment import im.vector.riotredesign.core.extensions.replaceFragment
import im.vector.riotredesign.features.home.group.SelectedGroupFragment
import im.vector.riotredesign.features.home.group.SelectedGroupParams
import im.vector.riotredesign.features.home.room.detail.RoomDetailActivity import im.vector.riotredesign.features.home.room.detail.RoomDetailActivity
import im.vector.riotredesign.features.home.room.detail.RoomDetailArgs import im.vector.riotredesign.features.home.room.detail.RoomDetailArgs
import kotlinx.android.synthetic.main.activity_home.* import kotlinx.android.synthetic.main.activity_home.*
@ -37,10 +35,10 @@ class HomeNavigator {
fun openSelectedGroup(groupSummary: GroupSummary) { fun openSelectedGroup(groupSummary: GroupSummary) {
Timber.v("Open selected group ${groupSummary.groupId}") Timber.v("Open selected group ${groupSummary.groupId}")
activity?.let { activity?.let {
val args = SelectedGroupParams(groupSummary.groupId, groupSummary.displayName, groupSummary.avatarUrl) val args = HomeDetailParams(groupSummary.groupId, groupSummary.displayName, groupSummary.avatarUrl)
val selectedGroupFragment = SelectedGroupFragment.newInstance(args) val homeDetailFragment = HomeDetailFragment.newInstance(args)
it.drawerLayout?.closeDrawer(GravityCompat.START) it.drawerLayout?.closeDrawer(GravityCompat.START)
it.replaceFragment(selectedGroupFragment, R.id.homeDetailFragmentContainer) it.replaceFragment(homeDetailFragment, R.id.homeDetailFragmentContainer)
} }
} }



View File

@ -18,5 +18,18 @@ package im.vector.riotredesign.features.home


import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.riotredesign.core.utils.RxStore import im.vector.riotredesign.core.utils.RxStore
import im.vector.riotredesign.features.home.room.list.RoomListDisplayModeFilter
import im.vector.riotredesign.features.home.room.list.RoomListFragment
import io.reactivex.Observable


class HomeRoomListObservableStore : RxStore<List<RoomSummary>>(emptyList()) class HomeRoomListObservableStore : RxStore<List<RoomSummary>>() {

fun observeFilteredBy(displayMode: RoomListFragment.DisplayMode): Observable<List<RoomSummary>> {
return observe()
.flatMapSingle {
Observable.fromIterable(it).filter(RoomListDisplayModeFilter(displayMode)).toList()
}
}


}

View File

@ -389,15 +389,15 @@ class RoomDetailFragment :
private fun renderState(state: RoomDetailViewState) { private fun renderState(state: RoomDetailViewState) {
renderRoomSummary(state) renderRoomSummary(state)
val summary = state.asyncRoomSummary() val summary = state.asyncRoomSummary()
val inviter = state.inviter() val inviter = state.asyncInviter()
if (summary?.membership == Membership.JOIN) { if (summary?.membership == Membership.JOIN) {
timelineEventController.setTimeline(state.timeline) timelineEventController.setTimeline(state.timeline)
inviteView.visibility = View.GONE inviteView.visibility = View.GONE
} else if (summary?.membership == Membership.INVITE && inviter != null) { } else if (summary?.membership == Membership.INVITE && inviter != null) {
inviteView.visibility = View.VISIBLE inviteView.visibility = View.VISIBLE
inviteView.render(inviter, VectorInviteView.Mode.LARGE) inviteView.render(inviter, VectorInviteView.Mode.LARGE)
} else { } else if (state.asyncInviter.complete) {
//TODO : close the screen vectorBaseActivity.finish()
} }
} }



View File

@ -292,7 +292,7 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
summary.lastMessage?.sender?.let { senderId -> summary.lastMessage?.sender?.let { senderId ->
session.getUser(senderId) session.getUser(senderId)
}?.also { }?.also {
setState { copy(inviter = Success(it)) } setState { copy(asyncInviter = Success(it)) }
} }
} }
} }

View File

@ -28,7 +28,7 @@ data class RoomDetailViewState(
val roomId: String, val roomId: String,
val eventId: String?, val eventId: String?,
val timeline: Timeline? = null, val timeline: Timeline? = null,
val inviter: Async<User> = Uninitialized, val asyncInviter: Async<User> = Uninitialized,
val asyncRoomSummary: Async<RoomSummary> = Uninitialized, val asyncRoomSummary: Async<RoomSummary> = Uninitialized,
val asyncTimelineData: Async<TimelineData> = Uninitialized val asyncTimelineData: Async<TimelineData> = Uninitialized
) : MvRxState { ) : MvRxState {

View File

@ -41,7 +41,7 @@ abstract class RoomCategoryItem : VectorEpoxyModel<RoomCategoryItem.Holder>() {
val expandedArrowDrawable = ContextCompat.getDrawable(holder.rootView.context, expandedArrowDrawableRes)?.also { val expandedArrowDrawable = ContextCompat.getDrawable(holder.rootView.context, expandedArrowDrawableRes)?.also {
DrawableCompat.setTint(it, tintColor) DrawableCompat.setTint(it, tintColor)
} }
holder.unreadCounterBadgeView.render(unreadCount, showHighlighted) holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State(unreadCount, showHighlighted))
holder.titleView.setCompoundDrawablesWithIntrinsicBounds(expandedArrowDrawable, null, null, null) holder.titleView.setCompoundDrawablesWithIntrinsicBounds(expandedArrowDrawable, null, null, null)
holder.titleView.text = title holder.titleView.text = title
holder.rootView.setOnClickListener { listener?.invoke() } holder.rootView.setOnClickListener { listener?.invoke() }

View File

@ -0,0 +1,32 @@
/*
* 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 im.vector.matrix.android.api.session.room.model.Membership
import im.vector.matrix.android.api.session.room.model.RoomSummary
import io.reactivex.functions.Predicate

class RoomListDisplayModeFilter(private val displayMode: RoomListFragment.DisplayMode) : Predicate<RoomSummary> {

override fun test(roomSummary: RoomSummary): Boolean {
return when (displayMode) {
RoomListFragment.DisplayMode.HOME -> roomSummary.notificationCount > 0 || roomSummary.membership == Membership.INVITE
RoomListFragment.DisplayMode.PEOPLE -> roomSummary.isDirect && roomSummary.membership == Membership.JOIN
RoomListFragment.DisplayMode.ROOMS -> !roomSummary.isDirect && roomSummary.membership == Membership.JOIN
}
}
}

View File

@ -29,7 +29,6 @@ import im.vector.matrix.android.api.session.room.model.tag.RoomTag
import im.vector.riotredesign.core.platform.VectorViewModel import im.vector.riotredesign.core.platform.VectorViewModel
import im.vector.riotredesign.core.utils.LiveEvent import im.vector.riotredesign.core.utils.LiveEvent
import im.vector.riotredesign.features.home.HomeRoomListObservableStore import im.vector.riotredesign.features.home.HomeRoomListObservableStore
import io.reactivex.Observable
import org.koin.android.ext.android.get import org.koin.android.ext.android.get


typealias RoomListFilterName = CharSequence typealias RoomListFilterName = CharSequence
@ -54,6 +53,7 @@ class RoomListViewModel(initialState: RoomListViewState,
} }


private val displayMode = initialState.displayMode private val displayMode = initialState.displayMode
private val roomListDisplayModeFilter = RoomListDisplayModeFilter(displayMode)
private val roomListFilter = BehaviorRelay.createDefault<Option<RoomListFilterName>>(Option.empty()) private val roomListFilter = BehaviorRelay.createDefault<Option<RoomListFilterName>>(Option.empty())


private val _openRoomLiveData = MutableLiveData<LiveEvent<String>>() private val _openRoomLiveData = MutableLiveData<LiveEvent<String>>()
@ -95,27 +95,13 @@ class RoomListViewModel(initialState: RoomListViewState,
copy(asyncRooms = asyncRooms) copy(asyncRooms = asyncRooms)
} }


homeRoomListObservableSource homeRoomListObservableSource.observeFilteredBy(displayMode)
.observe()
.flatMapSingle {
Observable.fromIterable(it)
.filter(filterByDisplayMode(displayMode))
.toList()
}
.map { buildRoomSummaries(it) } .map { buildRoomSummaries(it) }
.execute { async -> .execute { async ->
copy(asyncFilteredRooms = async) copy(asyncFilteredRooms = async)
} }
} }


private fun filterByDisplayMode(displayMode: RoomListFragment.DisplayMode) = { roomSummary: RoomSummary ->
when (displayMode) {
RoomListFragment.DisplayMode.HOME -> roomSummary.notificationCount > 0
RoomListFragment.DisplayMode.PEOPLE -> roomSummary.isDirect
RoomListFragment.DisplayMode.ROOMS -> !roomSummary.isDirect
}
}

private fun buildRoomSummaries(rooms: List<RoomSummary>): RoomSummaries { private fun buildRoomSummaries(rooms: List<RoomSummary>): RoomSummaries {
val invites = ArrayList<RoomSummary>() val invites = ArrayList<RoomSummary>()
val favourites = ArrayList<RoomSummary>() val favourites = ArrayList<RoomSummary>()

View File

@ -17,12 +17,16 @@
package im.vector.riotredesign.features.home.room.list package im.vector.riotredesign.features.home.room.list


import androidx.annotation.StringRes import androidx.annotation.StringRes
import com.airbnb.mvrx.Async
import com.airbnb.mvrx.MvRxState import com.airbnb.mvrx.MvRxState
import com.airbnb.mvrx.Uninitialized
import im.vector.matrix.android.api.session.room.model.RoomSummary import im.vector.matrix.android.api.session.room.model.RoomSummary
import im.vector.riotredesign.R import im.vector.riotredesign.R


data class RoomListViewState( data class RoomListViewState(
val displayMode: RoomListFragment.DisplayMode, val displayMode: RoomListFragment.DisplayMode,
val asyncRooms: Async<List<RoomSummary>> = Uninitialized,
val asyncFilteredRooms: Async<RoomSummaries> = Uninitialized,
val isInviteExpanded: Boolean = true, val isInviteExpanded: Boolean = true,
val isFavouriteRoomsExpanded: Boolean = true, val isFavouriteRoomsExpanded: Boolean = true,
val isDirectRoomsExpanded: Boolean = true, val isDirectRoomsExpanded: Boolean = true,

View File

@ -46,7 +46,7 @@ abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {
holder.titleView.text = roomName holder.titleView.text = roomName
holder.lastEventTimeView.text = lastEventTime holder.lastEventTimeView.text = lastEventTime
holder.lastEventView.text = lastFormattedEvent holder.lastEventView.text = lastFormattedEvent
holder.unreadCounterBadgeView.render(unreadCount, showHighlighted) holder.unreadCounterBadgeView.render(UnreadCounterBadgeView.State(unreadCount, showHighlighted))
AvatarRenderer.render(avatarUrl, roomId, roomName.toString(), holder.avatarImageView) AvatarRenderer.render(avatarUrl, roomId, roomName.toString(), holder.avatarImageView)
} }



View File

@ -29,24 +29,24 @@ class UnreadCounterBadgeView : AppCompatTextView {


constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)


fun render(count: Int, highlighted: Boolean) { fun render(state: State) {
if (count == 0) { if (state.count == 0) {
visibility = View.INVISIBLE visibility = View.INVISIBLE
} else { } else {
visibility = View.VISIBLE visibility = View.VISIBLE
val bgRes = if (highlighted) { val bgRes = if (state.highlighted) {
R.drawable.bg_unread_highlight R.drawable.bg_unread_highlight
} else { } else {
R.drawable.bg_unread_notification R.drawable.bg_unread_notification
} }
setBackgroundResource(bgRes) setBackgroundResource(bgRes)
text = RoomSummaryFormatter.formatUnreadMessagesCounter(count) text = RoomSummaryFormatter.formatUnreadMessagesCounter(state.count)
} }
} }


enum class Status { data class State(
NOTIFICATION, val count: Int,
HIGHLIGHT val highlighted: Boolean
} )


} }

View File

@ -57,6 +57,7 @@
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?attr/colorPrimary" android:background="?attr/colorPrimary"
app:labelVisibilityMode="unlabeled"
app:itemIconTint="@android:color/white" app:itemIconTint="@android:color/white"
app:itemTextColor="@color/home_bottom_nav_view_tint" app:itemTextColor="@color/home_bottom_nav_view_tint"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"

View File

@ -10,11 +10,7 @@
android:clickable="true" android:clickable="true"
android:focusable="true" android:focusable="true"
android:paddingStart="8dp" android:paddingStart="8dp"
android:paddingLeft="8dp" android:paddingLeft="8dp">
android:paddingTop="8dp"
android:paddingEnd="16dp"
android:paddingRight="16dp"
android:paddingBottom="8dp">


<ImageView <ImageView
android:id="@+id/roomAvatarImageView" android:id="@+id/roomAvatarImageView"
@ -22,7 +18,7 @@
android:layout_height="40dp" android:layout_height="40dp"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:layout_marginLeft="16dp" android:layout_marginLeft="16dp"
app:layout_constraintBottom_toBottomOf="parent" android:layout_marginTop="16dp"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:src="@tools:sample/avatars" /> tools:src="@tools:sample/avatars" />
@ -32,7 +28,10 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginTop="12dp"
android:layout_marginEnd="8dp" android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:duplicateParentState="true" android:duplicateParentState="true"
android:ellipsize="end" android:ellipsize="end"
android:maxLines="1" android:maxLines="1"
@ -43,14 +42,14 @@
app:layout_constraintHorizontal_bias="0.0" app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintHorizontal_chainStyle="packed" app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toEndOf="@id/roomAvatarImageView" app:layout_constraintStart_toEndOf="@id/roomAvatarImageView"
app:layout_constraintTop_toTopOf="@+id/roomAvatarImageView" app:layout_constraintTop_toTopOf="parent"
tools:text="@tools:sample/full_names" /> tools:text="@tools:sample/full_names" />



<im.vector.riotredesign.features.home.room.list.UnreadCounterBadgeView <im.vector.riotredesign.features.home.room.list.UnreadCounterBadgeView
android:id="@+id/roomUnreadCounterBadgeView" android:id="@+id/roomUnreadCounterBadgeView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp" android:layout_marginRight="8dp"
android:gravity="center" android:gravity="center"
android:minWidth="16dp" android:minWidth="16dp"
@ -59,9 +58,10 @@
android:paddingRight="4dp" android:paddingRight="4dp"
android:textColor="@android:color/white" android:textColor="@android:color/white"
android:textSize="10sp" android:textSize="10sp"
app:layout_constraintBottom_toBottomOf="@+id/roomNameView"
app:layout_constraintEnd_toStartOf="@+id/roomLastEventTimeView" app:layout_constraintEnd_toStartOf="@+id/roomLastEventTimeView"
app:layout_constraintStart_toEndOf="@+id/roomNameView" app:layout_constraintStart_toEndOf="@+id/roomNameView"
app:layout_constraintTop_toTopOf="@+id/roomAvatarImageView" app:layout_constraintTop_toTopOf="@+id/roomNameView"
tools:background="@drawable/bg_unread_highlight" tools:background="@drawable/bg_unread_highlight"
tools:text="4" /> tools:text="4" />


@ -69,20 +69,21 @@
android:id="@+id/roomLastEventTimeView" android:id="@+id/roomLastEventTimeView"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="8dp" android:layout_marginEnd="8dp"
android:layout_marginLeft="8dp" android:layout_marginRight="8dp"
android:textColor="@color/black_38" android:textColor="@color/black_38"
android:textSize="12sp" android:textSize="12sp"
app:layout_constraintBaseline_toBaselineOf="@id/messageMemberNameView" app:layout_constraintBottom_toBottomOf="@+id/roomNameView"
app:layout_constraintTop_toTopOf="@+id/roomAvatarImageView"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/roomNameView"
tools:text="@tools:sample/date/hhmm" /> tools:text="@tools:sample/date/hhmm" />



<TextView <TextView
android:id="@+id/roomLastEventView" android:id="@+id/roomLastEventView"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="34dp" android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:ellipsize="end" android:ellipsize="end"
android:maxLines="2" android:maxLines="2"
android:textColor="@color/black_38" android:textColor="@color/black_38"
@ -92,5 +93,14 @@
app:layout_constraintTop_toBottomOf="@+id/roomNameView" app:layout_constraintTop_toBottomOf="@+id/roomNameView"
tools:text="@tools:sample/lorem/random" /> tools:text="@tools:sample/lorem/random" />


<View
android:id="@+id/roomDividerView"
android:layout_width="0dp"
android:layout_height="1dp"
android:background="#1e000000"
android:layout_marginTop="16dp"
app:layout_constraintTop_toBottomOf="@+id/roomLastEventView"
app:layout_constraintStart_toStartOf="@+id/roomNameView" />



</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">

<im.vector.riotredesign.features.home.room.list.UnreadCounterBadgeView
android:id="@+id/actionUnreadCounterBadgeView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|center_horizontal"
android:layout_marginStart="10dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:gravity="center"
android:minWidth="8dp"
android:minHeight="8dp"
android:paddingLeft="4dp"
android:paddingRight="4dp"
android:textColor="@android:color/white"
android:textSize="10sp"
tools:background="@drawable/bg_unread_highlight"
tools:text="4" />

</FrameLayout>