From 275521db70419371e81c5594297f5179fc7147d7 Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 16 May 2019 19:14:02 +0200 Subject: [PATCH] Home: continue architecture rework. WIP --- .../android/api/session/user/UserService.kt | 8 ++ .../internal/database/mapper/UserMapper.kt | 27 +++--- .../internal/session/DefaultSession.kt | 5 + .../session/user/DefaultUserService.kt | 23 +++-- .../vector/riotredesign/core/di/AppModule.kt | 11 --- .../features/home/HomeActivity.kt | 6 -- .../features/home/HomeActivityViewModel.kt | 72 ++++++++------ .../features/home/HomeDrawerFragment.kt | 17 ++-- .../riotredesign/features/home/HomeModule.kt | 25 +++-- .../home/HomeRoomListObservableStore.kt | 22 +++++ .../features/home/group/GroupListViewModel.kt | 17 ++-- .../features/home/group/GroupSummaryItem.kt | 5 +- .../home/group/SelectedGroupFragment.kt | 58 +++++++---- .../home/room/detail/RoomDetailActions.kt | 1 - .../home/room/detail/RoomDetailActivity.kt | 14 ++- .../home/room/detail/RoomDetailFragment.kt | 24 +++-- .../home/room/detail/RoomDetailViewModel.kt | 62 ++++++------ .../home/room/list/RoomListFragment.kt | 10 ++ .../home/room/list/RoomListViewModel.kt | 76 ++------------- .../home/room/list/RoomListViewState.kt | 1 - .../home/room/list/RoomSummaryController.kt | 6 +- .../home/room/list/RoomSummaryItem.kt | 6 +- .../{bg_room_item.xml => bg_group_item.xml} | 2 +- .../main/res/layout/fragment_home_drawer.xml | 17 ++-- .../main/res/layout/fragment_room_detail.xml | 20 ++-- .../main/res/layout/fragment_room_list.xml | 7 ++ .../res/layout/fragment_selected_group.xml | 35 ++++++- vector/src/main/res/layout/item_group.xml | 84 +++++++++------- vector/src/main/res/layout/item_room.xml | 96 +++++++++---------- vector/src/main/res/menu/home.xml | 5 - 30 files changed, 416 insertions(+), 346 deletions(-) rename vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSelectionRepository.kt => matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/UserMapper.kt (51%) create mode 100644 vector/src/main/java/im/vector/riotredesign/features/home/HomeRoomListObservableStore.kt rename vector/src/main/res/drawable/{bg_room_item.xml => bg_group_item.xml} (83%) diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/user/UserService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/user/UserService.kt index 8e90e5e970..356ea6cc4f 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/user/UserService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/session/user/UserService.kt @@ -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 + } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSelectionRepository.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/UserMapper.kt similarity index 51% rename from vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSelectionRepository.kt rename to matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/UserMapper.kt index 9131d42994..2389427c90 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSelectionRepository.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/database/mapper/UserMapper.kt @@ -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) +} \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt index 420d675c92..2b43c15c55 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt @@ -231,6 +231,11 @@ internal class DefaultSession(override val sessionParams: SessionParams) : Sessi return userService.getUser(userId) } + override fun observeUser(userId: String): LiveData { + assert(isOpen) + return userService.observeUser(userId) + } + // Private methods ***************************************************************************** private fun assertMainThread() { diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/DefaultUserService.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/DefaultUserService.kt index b8e1f028bb..e3f68f06ee 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/DefaultUserService.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/user/DefaultUserService.kt @@ -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 { + val liveRealmData = RealmLiveData(monarchy.realmConfiguration) { realm -> + UserEntity.where(realm, userId) + } + return Transformations.map(liveRealmData) { results -> + results + .map { it.asDomain() } + .firstOrNull() + } } } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/core/di/AppModule.kt b/vector/src/main/java/im/vector/riotredesign/core/di/AppModule.kt index 6aff3e5a21..2c6541266c 100644 --- a/vector/src/main/java/im/vector/riotredesign/core/di/AppModule.kt +++ b/vector/src/main/java/im/vector/riotredesign/core/di/AppModule.kt @@ -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!! } - } } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/riotredesign/features/home/HomeActivity.kt index e30dcd1679..a61412dffc 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/HomeActivity.kt @@ -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 diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/HomeActivityViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/home/HomeActivityViewModel.kt index 03529618df..c710b47782 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/HomeActivityViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/HomeActivityViewModel.kt @@ -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(state), Session.Listener { companion object : MvRxViewModelFactory { @@ -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() - return HomeActivityViewModel(state, session, roomSelectionRepository) + val selectedGroupStore = viewModelContext.activity.get() + val homeRoomListObservableSource = viewModelContext.activity.get() + return HomeActivityViewModel(state, session, selectedGroupStore, homeRoomListObservableSource) } } @@ -54,29 +60,41 @@ class HomeActivityViewModel(state: EmptyState, val isLoading: LiveData get() = _isLoading - private val _openRoomLiveData = MutableLiveData>() - val openRoomLiveData: LiveData> - 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, Option, List>( + 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 { override fun onSuccess(data: String) { _isLoading.value = false - // Open room id - _openRoomLiveData.postValue(LiveEvent(data)) } override fun onFailure(failure: Throwable) { diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/HomeDrawerFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/home/HomeDrawerFragment.kt index 9566e881da..f32216db27 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/HomeDrawerFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/HomeDrawerFragment.kt @@ -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")) } } - } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt b/vector/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt index 1474d2da06..e5f085aa23 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/HomeModule.kt @@ -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) } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/HomeRoomListObservableStore.kt b/vector/src/main/java/im/vector/riotredesign/features/home/HomeRoomListObservableStore.kt new file mode 100644 index 0000000000..a2a3b64945 --- /dev/null +++ b/vector/src/main/java/im/vector/riotredesign/features/home/HomeRoomListObservableStore.kt @@ -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>(emptyList()) \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupListViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupListViewModel.kt index bbe042dfea..f8141e149b 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupListViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupListViewModel.kt @@ -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) } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupSummaryItem.kt b/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupSummaryItem.kt index 2bb1f81e6e..b9afe73844 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupSummaryItem.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/group/GroupSummaryItem.kt @@ -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() { 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(R.id.groupAvatarImageView) val groupNameView by bind(R.id.groupNameView) - val rootView by bind(R.id.itemGroupLayout) + val rootView by bind(R.id.itemGroupLayout) } } \ No newline at end of file diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/group/SelectedGroupFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/home/group/SelectedGroupFragment.kt index add2ef6f2b..a7fbe34951 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/group/SelectedGroupFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/group/SelectedGroupFragment.kt @@ -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() { - override fun onResourceReady(resource: Drawable, transition: Transition?) { - 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 { diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailActions.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailActions.kt index 7d6ffc04b4..c47320610f 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailActions.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailActions.kt @@ -25,7 +25,6 @@ sealed class RoomDetailActions { data class SendMessage(val text: String) : RoomDetailActions() data class SendMedia(val mediaFiles: List) : 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() diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailActivity.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailActivity.kt index fd79e8c123..b2ebc4c30b 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailActivity.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailActivity.kt @@ -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" diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt index dbc7408a63..87b30e8f7c 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailFragment.kt @@ -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 } } } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt index 44c2aa8f51..7f7f27eb40 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/detail/RoomDetailViewModel.kt @@ -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(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() - val visibleRoomHolder = viewModelContext.activity.get() - 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) } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListFragment.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListFragment.kt index 794c011d41..fedf61eb92 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListFragment.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListFragment.kt @@ -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() private val homeNavigator by inject() 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() diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewModel.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewModel.kt index fd9c19d315..1c015aa014 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewModel.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewModel.kt @@ -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(initialState) { @@ -53,11 +44,9 @@ class RoomListViewModel(initialState: RoomListViewState, @JvmStatic override fun create(viewModelContext: ViewModelContext, state: RoomListViewState): RoomListViewModel? { val currentSession = viewModelContext.activity.get() - val roomSelectionRepository = viewModelContext.activity.get() - val selectedGroupHolder = viewModelContext.activity.get() - val visibleRoomHolder = viewModelContext.activity.get() + val homeRoomListObservableSource = viewModelContext.activity.get() val roomSummaryComparator = viewModelContext.activity.get() - 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, Option, Option, 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, filterRoomOption: Option): List { - val filterRoom = filterRoomOption.orNull() - return rooms.filter { - if (filterRoom.isNullOrBlank()) { - true - } else { - it.displayName.contains(other = filterRoom, ignoreCase = true) - } - } - } - private fun buildRoomSummaries(rooms: List): RoomSummaries { val invites = ArrayList() val favourites = ArrayList() diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewState.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewState.kt index 164b6d3b9a..10c95efa4f 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewState.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomListViewState.kt @@ -25,7 +25,6 @@ import im.vector.riotredesign.R data class RoomListViewState( val asyncRooms: Async = Uninitialized, - val visibleRoomId: String? = null, val isInviteExpanded: Boolean = true, val isFavouriteRoomsExpanded: Boolean = true, val isDirectRoomsExpanded: Boolean = true, diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryController.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryController.kt index 24641da234..c509af407d 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryController.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryController.kt @@ -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, selectedRoomId: String?) { + private fun buildRoomModels(summaries: List) { 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) } diff --git a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryItem.kt b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryItem.kt index e68926101d..1cdde14d94 100644 --- a/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryItem.kt +++ b/vector/src/main/java/im/vector/riotredesign/features/home/room/list/RoomSummaryItem.kt @@ -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() { @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() { 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() { val unreadCounterBadgeView by bind(R.id.roomUnreadCounterBadgeView) val titleView by bind(R.id.roomNameView) val avatarImageView by bind(R.id.roomAvatarImageView) - val rootView by bind(R.id.itemRoomLayout) + val rootView by bind(R.id.itemRoomLayout) } } \ No newline at end of file diff --git a/vector/src/main/res/drawable/bg_room_item.xml b/vector/src/main/res/drawable/bg_group_item.xml similarity index 83% rename from vector/src/main/res/drawable/bg_room_item.xml rename to vector/src/main/res/drawable/bg_group_item.xml index 7a8d5873f9..221150eb8c 100644 --- a/vector/src/main/res/drawable/bg_room_item.xml +++ b/vector/src/main/res/drawable/bg_group_item.xml @@ -3,7 +3,7 @@ - + diff --git a/vector/src/main/res/layout/fragment_home_drawer.xml b/vector/src/main/res/layout/fragment_home_drawer.xml index d1bc3801d9..003715131d 100644 --- a/vector/src/main/res/layout/fragment_home_drawer.xml +++ b/vector/src/main/res/layout/fragment_home_drawer.xml @@ -2,9 +2,10 @@ + android:layout_height="match_parent" + android:clickable="true" + android:focusable="true"> - + app:layout_constraintTop_toBottomOf="@+id/homeDrawerUsernameView" /> diff --git a/vector/src/main/res/layout/fragment_room_detail.xml b/vector/src/main/res/layout/fragment_room_detail.xml index c65ae0e023..345f1189b0 100644 --- a/vector/src/main/res/layout/fragment_room_detail.xml +++ b/vector/src/main/res/layout/fragment_room_detail.xml @@ -6,7 +6,7 @@ android:layout_height="match_parent"> @@ -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" /> diff --git a/vector/src/main/res/layout/fragment_room_list.xml b/vector/src/main/res/layout/fragment_room_list.xml index 19cfdd59c0..249e14ae79 100644 --- a/vector/src/main/res/layout/fragment_room_list.xml +++ b/vector/src/main/res/layout/fragment_room_list.xml @@ -12,4 +12,11 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> + + diff --git a/vector/src/main/res/layout/fragment_selected_group.xml b/vector/src/main/res/layout/fragment_selected_group.xml index e2cd454db3..d29b1e7d64 100644 --- a/vector/src/main/res/layout/fragment_selected_group.xml +++ b/vector/src/main/res/layout/fragment_selected_group.xml @@ -2,11 +2,12 @@ + app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> + + + + + + + + + + + app:layout_constraintTop_toBottomOf="@+id/groupToolbar" /> - + android:foreground="?attr/selectableItemBackground" + android:paddingStart="8dp" + android:paddingLeft="8dp" + android:paddingEnd="16dp" + android:paddingRight="16dp"> - + - + - + - \ No newline at end of file + + + + + \ No newline at end of file diff --git a/vector/src/main/res/layout/item_room.xml b/vector/src/main/res/layout/item_room.xml index 0bbe7825c6..807d23636c 100644 --- a/vector/src/main/res/layout/item_room.xml +++ b/vector/src/main/res/layout/item_room.xml @@ -1,70 +1,62 @@ - - + + + 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" /> - + - - - - - - - \ No newline at end of file + diff --git a/vector/src/main/res/menu/home.xml b/vector/src/main/res/menu/home.xml index 2c8e3c0b30..c6df14a999 100644 --- a/vector/src/main/res/menu/home.xml +++ b/vector/src/main/res/menu/home.xml @@ -1,11 +1,6 @@ - -