mirror of
https://github.com/element-hq/element-android
synced 2024-11-27 11:59:12 +03:00
Home: continue architecture rework. WIP
This commit is contained in:
parent
268730e71b
commit
275521db70
30 changed files with 416 additions and 346 deletions
|
@ -18,6 +18,7 @@
|
|||
|
||||
package im.vector.matrix.android.api.session.user
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import im.vector.matrix.android.api.session.user.model.User
|
||||
|
||||
/**
|
||||
|
@ -32,4 +33,11 @@ interface UserService {
|
|||
*/
|
||||
fun getUser(userId: String): User?
|
||||
|
||||
/**
|
||||
* Observe a live user from a userId
|
||||
* @param userId the userId to look for.
|
||||
* @return a Livedata of user with userId
|
||||
*/
|
||||
fun observeUser(userId: String): LiveData<User?>
|
||||
|
||||
}
|
|
@ -14,23 +14,22 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package im.vector.riotredesign.features.home.room.list
|
||||
package im.vector.matrix.android.internal.database.mapper
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import im.vector.matrix.android.api.session.user.model.User
|
||||
import im.vector.matrix.android.internal.database.model.UserEntity
|
||||
|
||||
private const val SHARED_PREFS_SELECTED_ROOM_KEY = "SHARED_PREFS_SELECTED_ROOM_KEY"
|
||||
internal object UserMapper {
|
||||
|
||||
class RoomSelectionRepository(private val sharedPreferences: SharedPreferences) {
|
||||
|
||||
fun lastSelectedRoom(): String? {
|
||||
return sharedPreferences.getString(SHARED_PREFS_SELECTED_ROOM_KEY, null)
|
||||
fun map(userEntity: UserEntity): User {
|
||||
return User(
|
||||
userEntity.userId,
|
||||
userEntity.displayName,
|
||||
userEntity.avatarUrl
|
||||
)
|
||||
}
|
||||
|
||||
fun saveLastSelectedRoom(roomId: String) {
|
||||
sharedPreferences.edit()
|
||||
.putString(SHARED_PREFS_SELECTED_ROOM_KEY, roomId)
|
||||
.apply()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal fun UserEntity.asDomain(): User {
|
||||
return UserMapper.map(this)
|
||||
}
|
|
@ -231,6 +231,11 @@ internal class DefaultSession(override val sessionParams: SessionParams) : Sessi
|
|||
return userService.getUser(userId)
|
||||
}
|
||||
|
||||
override fun observeUser(userId: String): LiveData<User?> {
|
||||
assert(isOpen)
|
||||
return userService.observeUser(userId)
|
||||
}
|
||||
|
||||
// Private methods *****************************************************************************
|
||||
|
||||
private fun assertMainThread() {
|
||||
|
|
|
@ -18,9 +18,13 @@
|
|||
|
||||
package im.vector.matrix.android.internal.session.user
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.Transformations
|
||||
import com.zhuinden.monarchy.Monarchy
|
||||
import im.vector.matrix.android.api.session.user.UserService
|
||||
import im.vector.matrix.android.api.session.user.model.User
|
||||
import im.vector.matrix.android.internal.database.RealmLiveData
|
||||
import im.vector.matrix.android.internal.database.mapper.asDomain
|
||||
import im.vector.matrix.android.internal.database.model.UserEntity
|
||||
import im.vector.matrix.android.internal.database.query.where
|
||||
import im.vector.matrix.android.internal.util.fetchCopied
|
||||
|
@ -29,12 +33,19 @@ internal class DefaultUserService(private val monarchy: Monarchy) : UserService
|
|||
|
||||
override fun getUser(userId: String): User? {
|
||||
val userEntity = monarchy.fetchCopied { UserEntity.where(it, userId).findFirst() }
|
||||
?: return null
|
||||
?: return null
|
||||
|
||||
return User(
|
||||
userEntity.userId,
|
||||
userEntity.displayName,
|
||||
userEntity.avatarUrl
|
||||
)
|
||||
return userEntity.asDomain()
|
||||
}
|
||||
|
||||
override fun observeUser(userId: String): LiveData<User?> {
|
||||
val liveRealmData = RealmLiveData(monarchy.realmConfiguration) { realm ->
|
||||
UserEntity.where(realm, userId)
|
||||
}
|
||||
return Transformations.map(liveRealmData) { results ->
|
||||
results
|
||||
.map { it.asDomain() }
|
||||
.firstOrNull()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,8 +24,6 @@ import im.vector.riotredesign.core.resources.LocaleProvider
|
|||
import im.vector.riotredesign.core.resources.StringArrayProvider
|
||||
import im.vector.riotredesign.core.resources.StringProvider
|
||||
import im.vector.riotredesign.features.home.group.SelectedGroupStore
|
||||
import im.vector.riotredesign.features.home.room.VisibleRoomStore
|
||||
import im.vector.riotredesign.features.home.room.list.RoomSelectionRepository
|
||||
import im.vector.riotredesign.features.home.room.list.RoomSummaryComparator
|
||||
import im.vector.riotredesign.features.notifications.NotificationDrawerManager
|
||||
import org.koin.dsl.module.module
|
||||
|
@ -50,18 +48,10 @@ class AppModule(private val context: Context) {
|
|||
context.getSharedPreferences("im.vector.riot", MODE_PRIVATE)
|
||||
}
|
||||
|
||||
single {
|
||||
RoomSelectionRepository(get())
|
||||
}
|
||||
|
||||
single {
|
||||
SelectedGroupStore()
|
||||
}
|
||||
|
||||
single {
|
||||
VisibleRoomStore()
|
||||
}
|
||||
|
||||
single {
|
||||
RoomSummaryComparator()
|
||||
}
|
||||
|
@ -78,6 +68,5 @@ class AppModule(private val context: Context) {
|
|||
Matrix.getInstance().currentSession!!
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -109,8 +109,6 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
|
|||
|
||||
override fun configure(toolbar: Toolbar) {
|
||||
setSupportActionBar(toolbar)
|
||||
supportActionBar?.setHomeButtonEnabled(true)
|
||||
supportActionBar?.setDisplayUseLogoEnabled(true)
|
||||
}
|
||||
|
||||
override fun getMenuRes() = R.menu.home
|
||||
|
@ -121,10 +119,6 @@ class HomeActivity : VectorBaseActivity(), ToolbarConfigurable {
|
|||
drawerLayout.openDrawer(GravityCompat.START)
|
||||
return true
|
||||
}
|
||||
R.id.sliding_menu_settings -> {
|
||||
startActivity(VectorSettingsActivity.getIntent(this, "TODO"))
|
||||
return true
|
||||
}
|
||||
R.id.sliding_menu_sign_out -> {
|
||||
SignOutUiWorker(this).perform(Matrix.getInstance().currentSession!!)
|
||||
return true
|
||||
|
|
|
@ -18,26 +18,31 @@ package im.vector.riotredesign.features.home
|
|||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import arrow.core.Option
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
import im.vector.matrix.android.api.Matrix
|
||||
import im.vector.matrix.android.api.MatrixCallback
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.matrix.android.api.session.room.model.create.CreateRoomParams
|
||||
import im.vector.matrix.android.api.session.sync.FilterService
|
||||
import im.vector.matrix.rx.rx
|
||||
import im.vector.riotredesign.core.platform.VectorViewModel
|
||||
import im.vector.riotredesign.core.utils.LiveEvent
|
||||
import im.vector.riotredesign.features.home.room.list.RoomSelectionRepository
|
||||
import io.reactivex.rxkotlin.subscribeBy
|
||||
import im.vector.riotredesign.features.home.group.ALL_COMMUNITIES_GROUP_ID
|
||||
import im.vector.riotredesign.features.home.group.SelectedGroupStore
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.functions.BiFunction
|
||||
import org.koin.android.ext.android.get
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
data class EmptyState(val isEmpty: Boolean = true) : MvRxState
|
||||
|
||||
class HomeActivityViewModel(state: EmptyState,
|
||||
private val session: Session,
|
||||
roomSelectionRepository: RoomSelectionRepository
|
||||
private val selectedGroupStore: SelectedGroupStore,
|
||||
private val homeRoomListStore: HomeRoomListObservableStore
|
||||
) : VectorViewModel<EmptyState>(state), Session.Listener {
|
||||
|
||||
companion object : MvRxViewModelFactory<HomeActivityViewModel, EmptyState> {
|
||||
|
@ -45,8 +50,9 @@ class HomeActivityViewModel(state: EmptyState,
|
|||
@JvmStatic
|
||||
override fun create(viewModelContext: ViewModelContext, state: EmptyState): HomeActivityViewModel? {
|
||||
val session = Matrix.getInstance().currentSession!!
|
||||
val roomSelectionRepository = viewModelContext.activity.get<RoomSelectionRepository>()
|
||||
return HomeActivityViewModel(state, session, roomSelectionRepository)
|
||||
val selectedGroupStore = viewModelContext.activity.get<SelectedGroupStore>()
|
||||
val homeRoomListObservableSource = viewModelContext.activity.get<HomeRoomListObservableStore>()
|
||||
return HomeActivityViewModel(state, session, selectedGroupStore, homeRoomListObservableSource)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,29 +60,41 @@ class HomeActivityViewModel(state: EmptyState,
|
|||
val isLoading: LiveData<Boolean>
|
||||
get() = _isLoading
|
||||
|
||||
private val _openRoomLiveData = MutableLiveData<LiveEvent<String>>()
|
||||
val openRoomLiveData: LiveData<LiveEvent<String>>
|
||||
get() = _openRoomLiveData
|
||||
|
||||
init {
|
||||
session.addListener(this)
|
||||
val lastSelectedRoomId = roomSelectionRepository.lastSelectedRoom()
|
||||
if (lastSelectedRoomId == null || session.getRoom(lastSelectedRoomId) == null) {
|
||||
getTheFirstRoomWhenAvailable()
|
||||
} else {
|
||||
_openRoomLiveData.postValue(LiveEvent(lastSelectedRoomId))
|
||||
}
|
||||
observeRoomAndGroup()
|
||||
}
|
||||
|
||||
private fun getTheFirstRoomWhenAvailable() {
|
||||
session.rx().liveRoomSummaries()
|
||||
.filter { it.isNotEmpty() }
|
||||
.first(emptyList())
|
||||
.subscribeBy {
|
||||
val firstRoom = it.firstOrNull()
|
||||
if (firstRoom != null) {
|
||||
_openRoomLiveData.postValue(LiveEvent(firstRoom.roomId))
|
||||
}
|
||||
private fun observeRoomAndGroup() {
|
||||
Observable
|
||||
.combineLatest<List<RoomSummary>, Option<GroupSummary>, List<RoomSummary>>(
|
||||
session.rx().liveRoomSummaries().throttleLast(300, TimeUnit.MILLISECONDS),
|
||||
selectedGroupStore.observe(),
|
||||
BiFunction { rooms, selectedGroupOption ->
|
||||
val selectedGroup = selectedGroupOption.orNull()
|
||||
val filteredDirectRooms = rooms
|
||||
.filter { it.isDirect }
|
||||
.filter {
|
||||
if (selectedGroup == null || selectedGroup.groupId == ALL_COMMUNITIES_GROUP_ID) {
|
||||
true
|
||||
} else {
|
||||
it.otherMemberIds
|
||||
.intersect(selectedGroup.userIds)
|
||||
.isNotEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
val filteredGroupRooms = rooms
|
||||
.filter { !it.isDirect }
|
||||
.filter {
|
||||
selectedGroup?.groupId == ALL_COMMUNITIES_GROUP_ID
|
||||
|| selectedGroup?.roomIds?.contains(it.roomId) ?: true
|
||||
}
|
||||
filteredDirectRooms + filteredGroupRooms
|
||||
}
|
||||
)
|
||||
.subscribe {
|
||||
homeRoomListStore.post(it)
|
||||
}
|
||||
.disposeOnClear()
|
||||
}
|
||||
|
@ -87,8 +105,6 @@ class HomeActivityViewModel(state: EmptyState,
|
|||
session.createRoom(createRoomParams, object : MatrixCallback<String> {
|
||||
override fun onSuccess(data: String) {
|
||||
_isLoading.value = false
|
||||
// Open room id
|
||||
_openRoomLiveData.postValue(LiveEvent(data))
|
||||
}
|
||||
|
||||
override fun onFailure(failure: Throwable) {
|
||||
|
|
|
@ -19,9 +19,11 @@ package im.vector.riotredesign.features.home
|
|||
import android.os.Bundle
|
||||
import im.vector.matrix.android.api.Matrix
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.extensions.observeK
|
||||
import im.vector.riotredesign.core.extensions.replaceChildFragment
|
||||
import im.vector.riotredesign.core.platform.VectorBaseFragment
|
||||
import im.vector.riotredesign.features.home.group.GroupListFragment
|
||||
import im.vector.riotredesign.features.settings.VectorSettingsActivity
|
||||
import kotlinx.android.synthetic.main.fragment_home_drawer.*
|
||||
|
||||
class HomeDrawerFragment : VectorBaseFragment() {
|
||||
|
@ -42,12 +44,15 @@ class HomeDrawerFragment : VectorBaseFragment() {
|
|||
replaceChildFragment(groupListFragment, R.id.homeDrawerGroupListContainer)
|
||||
}
|
||||
val session = Matrix.getInstance().currentSession ?: return
|
||||
val user = session.getUser(session.sessionParams.credentials.userId)
|
||||
if (user != null) {
|
||||
AvatarRenderer.render(user.avatarUrl, user.userId, user.displayName, homeDrawerHeaderAvatarView)
|
||||
homeDrawerUsernameView.text = user.displayName
|
||||
homeDrawerUserIdView.text = user.userId
|
||||
session.observeUser(session.sessionParams.credentials.userId).observeK(this) { user ->
|
||||
if (user != null) {
|
||||
AvatarRenderer.render(user.avatarUrl, user.userId, user.displayName, homeDrawerHeaderAvatarView)
|
||||
homeDrawerUsernameView.text = user.displayName
|
||||
homeDrawerUserIdView.text = user.userId
|
||||
}
|
||||
}
|
||||
homeDrawerHeaderSettingsView.setOnClickListener {
|
||||
startActivity(VectorSettingsActivity.getIntent(requireContext(), "TODO"))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -25,7 +25,14 @@ import im.vector.riotredesign.features.autocomplete.user.AutocompleteUserControl
|
|||
import im.vector.riotredesign.features.autocomplete.user.AutocompleteUserPresenter
|
||||
import im.vector.riotredesign.features.home.group.GroupSummaryController
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.TimelineEventController
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.factory.*
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.factory.CallItemFactory
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.factory.DefaultItemFactory
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.factory.MessageItemFactory
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.factory.RoomHistoryVisibilityItemFactory
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.factory.RoomMemberItemFactory
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.factory.RoomNameItemFactory
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.factory.RoomTopicItemFactory
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.factory.TimelineItemFactory
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDateFormatter
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineMediaSizeProvider
|
||||
import im.vector.riotredesign.features.home.room.list.RoomSummaryController
|
||||
|
@ -49,6 +56,10 @@ class HomeModule {
|
|||
HomeNavigator()
|
||||
}
|
||||
|
||||
scope(HOME_SCOPE) {
|
||||
HomeRoomListObservableStore()
|
||||
}
|
||||
|
||||
scope(HOME_SCOPE) {
|
||||
HomePermalinkHandler(get())
|
||||
}
|
||||
|
@ -63,12 +74,12 @@ class HomeModule {
|
|||
val messageItemFactory = MessageItemFactory(colorProvider, timelineMediaSizeProvider, timelineDateFormatter, eventHtmlRenderer)
|
||||
|
||||
val timelineItemFactory = TimelineItemFactory(messageItemFactory = messageItemFactory,
|
||||
roomNameItemFactory = RoomNameItemFactory(get()),
|
||||
roomTopicItemFactory = RoomTopicItemFactory(get()),
|
||||
roomMemberItemFactory = RoomMemberItemFactory(get()),
|
||||
roomHistoryVisibilityItemFactory = RoomHistoryVisibilityItemFactory(get()),
|
||||
callItemFactory = CallItemFactory(get()),
|
||||
defaultItemFactory = DefaultItemFactory()
|
||||
roomNameItemFactory = RoomNameItemFactory(get()),
|
||||
roomTopicItemFactory = RoomTopicItemFactory(get()),
|
||||
roomMemberItemFactory = RoomMemberItemFactory(get()),
|
||||
roomHistoryVisibilityItemFactory = RoomHistoryVisibilityItemFactory(get()),
|
||||
callItemFactory = CallItemFactory(get()),
|
||||
defaultItemFactory = DefaultItemFactory()
|
||||
)
|
||||
TimelineEventController(timelineDateFormatter, timelineItemFactory, timelineMediaSizeProvider)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
import im.vector.riotredesign.core.utils.RxStore
|
||||
|
||||
class HomeRoomListObservableStore : RxStore<List<RoomSummary>>(emptyList())
|
|
@ -54,13 +54,16 @@ class GroupListViewModel(initialState: GroupListViewState,
|
|||
|
||||
init {
|
||||
observeGroupSummaries()
|
||||
observeState()
|
||||
observeSelectionState()
|
||||
}
|
||||
|
||||
private fun observeState() {
|
||||
subscribe {
|
||||
val optionGroup = Option.fromNullable(it.selectedGroup)
|
||||
selectedGroupHolder.post(optionGroup)
|
||||
private fun observeSelectionState() {
|
||||
selectSubscribe(GroupListViewState::selectedGroup) {
|
||||
if (it != null) {
|
||||
_openGroupLiveData.postValue(LiveEvent(it))
|
||||
val optionGroup = Option.fromNullable(it)
|
||||
selectedGroupHolder.post(optionGroup)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,7 +78,6 @@ class GroupListViewModel(initialState: GroupListViewState,
|
|||
private fun handleSelectGroup(action: GroupListActions.SelectGroup) = withState { state ->
|
||||
if (state.selectedGroup?.groupId != action.groupSummary.groupId) {
|
||||
setState { copy(selectedGroup = action.groupSummary) }
|
||||
_openGroupLiveData.postValue(LiveEvent(action.groupSummary))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,7 +93,8 @@ class GroupListViewModel(initialState: GroupListViewState,
|
|||
listOf(allCommunityGroup) + it
|
||||
}
|
||||
.execute { async ->
|
||||
copy(asyncGroups = async)
|
||||
val newSelectedGroup = selectedGroup ?: async()?.firstOrNull()
|
||||
copy(asyncGroups = async, selectedGroup = newSelectedGroup)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
|
||||
package im.vector.riotredesign.features.home.group
|
||||
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
|
@ -24,6 +23,7 @@ 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.platform.CheckableFrameLayout
|
||||
import im.vector.riotredesign.features.home.AvatarRenderer
|
||||
|
||||
@EpoxyModelClass(layout = R.layout.item_group)
|
||||
|
@ -39,13 +39,14 @@ abstract class GroupSummaryItem : VectorEpoxyModel<GroupSummaryItem.Holder>() {
|
|||
super.bind(holder)
|
||||
holder.rootView.setOnClickListener { listener?.invoke() }
|
||||
holder.groupNameView.text = groupName
|
||||
holder.rootView.isChecked = selected
|
||||
AvatarRenderer.render(avatarUrl, groupId, groupName.toString(), holder.avatarImageView)
|
||||
}
|
||||
|
||||
class Holder : VectorEpoxyHolder() {
|
||||
val avatarImageView by bind<ImageView>(R.id.groupAvatarImageView)
|
||||
val groupNameView by bind<TextView>(R.id.groupNameView)
|
||||
val rootView by bind<ViewGroup>(R.id.itemGroupLayout)
|
||||
val rootView by bind<CheckableFrameLayout>(R.id.itemGroupLayout)
|
||||
}
|
||||
|
||||
}
|
|
@ -18,15 +18,10 @@
|
|||
|
||||
package im.vector.riotredesign.features.home.group
|
||||
|
||||
import android.graphics.drawable.Drawable
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import com.airbnb.mvrx.args
|
||||
import com.bumptech.glide.request.target.SimpleTarget
|
||||
import com.bumptech.glide.request.transition.Transition
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.extensions.replaceChildFragment
|
||||
import im.vector.riotredesign.core.glide.GlideApp
|
||||
import im.vector.riotredesign.core.platform.ToolbarConfigurable
|
||||
import im.vector.riotredesign.core.platform.VectorBaseFragment
|
||||
import im.vector.riotredesign.features.home.AvatarRenderer
|
||||
|
@ -42,9 +37,12 @@ data class SelectedGroupParams(
|
|||
val groupAvatar: String
|
||||
) : Parcelable
|
||||
|
||||
private const val CURRENT_DISPLAY_MODE = "CURRENT_DISPLAY_MODE"
|
||||
|
||||
class SelectedGroupFragment : VectorBaseFragment() {
|
||||
|
||||
private val selectedGroupParams: SelectedGroupParams by args()
|
||||
private lateinit var currentDisplayMode: RoomListFragment.DisplayMode
|
||||
|
||||
override fun getLayoutResId(): Int {
|
||||
return R.layout.fragment_selected_group
|
||||
|
@ -53,31 +51,36 @@ class SelectedGroupFragment : VectorBaseFragment() {
|
|||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
if (savedInstanceState == null) {
|
||||
updateSelectedFragment(RoomListFragment.DisplayMode.HOME)
|
||||
toolbar.setTitle(RoomListFragment.DisplayMode.HOME.titleRes)
|
||||
currentDisplayMode = RoomListFragment.DisplayMode.HOME
|
||||
} else {
|
||||
currentDisplayMode = savedInstanceState.getSerializable(CURRENT_DISPLAY_MODE) as? RoomListFragment.DisplayMode
|
||||
?: RoomListFragment.DisplayMode.HOME
|
||||
}
|
||||
renderState(currentDisplayMode)
|
||||
setupBottomNavigationView()
|
||||
setupToolbar()
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
outState.putSerializable(CURRENT_DISPLAY_MODE, currentDisplayMode)
|
||||
super.onSaveInstanceState(outState)
|
||||
}
|
||||
|
||||
private fun setupToolbar() {
|
||||
val parentActivity = vectorBaseActivity
|
||||
if (parentActivity is ToolbarConfigurable) {
|
||||
parentActivity.configure(toolbar)
|
||||
}
|
||||
val toolbarLogoTarget = object : SimpleTarget<Drawable>() {
|
||||
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
|
||||
toolbar.logo = resource
|
||||
}
|
||||
parentActivity.configure(groupToolbar)
|
||||
}
|
||||
groupToolbar.title = ""
|
||||
AvatarRenderer.render(
|
||||
requireContext(),
|
||||
GlideApp.with(this),
|
||||
selectedGroupParams.groupAvatar,
|
||||
selectedGroupParams.groupId,
|
||||
selectedGroupParams.groupName,
|
||||
toolbarLogoTarget
|
||||
groupToolbarAvatarImageView
|
||||
)
|
||||
groupToolbarAvatarImageView.setOnClickListener {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupBottomNavigationView() {
|
||||
|
@ -87,16 +90,29 @@ class SelectedGroupFragment : VectorBaseFragment() {
|
|||
it.itemId == R.id.bottom_action_rooms -> RoomListFragment.DisplayMode.ROOMS
|
||||
else -> RoomListFragment.DisplayMode.HOME
|
||||
}
|
||||
updateSelectedFragment(displayMode)
|
||||
toolbar.setTitle(displayMode.titleRes)
|
||||
if (currentDisplayMode != displayMode) {
|
||||
currentDisplayMode = displayMode
|
||||
renderState(displayMode)
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderState(displayMode: RoomListFragment.DisplayMode) {
|
||||
groupToolbarTitleView.setText(displayMode.titleRes)
|
||||
updateSelectedFragment(displayMode)
|
||||
}
|
||||
|
||||
private fun updateSelectedFragment(displayMode: RoomListFragment.DisplayMode) {
|
||||
val roomListParams = RoomListParams(displayMode)
|
||||
val roomListFragment = RoomListFragment.newInstance(roomListParams)
|
||||
replaceChildFragment(roomListFragment, R.id.roomListContainer)
|
||||
val fragmentTag = "FRAGMENT_TAG_${displayMode.name}"
|
||||
var fragment = childFragmentManager.findFragmentByTag(fragmentTag)
|
||||
if (fragment == null) {
|
||||
fragment = RoomListFragment.newInstance(RoomListParams(displayMode))
|
||||
}
|
||||
childFragmentManager.beginTransaction()
|
||||
.replace(R.id.roomListContainer, fragment, fragmentTag)
|
||||
.addToBackStack(fragmentTag)
|
||||
.commit()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -25,7 +25,6 @@ sealed class RoomDetailActions {
|
|||
|
||||
data class SendMessage(val text: String) : RoomDetailActions()
|
||||
data class SendMedia(val mediaFiles: List<MediaFile>) : RoomDetailActions()
|
||||
object IsDisplayed : RoomDetailActions()
|
||||
data class EventDisplayed(val event: TimelineEvent) : RoomDetailActions()
|
||||
data class LoadMore(val direction: Timeline.Direction) : RoomDetailActions()
|
||||
data class SendReaction(val reaction: String, val targetEventId: String) : RoomDetailActions()
|
||||
|
|
|
@ -21,11 +21,13 @@ package im.vector.riotredesign.features.home.room.detail
|
|||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import im.vector.riotredesign.R
|
||||
import im.vector.riotredesign.core.extensions.replaceFragment
|
||||
import im.vector.riotredesign.core.platform.ToolbarConfigurable
|
||||
import im.vector.riotredesign.core.platform.VectorBaseActivity
|
||||
|
||||
class RoomDetailActivity : VectorBaseActivity() {
|
||||
class RoomDetailActivity : VectorBaseActivity(), ToolbarConfigurable {
|
||||
|
||||
override fun getLayoutRes(): Int {
|
||||
return R.layout.activity_room_detail
|
||||
|
@ -35,12 +37,20 @@ class RoomDetailActivity : VectorBaseActivity() {
|
|||
super.onCreate(savedInstanceState)
|
||||
if (savedInstanceState == null) {
|
||||
val roomDetailArgs: RoomDetailArgs = intent?.extras?.getParcelable(EXTRA_ROOM_DETAIL_ARGS)
|
||||
?: return
|
||||
?: return
|
||||
val roomDetailFragment = RoomDetailFragment.newInstance(roomDetailArgs)
|
||||
replaceFragment(roomDetailFragment, R.id.roomDetailContainer)
|
||||
}
|
||||
}
|
||||
|
||||
override fun configure(toolbar: Toolbar) {
|
||||
setSupportActionBar(toolbar)
|
||||
supportActionBar?.let {
|
||||
it.setDisplayShowHomeEnabled(true)
|
||||
it.setDisplayHomeAsUpEnabled(true)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val EXTRA_ROOM_DETAIL_ARGS = "EXTRA_ROOM_DETAIL_ARGS"
|
||||
|
|
|
@ -64,6 +64,7 @@ import im.vector.riotredesign.core.epoxy.LayoutManagerStateRestorer
|
|||
import im.vector.riotredesign.core.extensions.hideKeyboard
|
||||
import im.vector.riotredesign.core.extensions.observeEvent
|
||||
import im.vector.riotredesign.core.glide.GlideApp
|
||||
import im.vector.riotredesign.core.platform.ToolbarConfigurable
|
||||
import im.vector.riotredesign.core.platform.VectorBaseFragment
|
||||
import im.vector.riotredesign.core.utils.*
|
||||
import im.vector.riotredesign.features.autocomplete.command.AutocompleteCommandPresenter
|
||||
|
@ -168,6 +169,7 @@ class RoomDetailFragment :
|
|||
super.onActivityCreated(savedInstanceState)
|
||||
actionViewModel = ViewModelProviders.of(requireActivity()).get(ActionsHandler::class.java)
|
||||
bindScope(getOrCreateScope(HomeModule.ROOM_DETAIL_SCOPE))
|
||||
setupToolbar()
|
||||
setupRecyclerView()
|
||||
setupComposer()
|
||||
setupAttachmentButton()
|
||||
|
@ -187,6 +189,13 @@ class RoomDetailFragment :
|
|||
})
|
||||
}
|
||||
|
||||
private fun setupToolbar() {
|
||||
val parentActivity = vectorBaseActivity
|
||||
if (parentActivity is ToolbarConfigurable) {
|
||||
parentActivity.configure(roomToolbar)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
super.onActivityResult(requestCode, resultCode, data)
|
||||
if (resultCode == RESULT_OK && data != null) {
|
||||
|
@ -204,11 +213,6 @@ class RoomDetailFragment :
|
|||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
roomDetailViewModel.process(RoomDetailActions.IsDisplayed)
|
||||
}
|
||||
|
||||
// PRIVATE METHODS *****************************************************************************
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
|
@ -399,13 +403,13 @@ class RoomDetailFragment :
|
|||
|
||||
private fun renderRoomSummary(state: RoomDetailViewState) {
|
||||
state.asyncRoomSummary()?.let {
|
||||
toolbarTitleView.text = it.displayName
|
||||
AvatarRenderer.render(it, toolbarAvatarImageView)
|
||||
roomToolbarTitleView.text = it.displayName
|
||||
AvatarRenderer.render(it, roomToolbarAvatarImageView)
|
||||
if (it.topic.isNotEmpty()) {
|
||||
toolbarSubtitleView.visibility = View.VISIBLE
|
||||
toolbarSubtitleView.text = it.topic
|
||||
roomToolbarSubtitleView.visibility = View.VISIBLE
|
||||
roomToolbarSubtitleView.text = it.topic
|
||||
} else {
|
||||
toolbarSubtitleView.visibility = View.GONE
|
||||
roomToolbarSubtitleView.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,6 @@ import im.vector.riotredesign.core.platform.VectorViewModel
|
|||
import im.vector.riotredesign.core.utils.LiveEvent
|
||||
import im.vector.riotredesign.features.command.CommandParser
|
||||
import im.vector.riotredesign.features.command.ParsedCommand
|
||||
import im.vector.riotredesign.features.home.room.VisibleRoomStore
|
||||
import im.vector.riotredesign.features.home.room.detail.timeline.helper.TimelineDisplayableEvents
|
||||
import io.reactivex.rxkotlin.subscribeBy
|
||||
import org.koin.android.ext.android.get
|
||||
|
@ -42,8 +41,7 @@ import java.util.*
|
|||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class RoomDetailViewModel(initialState: RoomDetailViewState,
|
||||
private val session: Session,
|
||||
private val visibleRoomHolder: VisibleRoomStore
|
||||
private val session: Session
|
||||
) : VectorViewModel<RoomDetailViewState>(initialState) {
|
||||
|
||||
private val room = session.getRoom(initialState.roomId)!!
|
||||
|
@ -59,8 +57,7 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
|
|||
@JvmStatic
|
||||
override fun create(viewModelContext: ViewModelContext, state: RoomDetailViewState): RoomDetailViewModel? {
|
||||
val currentSession = viewModelContext.activity.get<Session>()
|
||||
val visibleRoomHolder = viewModelContext.activity.get<VisibleRoomStore>()
|
||||
return RoomDetailViewModel(state, currentSession, visibleRoomHolder)
|
||||
return RoomDetailViewModel(state, currentSession)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,18 +72,17 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
|
|||
|
||||
fun process(action: RoomDetailActions) {
|
||||
when (action) {
|
||||
is RoomDetailActions.SendMessage -> handleSendMessage(action)
|
||||
is RoomDetailActions.IsDisplayed -> handleIsDisplayed()
|
||||
is RoomDetailActions.SendMedia -> handleSendMedia(action)
|
||||
is RoomDetailActions.EventDisplayed -> handleEventDisplayed(action)
|
||||
is RoomDetailActions.LoadMore -> handleLoadMore(action)
|
||||
is RoomDetailActions.SendReaction -> handleSendReaction(action)
|
||||
is RoomDetailActions.AcceptInvite -> handleAcceptInvite()
|
||||
is RoomDetailActions.RejectInvite -> handleRejectInvite()
|
||||
is RoomDetailActions.RedactAction -> handleRedactEvent(action)
|
||||
is RoomDetailActions.UndoReaction -> handleUndoReact(action)
|
||||
is RoomDetailActions.SendMessage -> handleSendMessage(action)
|
||||
is RoomDetailActions.SendMedia -> handleSendMedia(action)
|
||||
is RoomDetailActions.EventDisplayed -> handleEventDisplayed(action)
|
||||
is RoomDetailActions.LoadMore -> handleLoadMore(action)
|
||||
is RoomDetailActions.SendReaction -> handleSendReaction(action)
|
||||
is RoomDetailActions.AcceptInvite -> handleAcceptInvite()
|
||||
is RoomDetailActions.RejectInvite -> handleRejectInvite()
|
||||
is RoomDetailActions.RedactAction -> handleRedactEvent(action)
|
||||
is RoomDetailActions.UndoReaction -> handleUndoReact(action)
|
||||
is RoomDetailActions.UpdateQuickReactAction -> handleUpdateQuickReaction(action)
|
||||
is RoomDetailActions.ShowEditHistoryAction -> handleShowEditHistoryReaction(action)
|
||||
is RoomDetailActions.ShowEditHistoryAction -> handleShowEditHistoryReaction(action)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -107,63 +103,63 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
|
|||
val slashCommandResult = CommandParser.parseSplashCommand(action.text)
|
||||
|
||||
when (slashCommandResult) {
|
||||
is ParsedCommand.ErrorNotACommand -> {
|
||||
is ParsedCommand.ErrorNotACommand -> {
|
||||
// Send the text message to the room
|
||||
room.sendTextMessage(action.text)
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.MessageSent))
|
||||
}
|
||||
is ParsedCommand.ErrorSyntax -> {
|
||||
is ParsedCommand.ErrorSyntax -> {
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandError(slashCommandResult.command)))
|
||||
}
|
||||
is ParsedCommand.ErrorEmptySlashCommand -> {
|
||||
is ParsedCommand.ErrorEmptySlashCommand -> {
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandUnknown("/")))
|
||||
}
|
||||
is ParsedCommand.ErrorUnknownSlashCommand -> {
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandUnknown(slashCommandResult.slashCommand)))
|
||||
}
|
||||
is ParsedCommand.Invite -> {
|
||||
is ParsedCommand.Invite -> {
|
||||
handleInviteSlashCommand(slashCommandResult)
|
||||
}
|
||||
is ParsedCommand.SetUserPowerLevel -> {
|
||||
is ParsedCommand.SetUserPowerLevel -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
}
|
||||
is ParsedCommand.ClearScalarToken -> {
|
||||
is ParsedCommand.ClearScalarToken -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
}
|
||||
is ParsedCommand.SetMarkdown -> {
|
||||
is ParsedCommand.SetMarkdown -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
}
|
||||
is ParsedCommand.UnbanUser -> {
|
||||
is ParsedCommand.UnbanUser -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
}
|
||||
is ParsedCommand.BanUser -> {
|
||||
is ParsedCommand.BanUser -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
}
|
||||
is ParsedCommand.KickUser -> {
|
||||
is ParsedCommand.KickUser -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
}
|
||||
is ParsedCommand.JoinRoom -> {
|
||||
is ParsedCommand.JoinRoom -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
}
|
||||
is ParsedCommand.PartRoom -> {
|
||||
is ParsedCommand.PartRoom -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
}
|
||||
is ParsedCommand.SendEmote -> {
|
||||
is ParsedCommand.SendEmote -> {
|
||||
room.sendTextMessage(slashCommandResult.message, msgType = MessageType.MSGTYPE_EMOTE)
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandHandled))
|
||||
}
|
||||
is ParsedCommand.ChangeTopic -> {
|
||||
is ParsedCommand.ChangeTopic -> {
|
||||
handleChangeTopicSlashCommand(slashCommandResult)
|
||||
}
|
||||
is ParsedCommand.ChangeDisplayName -> {
|
||||
is ParsedCommand.ChangeDisplayName -> {
|
||||
// TODO
|
||||
_sendMessageResultLiveData.postValue(LiveEvent(SendMessageResult.SlashCommandNotImplemented))
|
||||
}
|
||||
|
@ -255,10 +251,6 @@ class RoomDetailViewModel(initialState: RoomDetailViewState,
|
|||
displayedEventsObservable.accept(action)
|
||||
}
|
||||
|
||||
private fun handleIsDisplayed() {
|
||||
visibleRoomHolder.post(roomId)
|
||||
}
|
||||
|
||||
private fun handleLoadMore(action: RoomDetailActions.LoadMore) {
|
||||
timeline.paginate(action.direction, PAGINATION_COUNT)
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||
import com.airbnb.mvrx.Fail
|
||||
import com.airbnb.mvrx.Incomplete
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.args
|
||||
import com.airbnb.mvrx.fragmentViewModel
|
||||
import im.vector.matrix.android.api.failure.Failure
|
||||
import im.vector.matrix.android.api.session.room.model.RoomSummary
|
||||
|
@ -61,6 +62,7 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Callback {
|
|||
}
|
||||
}
|
||||
|
||||
private val roomListParams: RoomListParams by args()
|
||||
private val roomController by inject<RoomSummaryController>()
|
||||
private val homeNavigator by inject<HomeNavigator>()
|
||||
private val roomListViewModel: RoomListViewModel by fragmentViewModel()
|
||||
|
@ -71,12 +73,20 @@ class RoomListFragment : VectorBaseFragment(), RoomSummaryController.Callback {
|
|||
super.onActivityCreated(savedInstanceState)
|
||||
bindScope(getOrCreateScope(HomeModule.ROOM_LIST_SCOPE))
|
||||
setupRecyclerView()
|
||||
setupCreateRoomButton()
|
||||
roomListViewModel.subscribe { renderState(it) }
|
||||
roomListViewModel.openRoomLiveData.observeEvent(this) {
|
||||
homeNavigator.openRoomDetail(it, null)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupCreateRoomButton() {
|
||||
createRoomButton.setImageResource(R.drawable.ic_add_white)
|
||||
createRoomButton.setOnClickListener {
|
||||
vectorBaseActivity.notImplemented()
|
||||
}
|
||||
}
|
||||
|
||||
private fun setupRecyclerView() {
|
||||
val layoutManager = LinearLayoutManager(context)
|
||||
val stateRestorer = LayoutManagerStateRestorer(layoutManager).register()
|
||||
|
|
|
@ -23,28 +23,19 @@ import com.airbnb.mvrx.MvRxViewModelFactory
|
|||
import com.airbnb.mvrx.ViewModelContext
|
||||
import com.jakewharton.rxrelay2.BehaviorRelay
|
||||
import im.vector.matrix.android.api.session.Session
|
||||
import im.vector.matrix.android.api.session.group.model.GroupSummary
|
||||
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.tag.RoomTag
|
||||
import im.vector.matrix.rx.rx
|
||||
import im.vector.riotredesign.core.platform.VectorViewModel
|
||||
import im.vector.riotredesign.core.utils.LiveEvent
|
||||
import im.vector.riotredesign.features.home.group.ALL_COMMUNITIES_GROUP_ID
|
||||
import im.vector.riotredesign.features.home.group.SelectedGroupStore
|
||||
import im.vector.riotredesign.features.home.room.VisibleRoomStore
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.functions.Function3
|
||||
import im.vector.riotredesign.features.home.HomeRoomListObservableStore
|
||||
import org.koin.android.ext.android.get
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
typealias RoomListFilterName = CharSequence
|
||||
|
||||
class RoomListViewModel(initialState: RoomListViewState,
|
||||
private val session: Session,
|
||||
private val selectedGroupHolder: SelectedGroupStore,
|
||||
private val visibleRoomHolder: VisibleRoomStore,
|
||||
private val roomSelectionRepository: RoomSelectionRepository,
|
||||
private val homeRoomListObservableSource: HomeRoomListObservableStore,
|
||||
private val roomSummaryComparator: RoomSummaryComparator)
|
||||
: VectorViewModel<RoomListViewState>(initialState) {
|
||||
|
||||
|
@ -53,11 +44,9 @@ class RoomListViewModel(initialState: RoomListViewState,
|
|||
@JvmStatic
|
||||
override fun create(viewModelContext: ViewModelContext, state: RoomListViewState): RoomListViewModel? {
|
||||
val currentSession = viewModelContext.activity.get<Session>()
|
||||
val roomSelectionRepository = viewModelContext.activity.get<RoomSelectionRepository>()
|
||||
val selectedGroupHolder = viewModelContext.activity.get<SelectedGroupStore>()
|
||||
val visibleRoomHolder = viewModelContext.activity.get<VisibleRoomStore>()
|
||||
val homeRoomListObservableSource = viewModelContext.activity.get<HomeRoomListObservableStore>()
|
||||
val roomSummaryComparator = viewModelContext.activity.get<RoomSummaryComparator>()
|
||||
return RoomListViewModel(state, currentSession, selectedGroupHolder, visibleRoomHolder, roomSelectionRepository, roomSummaryComparator)
|
||||
return RoomListViewModel(state, currentSession, homeRoomListObservableSource, roomSummaryComparator)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -70,7 +59,6 @@ class RoomListViewModel(initialState: RoomListViewState,
|
|||
|
||||
init {
|
||||
observeRoomSummaries()
|
||||
observeVisibleRoom()
|
||||
}
|
||||
|
||||
fun accept(action: RoomListActions) {
|
||||
|
@ -83,11 +71,8 @@ class RoomListViewModel(initialState: RoomListViewState,
|
|||
|
||||
// PRIVATE METHODS *****************************************************************************
|
||||
|
||||
private fun handleSelectRoom(action: RoomListActions.SelectRoom) = withState { state ->
|
||||
if (state.visibleRoomId != action.roomSummary.roomId) {
|
||||
roomSelectionRepository.saveLastSelectedRoom(action.roomSummary.roomId)
|
||||
_openRoomLiveData.postValue(LiveEvent(action.roomSummary.roomId))
|
||||
}
|
||||
private fun handleSelectRoom(action: RoomListActions.SelectRoom) {
|
||||
_openRoomLiveData.postValue(LiveEvent(action.roomSummary.roomId))
|
||||
}
|
||||
|
||||
private fun handleFilterRooms(action: RoomListActions.FilterRooms) {
|
||||
|
@ -99,44 +84,10 @@ class RoomListViewModel(initialState: RoomListViewState,
|
|||
this.toggle(action.category)
|
||||
}
|
||||
|
||||
private fun observeVisibleRoom() {
|
||||
visibleRoomHolder.observe()
|
||||
.doOnNext {
|
||||
setState { copy(visibleRoomId = it) }
|
||||
}
|
||||
.subscribe()
|
||||
.disposeOnClear()
|
||||
}
|
||||
|
||||
private fun observeRoomSummaries() {
|
||||
Observable.combineLatest<List<RoomSummary>, Option<GroupSummary>, Option<RoomListFilterName>, RoomSummaries>(
|
||||
session.rx().liveRoomSummaries().throttleLast(300, TimeUnit.MILLISECONDS),
|
||||
selectedGroupHolder.observe(),
|
||||
roomListFilter.throttleLast(300, TimeUnit.MILLISECONDS),
|
||||
Function3 { rooms, selectedGroupOption, filterRoomOption ->
|
||||
val filteredRooms = filterRooms(rooms, filterRoomOption)
|
||||
val selectedGroup = selectedGroupOption.orNull()
|
||||
val filteredDirectRooms = filteredRooms
|
||||
.filter { it.isDirect }
|
||||
.filter {
|
||||
if (selectedGroup == null || selectedGroup.groupId == ALL_COMMUNITIES_GROUP_ID) {
|
||||
true
|
||||
} else {
|
||||
it.otherMemberIds
|
||||
.intersect(selectedGroup.userIds)
|
||||
.isNotEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
val filteredGroupRooms = filteredRooms
|
||||
.filter { !it.isDirect }
|
||||
.filter {
|
||||
selectedGroup?.groupId == ALL_COMMUNITIES_GROUP_ID
|
||||
|| selectedGroup?.roomIds?.contains(it.roomId) ?: true
|
||||
}
|
||||
buildRoomSummaries(filteredDirectRooms + filteredGroupRooms)
|
||||
}
|
||||
)
|
||||
homeRoomListObservableSource.observe()
|
||||
.map { buildRoomSummaries(it) }
|
||||
.execute { async ->
|
||||
copy(
|
||||
asyncRooms = async
|
||||
|
@ -144,17 +95,6 @@ class RoomListViewModel(initialState: RoomListViewState,
|
|||
}
|
||||
}
|
||||
|
||||
private fun filterRooms(rooms: List<RoomSummary>, filterRoomOption: Option<RoomListFilterName>): List<RoomSummary> {
|
||||
val filterRoom = filterRoomOption.orNull()
|
||||
return rooms.filter {
|
||||
if (filterRoom.isNullOrBlank()) {
|
||||
true
|
||||
} else {
|
||||
it.displayName.contains(other = filterRoom, ignoreCase = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildRoomSummaries(rooms: List<RoomSummary>): RoomSummaries {
|
||||
val invites = ArrayList<RoomSummary>()
|
||||
val favourites = ArrayList<RoomSummary>()
|
||||
|
|
|
@ -25,7 +25,6 @@ import im.vector.riotredesign.R
|
|||
|
||||
data class RoomListViewState(
|
||||
val asyncRooms: Async<RoomSummaries> = Uninitialized,
|
||||
val visibleRoomId: String? = null,
|
||||
val isInviteExpanded: Boolean = true,
|
||||
val isFavouriteRoomsExpanded: Boolean = true,
|
||||
val isDirectRoomsExpanded: Boolean = true,
|
||||
|
|
|
@ -37,7 +37,7 @@ class RoomSummaryController(private val stringProvider: StringProvider
|
|||
callback?.onToggleRoomCategory(category)
|
||||
}
|
||||
if (isExpanded) {
|
||||
buildRoomModels(summaries, viewState.visibleRoomId)
|
||||
buildRoomModels(summaries)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,18 +71,16 @@ class RoomSummaryController(private val stringProvider: StringProvider
|
|||
}
|
||||
}
|
||||
|
||||
private fun buildRoomModels(summaries: List<RoomSummary>, selectedRoomId: String?) {
|
||||
private fun buildRoomModels(summaries: List<RoomSummary>) {
|
||||
summaries.forEach { roomSummary ->
|
||||
val unreadCount = roomSummary.notificationCount
|
||||
val showHighlighted = roomSummary.highlightCount > 0
|
||||
val isSelected = roomSummary.roomId == selectedRoomId
|
||||
|
||||
roomSummaryItem {
|
||||
id(roomSummary.roomId)
|
||||
roomId(roomSummary.roomId)
|
||||
roomName(roomSummary.displayName)
|
||||
avatarUrl(roomSummary.avatarUrl)
|
||||
selected(isSelected)
|
||||
showHighlighted(showHighlighted)
|
||||
unreadCount(unreadCount)
|
||||
listener { callback?.onRoomSelected(roomSummary) }
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package im.vector.riotredesign.features.home.room.list
|
||||
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import com.airbnb.epoxy.EpoxyAttribute
|
||||
|
@ -23,7 +24,6 @@ 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.platform.CheckableFrameLayout
|
||||
import im.vector.riotredesign.features.home.AvatarRenderer
|
||||
|
||||
|
||||
|
@ -33,7 +33,6 @@ abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {
|
|||
@EpoxyAttribute lateinit var roomName: CharSequence
|
||||
@EpoxyAttribute lateinit var roomId: String
|
||||
@EpoxyAttribute var avatarUrl: String? = null
|
||||
@EpoxyAttribute var selected: Boolean = false
|
||||
@EpoxyAttribute var unreadCount: Int = 0
|
||||
@EpoxyAttribute var showHighlighted: Boolean = false
|
||||
@EpoxyAttribute var listener: (() -> Unit)? = null
|
||||
|
@ -42,7 +41,6 @@ abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {
|
|||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
holder.unreadCounterBadgeView.render(unreadCount, showHighlighted)
|
||||
holder.rootView.isChecked = selected
|
||||
holder.rootView.setOnClickListener { listener?.invoke() }
|
||||
holder.titleView.text = roomName
|
||||
AvatarRenderer.render(avatarUrl, roomId, roomName.toString(), holder.avatarImageView)
|
||||
|
@ -52,7 +50,7 @@ abstract class RoomSummaryItem : VectorEpoxyModel<RoomSummaryItem.Holder>() {
|
|||
val unreadCounterBadgeView by bind<UnreadCounterBadgeView>(R.id.roomUnreadCounterBadgeView)
|
||||
val titleView by bind<TextView>(R.id.roomNameView)
|
||||
val avatarImageView by bind<ImageView>(R.id.roomAvatarImageView)
|
||||
val rootView by bind<CheckableFrameLayout>(R.id.itemRoomLayout)
|
||||
val rootView by bind<ViewGroup>(R.id.itemRoomLayout)
|
||||
}
|
||||
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
<item android:state_checked="true">
|
||||
<shape>
|
||||
<solid android:color="@android:color/white" />
|
||||
<solid android:color="#10000000" />
|
||||
<corners android:radius="4dp" />
|
||||
</shape>
|
||||
</item>
|
|
@ -2,9 +2,10 @@
|
|||
<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/stateView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/homeDrawerHeader"
|
||||
|
@ -46,12 +47,16 @@
|
|||
app:layout_constraintTop_toBottomOf="@+id/homeDrawerUsernameView"
|
||||
tools:text="@tools:sample/full_names" />
|
||||
|
||||
<ImageButton
|
||||
<ImageView
|
||||
android:id="@+id/homeDrawerHeaderSettingsView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:padding="6dp"
|
||||
android:scaleType="fitCenter"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:src="@drawable/ic_settings"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@+id/homeDrawerUserIdView" />
|
||||
app:layout_constraintTop_toBottomOf="@+id/homeDrawerUsernameView" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:id="@+id/roomToolbar"
|
||||
style="@style/VectorToolbarStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="?actionBarSize"
|
||||
|
@ -23,7 +23,7 @@
|
|||
android:layout_height="match_parent">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/toolbarAvatarImageView"
|
||||
android:id="@+id/roomToolbarAvatarImageView"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginTop="8dp"
|
||||
|
@ -34,7 +34,7 @@
|
|||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/toolbarTitleView"
|
||||
android:id="@+id/roomToolbarTitleView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
|
@ -43,15 +43,15 @@
|
|||
android:maxLines="1"
|
||||
android:textColor="?vctr_toolbar_primary_text_color"
|
||||
android:textSize="18sp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/toolbarSubtitleView"
|
||||
app:layout_constraintBottom_toTopOf="@+id/roomToolbarSubtitleView"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toEndOf="@+id/toolbarAvatarImageView"
|
||||
app:layout_constraintStart_toEndOf="@+id/roomToolbarAvatarImageView"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="@tools:sample/full_names" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/toolbarSubtitleView"
|
||||
android:id="@+id/roomToolbarSubtitleView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
|
@ -63,8 +63,8 @@
|
|||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toEndOf="@+id/toolbarAvatarImageView"
|
||||
app:layout_constraintTop_toBottomOf="@+id/toolbarTitleView"
|
||||
app:layout_constraintStart_toEndOf="@+id/roomToolbarAvatarImageView"
|
||||
app:layout_constraintTop_toBottomOf="@+id/roomToolbarTitleView"
|
||||
tools:text="@tools:sample/date/day_of_week" />
|
||||
|
||||
|
||||
|
@ -79,7 +79,7 @@
|
|||
app:layout_constraintBottom_toTopOf="@+id/composerDivider"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/toolbar"
|
||||
app:layout_constraintTop_toBottomOf="@id/roomToolbar"
|
||||
tools:listitem="@layout/item_timeline_event_base" />
|
||||
|
||||
<View
|
||||
|
@ -148,7 +148,7 @@
|
|||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/toolbar"
|
||||
app:layout_constraintTop_toBottomOf="@+id/roomToolbar"
|
||||
app:layout_constraintVertical_bias="1.0"
|
||||
tools:visibility="visible" />
|
||||
|
||||
|
|
|
@ -12,4 +12,11 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/createRoomButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_margin="16dp" />
|
||||
|
||||
</im.vector.riotredesign.core.platform.StateView>
|
||||
|
|
|
@ -2,11 +2,12 @@
|
|||
|
||||
<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:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:id="@+id/groupToolbar"
|
||||
style="@style/VectorToolbarStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
|
@ -14,14 +15,42 @@
|
|||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
|
||||
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
|
||||
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/groupToolbarAvatarImageView"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/groupToolbarTitleView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?vctr_toolbar_primary_text_color"
|
||||
android:textSize="18sp"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.appcompat.widget.Toolbar>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/roomListContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/bottomNavigationView"
|
||||
app:layout_constraintTop_toBottomOf="@+id/toolbar" />
|
||||
app:layout_constraintTop_toBottomOf="@+id/groupToolbar" />
|
||||
|
||||
<com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
android:id="@+id/bottomNavigationView"
|
||||
|
|
|
@ -1,48 +1,60 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
|
||||
<im.vector.riotredesign.core.platform.CheckableFrameLayout 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/itemGroupLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="56dp"
|
||||
android:background="@android:color/transparent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_group_item"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:padding="16dp">
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingRight="16dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/groupAvatarImageView"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center"
|
||||
android:duplicateParentState="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="56dp"
|
||||
android:duplicateParentState="true">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/groupNameView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="32dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/groupAvatarImageView"
|
||||
app:layout_constraintEnd_toStartOf="@+id/groupAvatarChevron"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toEndOf="@+id/groupAvatarImageView"
|
||||
app:layout_constraintTop_toTopOf="@+id/groupAvatarImageView"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
<ImageView
|
||||
android:id="@+id/groupAvatarImageView"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center"
|
||||
android:duplicateParentState="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/groupAvatarChevron"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_material_chevron_right_black"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
<TextView
|
||||
android:id="@+id/groupNameView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="32dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/groupAvatarImageView"
|
||||
app:layout_constraintEnd_toStartOf="@+id/groupAvatarChevron"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintStart_toEndOf="@+id/groupAvatarImageView"
|
||||
app:layout_constraintTop_toTopOf="@+id/groupAvatarImageView"
|
||||
tools:text="@tools:sample/lorem/random" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
<ImageView
|
||||
android:id="@+id/groupAvatarChevron"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/ic_material_chevron_right_black"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</im.vector.riotredesign.core.platform.CheckableFrameLayout>
|
|
@ -1,70 +1,62 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<im.vector.riotredesign.core.platform.CheckableFrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<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/itemRoomLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_room_item"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:minHeight="48dp"
|
||||
android:paddingStart="8dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingRight="16dp">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
<ImageView
|
||||
android:id="@+id/roomAvatarImageView"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/roomNameView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:duplicateParentState="true"
|
||||
android:minHeight="48dp">
|
||||
android:textColor="@color/color_room_title"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/roomUnreadCounterBadgeView"
|
||||
app:layout_constraintStart_toEndOf="@id/roomAvatarImageView"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="@tools:sample/full_names" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/roomAvatarImageView"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@tools:sample/avatars" />
|
||||
<im.vector.riotredesign.features.home.room.list.UnreadCounterBadgeView
|
||||
android:id="@+id/roomUnreadCounterBadgeView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:minWidth="24dp"
|
||||
android:minHeight="24dp"
|
||||
android:paddingLeft="4dp"
|
||||
android:paddingRight="4dp"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:background="@drawable/bg_unread_highlight"
|
||||
tools:text="115" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/roomNameView"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:duplicateParentState="true"
|
||||
android:textColor="@color/color_room_title"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/roomUnreadCounterBadgeView"
|
||||
app:layout_constraintStart_toEndOf="@id/roomAvatarImageView"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="@tools:sample/full_names" />
|
||||
|
||||
<im.vector.riotredesign.features.home.room.list.UnreadCounterBadgeView
|
||||
android:id="@+id/roomUnreadCounterBadgeView"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:minWidth="24dp"
|
||||
android:minHeight="24dp"
|
||||
android:paddingLeft="4dp"
|
||||
android:paddingRight="4dp"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="12sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:background="@drawable/bg_unread_highlight"
|
||||
tools:text="115" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</im.vector.riotredesign.core.platform.CheckableFrameLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item
|
||||
android:id="@+id/sliding_menu_settings"
|
||||
android:icon="@drawable/ic_settings"
|
||||
android:title="@string/room_sliding_menu_settings" />
|
||||
|
||||
<item
|
||||
android:id="@+id/sliding_menu_sign_out"
|
||||
android:icon="@drawable/ic_material_exit_to_app"
|
||||
|
|
Loading…
Reference in a new issue