Merge Space and Communities initial commit
This commit is contained in:
parent
733d4185c4
commit
1ce7085ca9
@ -19,20 +19,29 @@ package im.vector.app
|
|||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.LifecycleObserver
|
import androidx.lifecycle.LifecycleObserver
|
||||||
import androidx.lifecycle.OnLifecycleEvent
|
import androidx.lifecycle.OnLifecycleEvent
|
||||||
import arrow.core.Option
|
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
import im.vector.app.core.utils.BehaviorDataSource
|
import im.vector.app.core.utils.BehaviorDataSource
|
||||||
import im.vector.app.features.spaces.ALL_COMMUNITIES_GROUP_ID
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
import im.vector.app.features.ui.UiStateRepository
|
import im.vector.app.features.ui.UiStateRepository
|
||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.matrix.android.sdk.api.MatrixPatterns
|
|
||||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
sealed class RoomGroupingMethod {
|
||||||
|
data class ByLegacyGroup(val groupSummary: GroupSummary?) : RoomGroupingMethod()
|
||||||
|
data class BySpace(val spaceSummary: RoomSummary?) : RoomGroupingMethod()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun RoomGroupingMethod.space() = (this as? RoomGroupingMethod.BySpace)?.spaceSummary
|
||||||
|
fun RoomGroupingMethod.group() = (this as? RoomGroupingMethod.ByLegacyGroup)?.groupSummary
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class handles the global app state.
|
* This class handles the global app state.
|
||||||
* It requires to be added to ProcessLifecycleOwner.get().lifecycle
|
* It requires to be added to ProcessLifecycleOwner.get().lifecycle
|
||||||
@ -42,48 +51,83 @@ import javax.inject.Singleton
|
|||||||
class AppStateHandler @Inject constructor(
|
class AppStateHandler @Inject constructor(
|
||||||
sessionDataSource: ActiveSessionDataSource,
|
sessionDataSource: ActiveSessionDataSource,
|
||||||
private val uiStateRepository: UiStateRepository,
|
private val uiStateRepository: UiStateRepository,
|
||||||
private val activeSessionHolder: ActiveSessionHolder
|
private val activeSessionHolder: ActiveSessionHolder,
|
||||||
|
vectorPreferences: VectorPreferences
|
||||||
) : LifecycleObserver {
|
) : LifecycleObserver {
|
||||||
|
|
||||||
private val compositeDisposable = CompositeDisposable()
|
private val compositeDisposable = CompositeDisposable()
|
||||||
|
|
||||||
private val selectedSpaceDataSource = BehaviorDataSource<Option<RoomSummary>>(Option.empty())
|
private val selectedSpaceDataSource = BehaviorDataSource(
|
||||||
|
// TODO get that from latest persisted?
|
||||||
|
if (vectorPreferences.labSpaces())
|
||||||
|
RoomGroupingMethod.BySpace(null)
|
||||||
|
else RoomGroupingMethod.ByLegacyGroup(null)
|
||||||
|
)
|
||||||
|
|
||||||
val selectedSpaceObservable = selectedSpaceDataSource.observe()
|
val selectedRoomGroupingObservable = selectedSpaceDataSource.observe()
|
||||||
|
|
||||||
fun setCurrentSpace(space: RoomSummary?) {
|
fun getCurrentRoomGroupingMethod(): RoomGroupingMethod = selectedSpaceDataSource.currentValue ?: RoomGroupingMethod.BySpace(null)
|
||||||
if (space == selectedSpaceDataSource.currentValue?.orNull()) return
|
|
||||||
selectedSpaceDataSource.post(space?.let { Option.just(it) } ?: Option.empty())
|
fun setCurrentSpace(spaceId: String?, session: Session? = null) {
|
||||||
if (space != null && space.roomId != ALL_COMMUNITIES_GROUP_ID) {
|
val uSession = session ?: activeSessionHolder.getSafeActiveSession()
|
||||||
|
if (selectedSpaceDataSource.currentValue is RoomGroupingMethod.BySpace
|
||||||
|
&& spaceId == selectedSpaceDataSource.currentValue?.space()?.roomId) return
|
||||||
|
val spaceSum = spaceId?.let { uSession?.getRoomSummary(spaceId) }
|
||||||
|
selectedSpaceDataSource.post(RoomGroupingMethod.BySpace(spaceSum))
|
||||||
|
if (spaceId != null) {
|
||||||
GlobalScope.launch {
|
GlobalScope.launch {
|
||||||
tryOrNull {
|
tryOrNull {
|
||||||
activeSessionHolder.getSafeActiveSession()?.getRoom(space.roomId)?.loadRoomMembersIfNeeded()
|
uSession?.getRoom(spaceId)?.loadRoomMembersIfNeeded()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setCurrentGroup(groupId: String?, session: Session? = null) {
|
||||||
|
val uSession = session ?: activeSessionHolder.getSafeActiveSession()
|
||||||
|
if (selectedSpaceDataSource.currentValue is RoomGroupingMethod.ByLegacyGroup
|
||||||
|
&& groupId == selectedSpaceDataSource.currentValue?.group()?.groupId) return
|
||||||
|
val activeGroup = groupId?.let { uSession?.getGroupSummary(groupId) }
|
||||||
|
selectedSpaceDataSource.post(RoomGroupingMethod.ByLegacyGroup(activeGroup))
|
||||||
|
if (groupId != null) {
|
||||||
|
GlobalScope.launch {
|
||||||
|
tryOrNull {
|
||||||
|
uSession?.getGroup(groupId)?.fetchGroupData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// restore current space from ui state
|
|
||||||
sessionDataSource.currentValue?.orNull()?.let { session ->
|
sessionDataSource.observe()
|
||||||
uiStateRepository.getSelectedSpace(session.sessionId)?.let { selectedSpaceId ->
|
.distinctUntilChanged()
|
||||||
session.getRoomSummary(selectedSpaceId)?.let {
|
.subscribe {
|
||||||
setCurrentSpace(it)
|
it.orNull()?.let { session ->
|
||||||
}
|
Timber.w("VAL: Latest method is space? ${uiStateRepository.isGroupingMethodSpace(session.sessionId)}")
|
||||||
}
|
if (uiStateRepository.isGroupingMethodSpace(session.sessionId)) {
|
||||||
|
uiStateRepository.getSelectedSpace(session.sessionId)?.let { selectedSpaceId ->
|
||||||
|
Timber.w("VAL: Latest selected space: $selectedSpaceId")
|
||||||
|
setCurrentSpace(selectedSpaceId, session)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uiStateRepository.getSelectedGroup(session.sessionId)?.let { selectedGroupId ->
|
||||||
|
setCurrentGroup(selectedGroupId, session)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.also {
|
||||||
|
compositeDisposable.add(it)
|
||||||
}
|
}
|
||||||
|
// restore current space from ui state
|
||||||
}
|
}
|
||||||
|
|
||||||
fun safeActiveSpaceId(): String? {
|
fun safeActiveSpaceId(): String? {
|
||||||
return selectedSpaceDataSource.currentValue?.orNull()?.roomId?.takeIf {
|
return (selectedSpaceDataSource.currentValue as? RoomGroupingMethod.BySpace)?.spaceSummary?.roomId
|
||||||
MatrixPatterns.isRoomId(it)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun safeActiveSpace(): RoomSummary? {
|
fun safeActiveGroupId(): String? {
|
||||||
return selectedSpaceDataSource.currentValue?.orNull()?.takeIf {
|
return (selectedSpaceDataSource.currentValue as? RoomGroupingMethod.ByLegacyGroup)?.groupSummary?.groupId
|
||||||
MatrixPatterns.isRoomId(it.roomId)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
|
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
|
||||||
@ -93,5 +137,19 @@ class AppStateHandler @Inject constructor(
|
|||||||
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
|
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
|
||||||
fun entersBackground() {
|
fun entersBackground() {
|
||||||
compositeDisposable.clear()
|
compositeDisposable.clear()
|
||||||
|
Timber.w("VAL: entersBackground session: ${ activeSessionHolder.getSafeActiveSession()?.myUserId}")
|
||||||
|
val session = activeSessionHolder.getSafeActiveSession() ?: return
|
||||||
|
when (val currentMethod = selectedSpaceDataSource.currentValue ?: RoomGroupingMethod.BySpace(null)) {
|
||||||
|
is RoomGroupingMethod.BySpace -> {
|
||||||
|
uiStateRepository.storeGroupingMethod(true, session)
|
||||||
|
Timber.w("VAL: Store selected space: ${currentMethod.spaceSummary?.roomId}")
|
||||||
|
uiStateRepository.storeSelectedSpace(currentMethod.spaceSummary?.roomId, session)
|
||||||
|
}
|
||||||
|
is RoomGroupingMethod.ByLegacyGroup -> {
|
||||||
|
uiStateRepository.storeGroupingMethod(false, session)
|
||||||
|
Timber.w("VAL: Store group space: ${currentMethod.groupSummary?.groupId}")
|
||||||
|
uiStateRepository.storeSelectedGroup(currentMethod.groupSummary?.groupId, session)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,6 @@ import im.vector.app.features.devtools.RoomDevToolSendFormFragment
|
|||||||
import im.vector.app.features.devtools.RoomDevToolStateEventListFragment
|
import im.vector.app.features.devtools.RoomDevToolStateEventListFragment
|
||||||
import im.vector.app.features.discovery.DiscoverySettingsFragment
|
import im.vector.app.features.discovery.DiscoverySettingsFragment
|
||||||
import im.vector.app.features.discovery.change.SetIdentityServerFragment
|
import im.vector.app.features.discovery.change.SetIdentityServerFragment
|
||||||
import im.vector.app.features.grouplist.GroupListFragment
|
|
||||||
import im.vector.app.features.home.HomeDetailFragment
|
import im.vector.app.features.home.HomeDetailFragment
|
||||||
import im.vector.app.features.home.HomeDrawerFragment
|
import im.vector.app.features.home.HomeDrawerFragment
|
||||||
import im.vector.app.features.home.LoadingFragment
|
import im.vector.app.features.home.LoadingFragment
|
||||||
@ -150,11 +149,6 @@ interface FragmentModule {
|
|||||||
@FragmentKey(LocalePickerFragment::class)
|
@FragmentKey(LocalePickerFragment::class)
|
||||||
fun bindLocalePickerFragment(fragment: LocalePickerFragment): Fragment
|
fun bindLocalePickerFragment(fragment: LocalePickerFragment): Fragment
|
||||||
|
|
||||||
@Binds
|
|
||||||
@IntoMap
|
|
||||||
@FragmentKey(GroupListFragment::class)
|
|
||||||
fun bindGroupListFragment(fragment: GroupListFragment): Fragment
|
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@IntoMap
|
@IntoMap
|
||||||
@FragmentKey(SpaceListFragment::class)
|
@FragmentKey(SpaceListFragment::class)
|
||||||
|
@ -35,7 +35,6 @@ import im.vector.app.features.call.webrtc.WebRtcCallManager
|
|||||||
import im.vector.app.features.configuration.VectorConfiguration
|
import im.vector.app.features.configuration.VectorConfiguration
|
||||||
import im.vector.app.features.crypto.keysrequest.KeyRequestHandler
|
import im.vector.app.features.crypto.keysrequest.KeyRequestHandler
|
||||||
import im.vector.app.features.crypto.verification.IncomingVerificationRequestHandler
|
import im.vector.app.features.crypto.verification.IncomingVerificationRequestHandler
|
||||||
import im.vector.app.features.grouplist.SelectedGroupDataSource
|
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
import im.vector.app.features.home.CurrentSpaceSuggestedRoomListDataSource
|
import im.vector.app.features.home.CurrentSpaceSuggestedRoomListDataSource
|
||||||
import im.vector.app.features.home.room.detail.RoomDetailPendingActionStore
|
import im.vector.app.features.home.room.detail.RoomDetailPendingActionStore
|
||||||
@ -115,8 +114,6 @@ interface VectorComponent {
|
|||||||
|
|
||||||
fun errorFormatter(): ErrorFormatter
|
fun errorFormatter(): ErrorFormatter
|
||||||
|
|
||||||
fun selectedGroupStore(): SelectedGroupDataSource
|
|
||||||
|
|
||||||
fun appStateHandler(): AppStateHandler
|
fun appStateHandler(): AppStateHandler
|
||||||
|
|
||||||
fun currentSpaceSuggestedRoomListDataSource(): CurrentSpaceSuggestedRoomListDataSource
|
fun currentSpaceSuggestedRoomListDataSource(): CurrentSpaceSuggestedRoomListDataSource
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.app.features.grouplist
|
|
||||||
|
|
||||||
import im.vector.app.core.platform.VectorViewModelAction
|
|
||||||
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
|
||||||
|
|
||||||
sealed class GroupListAction : VectorViewModelAction {
|
|
||||||
data class SelectGroup(val groupSummary: GroupSummary) : GroupListAction()
|
|
||||||
}
|
|
@ -1,83 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.app.features.grouplist
|
|
||||||
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import com.airbnb.mvrx.Incomplete
|
|
||||||
import com.airbnb.mvrx.Success
|
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
|
||||||
import com.airbnb.mvrx.withState
|
|
||||||
import im.vector.app.core.extensions.cleanup
|
|
||||||
import im.vector.app.core.extensions.configureWith
|
|
||||||
import im.vector.app.core.extensions.exhaustive
|
|
||||||
import im.vector.app.core.platform.StateView
|
|
||||||
import im.vector.app.core.platform.VectorBaseFragment
|
|
||||||
import im.vector.app.databinding.FragmentGroupListBinding
|
|
||||||
import im.vector.app.features.home.HomeActivitySharedAction
|
|
||||||
import im.vector.app.features.home.HomeSharedActionViewModel
|
|
||||||
|
|
||||||
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
class GroupListFragment @Inject constructor(
|
|
||||||
val groupListViewModelFactory: GroupListViewModel.Factory,
|
|
||||||
private val groupController: GroupSummaryController
|
|
||||||
) : VectorBaseFragment<FragmentGroupListBinding>(),
|
|
||||||
GroupSummaryController.Callback {
|
|
||||||
|
|
||||||
private lateinit var sharedActionViewModel: HomeSharedActionViewModel
|
|
||||||
private val viewModel: GroupListViewModel by fragmentViewModel()
|
|
||||||
|
|
||||||
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentGroupListBinding {
|
|
||||||
return FragmentGroupListBinding.inflate(inflater, container, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
sharedActionViewModel = activityViewModelProvider.get(HomeSharedActionViewModel::class.java)
|
|
||||||
groupController.callback = this
|
|
||||||
views.stateView.contentView = views.groupListView
|
|
||||||
views.groupListView.configureWith(groupController)
|
|
||||||
viewModel.observeViewEvents {
|
|
||||||
when (it) {
|
|
||||||
is GroupListViewEvents.OpenGroupSummary -> sharedActionViewModel.post(HomeActivitySharedAction.OpenGroup)
|
|
||||||
}.exhaustive
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
|
||||||
groupController.callback = null
|
|
||||||
views.groupListView.cleanup()
|
|
||||||
super.onDestroyView()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun invalidate() = withState(viewModel) { state ->
|
|
||||||
when (state.asyncGroups) {
|
|
||||||
is Incomplete -> views.stateView.state = StateView.State.Loading
|
|
||||||
is Success -> views.stateView.state = StateView.State.Content
|
|
||||||
}
|
|
||||||
groupController.update(state)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onGroupSelected(groupSummary: GroupSummary) {
|
|
||||||
viewModel.handle(GroupListAction.SelectGroup(groupSummary))
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,142 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.app.features.grouplist
|
|
||||||
|
|
||||||
import androidx.lifecycle.viewModelScope
|
|
||||||
import arrow.core.Option
|
|
||||||
import com.airbnb.mvrx.FragmentViewModelContext
|
|
||||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
|
||||||
import com.airbnb.mvrx.ViewModelContext
|
|
||||||
import dagger.assisted.Assisted
|
|
||||||
import dagger.assisted.AssistedInject
|
|
||||||
import dagger.assisted.AssistedFactory
|
|
||||||
import im.vector.app.R
|
|
||||||
import im.vector.app.core.platform.VectorViewModel
|
|
||||||
import im.vector.app.core.resources.StringProvider
|
|
||||||
import io.reactivex.Observable
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
|
||||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
|
||||||
import org.matrix.android.sdk.api.session.Session
|
|
||||||
import org.matrix.android.sdk.api.session.group.groupSummaryQueryParams
|
|
||||||
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
|
||||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
|
||||||
import org.matrix.android.sdk.rx.rx
|
|
||||||
|
|
||||||
const val ALL_COMMUNITIES_GROUP_ID = "+ALL_COMMUNITIES_GROUP_ID"
|
|
||||||
|
|
||||||
class GroupListViewModel @AssistedInject constructor(@Assisted initialState: GroupListViewState,
|
|
||||||
private val selectedGroupStore: SelectedGroupDataSource,
|
|
||||||
private val session: Session,
|
|
||||||
private val stringProvider: StringProvider
|
|
||||||
) : VectorViewModel<GroupListViewState, GroupListAction, GroupListViewEvents>(initialState) {
|
|
||||||
|
|
||||||
@AssistedFactory
|
|
||||||
interface Factory {
|
|
||||||
fun create(initialState: GroupListViewState): GroupListViewModel
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object : MvRxViewModelFactory<GroupListViewModel, GroupListViewState> {
|
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
override fun create(viewModelContext: ViewModelContext, state: GroupListViewState): GroupListViewModel? {
|
|
||||||
val groupListFragment: GroupListFragment = (viewModelContext as FragmentViewModelContext).fragment()
|
|
||||||
return groupListFragment.groupListViewModelFactory.create(state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var currentGroupId = ""
|
|
||||||
|
|
||||||
init {
|
|
||||||
observeGroupSummaries()
|
|
||||||
observeSelectionState()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun observeSelectionState() {
|
|
||||||
selectSubscribe(GroupListViewState::selectedGroup) { groupSummary ->
|
|
||||||
if (groupSummary != null) {
|
|
||||||
// We only want to open group if the updated selectedGroup is a different one.
|
|
||||||
if (currentGroupId != groupSummary.groupId) {
|
|
||||||
currentGroupId = groupSummary.groupId
|
|
||||||
_viewEvents.post(GroupListViewEvents.OpenGroupSummary)
|
|
||||||
}
|
|
||||||
val optionGroup = Option.just(groupSummary)
|
|
||||||
selectedGroupStore.post(optionGroup)
|
|
||||||
} else {
|
|
||||||
// If selected group is null we force to default. It can happens when leaving the selected group.
|
|
||||||
setState {
|
|
||||||
copy(selectedGroup = this.asyncGroups()?.find { it.groupId == ALL_COMMUNITIES_GROUP_ID })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun handle(action: GroupListAction) {
|
|
||||||
when (action) {
|
|
||||||
is GroupListAction.SelectGroup -> handleSelectGroup(action)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// PRIVATE METHODS *****************************************************************************
|
|
||||||
|
|
||||||
private fun handleSelectGroup(action: GroupListAction.SelectGroup) = withState { state ->
|
|
||||||
if (state.selectedGroup?.groupId != action.groupSummary.groupId) {
|
|
||||||
// We take care of refreshing group data when selecting to be sure we get all the rooms and users
|
|
||||||
tryOrNull {
|
|
||||||
viewModelScope.launch {
|
|
||||||
session.getGroup(action.groupSummary.groupId)?.fetchGroupData()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setState { copy(selectedGroup = action.groupSummary) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun observeGroupSummaries() {
|
|
||||||
val groupSummariesQueryParams = groupSummaryQueryParams {
|
|
||||||
memberships = listOf(Membership.JOIN)
|
|
||||||
displayName = QueryStringValue.IsNotEmpty
|
|
||||||
}
|
|
||||||
Observable.combineLatest<GroupSummary, List<GroupSummary>, List<GroupSummary>>(
|
|
||||||
session
|
|
||||||
.rx()
|
|
||||||
.liveUser(session.myUserId)
|
|
||||||
.map { optionalUser ->
|
|
||||||
GroupSummary(
|
|
||||||
groupId = ALL_COMMUNITIES_GROUP_ID,
|
|
||||||
membership = Membership.JOIN,
|
|
||||||
displayName = stringProvider.getString(R.string.group_all_communities),
|
|
||||||
avatarUrl = optionalUser.getOrNull()?.avatarUrl ?: "")
|
|
||||||
},
|
|
||||||
session
|
|
||||||
.rx()
|
|
||||||
.liveGroupSummaries(groupSummariesQueryParams),
|
|
||||||
{ allCommunityGroup, communityGroups ->
|
|
||||||
listOf(allCommunityGroup) + communityGroups
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.execute { async ->
|
|
||||||
val currentSelectedGroupId = selectedGroup?.groupId
|
|
||||||
val newSelectedGroup = if (currentSelectedGroupId != null) {
|
|
||||||
async()?.find { it.groupId == currentSelectedGroupId }
|
|
||||||
} else {
|
|
||||||
async()?.firstOrNull()
|
|
||||||
}
|
|
||||||
copy(asyncGroups = async, selectedGroup = newSelectedGroup)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.app.features.grouplist
|
|
||||||
|
|
||||||
import com.airbnb.mvrx.Async
|
|
||||||
import com.airbnb.mvrx.MvRxState
|
|
||||||
import com.airbnb.mvrx.Uninitialized
|
|
||||||
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
|
||||||
|
|
||||||
data class GroupListViewState(
|
|
||||||
val asyncGroups: Async<List<GroupSummary>> = Uninitialized,
|
|
||||||
val selectedGroup: GroupSummary? = null
|
|
||||||
) : MvRxState
|
|
@ -1,64 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.app.features.grouplist
|
|
||||||
|
|
||||||
import com.airbnb.epoxy.EpoxyController
|
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
|
||||||
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
|
||||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
class GroupSummaryController @Inject constructor(private val avatarRenderer: AvatarRenderer) : EpoxyController() {
|
|
||||||
|
|
||||||
var callback: Callback? = null
|
|
||||||
private var viewState: GroupListViewState? = null
|
|
||||||
|
|
||||||
init {
|
|
||||||
requestModelBuild()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun update(viewState: GroupListViewState) {
|
|
||||||
this.viewState = viewState
|
|
||||||
requestModelBuild()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun buildModels() {
|
|
||||||
val nonNullViewState = viewState ?: return
|
|
||||||
buildGroupModels(nonNullViewState.asyncGroups(), nonNullViewState.selectedGroup)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun buildGroupModels(summaries: List<GroupSummary>?, selected: GroupSummary?) {
|
|
||||||
if (summaries.isNullOrEmpty()) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
summaries.forEach { groupSummary ->
|
|
||||||
val isSelected = groupSummary.groupId == selected?.groupId
|
|
||||||
groupSummaryItem {
|
|
||||||
avatarRenderer(avatarRenderer)
|
|
||||||
id(groupSummary.groupId)
|
|
||||||
matrixItem(groupSummary.toMatrixItem())
|
|
||||||
selected(isSelected)
|
|
||||||
listener { callback?.onGroupSelected(groupSummary) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Callback {
|
|
||||||
fun onGroupSelected(groupSummary: GroupSummary)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,26 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.app.features.grouplist
|
|
||||||
|
|
||||||
import arrow.core.Option
|
|
||||||
import im.vector.app.core.utils.BehaviorDataSource
|
|
||||||
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
|
||||||
import javax.inject.Inject
|
|
||||||
import javax.inject.Singleton
|
|
||||||
|
|
||||||
@Singleton
|
|
||||||
class SelectedGroupDataSource @Inject constructor() : BehaviorDataSource<Option<GroupSummary>>(Option.empty())
|
|
@ -32,6 +32,7 @@ import androidx.core.view.isVisible
|
|||||||
import androidx.drawerlayout.widget.DrawerLayout
|
import androidx.drawerlayout.widget.DrawerLayout
|
||||||
import com.airbnb.mvrx.MvRx
|
import com.airbnb.mvrx.MvRx
|
||||||
import com.airbnb.mvrx.viewModel
|
import com.airbnb.mvrx.viewModel
|
||||||
|
import im.vector.app.AppStateHandler
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
import im.vector.app.core.di.ScreenComponent
|
import im.vector.app.core.di.ScreenComponent
|
||||||
@ -108,6 +109,7 @@ class HomeActivity :
|
|||||||
@Inject lateinit var permalinkHandler: PermalinkHandler
|
@Inject lateinit var permalinkHandler: PermalinkHandler
|
||||||
@Inject lateinit var avatarRenderer: AvatarRenderer
|
@Inject lateinit var avatarRenderer: AvatarRenderer
|
||||||
@Inject lateinit var initSyncStepFormatter: InitSyncStepFormatter
|
@Inject lateinit var initSyncStepFormatter: InitSyncStepFormatter
|
||||||
|
@Inject lateinit var appStateHandler: AppStateHandler
|
||||||
|
|
||||||
private val createSpaceResultLauncher = registerStartForActivityResult { activityResult ->
|
private val createSpaceResultLauncher = registerStartForActivityResult { activityResult ->
|
||||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||||
@ -152,10 +154,15 @@ class HomeActivity :
|
|||||||
sharedActionViewModel = viewModelProvider.get(HomeSharedActionViewModel::class.java)
|
sharedActionViewModel = viewModelProvider.get(HomeSharedActionViewModel::class.java)
|
||||||
views.drawerLayout.addDrawerListener(drawerListener)
|
views.drawerLayout.addDrawerListener(drawerListener)
|
||||||
if (isFirstCreation()) {
|
if (isFirstCreation()) {
|
||||||
replaceFragment(R.id.homeDetailFragmentContainer, LoadingFragment::class.java)
|
replaceFragment(R.id.homeDetailFragmentContainer, HomeDetailFragment::class.java)
|
||||||
replaceFragment(R.id.homeDrawerFragmentContainer, HomeDrawerFragment::class.java)
|
replaceFragment(R.id.homeDrawerFragmentContainer, HomeDrawerFragment::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// appStateHandler.selectedRoomGroupingObservable.subscribe {
|
||||||
|
// if (supportFragmentManager.getFragment())
|
||||||
|
// replaceFragment(R.id.homeDetailFragmentContainer, HomeDetailFragment::class.java, allowStateLoss = true)
|
||||||
|
// }.disposeOnDestroy()
|
||||||
|
|
||||||
sharedActionViewModel
|
sharedActionViewModel
|
||||||
.observe()
|
.observe()
|
||||||
.subscribe { sharedAction ->
|
.subscribe { sharedAction ->
|
||||||
@ -164,13 +171,17 @@ class HomeActivity :
|
|||||||
is HomeActivitySharedAction.CloseDrawer -> views.drawerLayout.closeDrawer(GravityCompat.START)
|
is HomeActivitySharedAction.CloseDrawer -> views.drawerLayout.closeDrawer(GravityCompat.START)
|
||||||
is HomeActivitySharedAction.OpenGroup -> {
|
is HomeActivitySharedAction.OpenGroup -> {
|
||||||
views.drawerLayout.closeDrawer(GravityCompat.START)
|
views.drawerLayout.closeDrawer(GravityCompat.START)
|
||||||
|
|
||||||
// Temporary
|
// Temporary
|
||||||
|
// When switching from space to group or group to space, we need to reload the fragment
|
||||||
|
// To be removed when dropping legacy groups
|
||||||
|
if (sharedAction.clearFragment) {
|
||||||
|
replaceFragment(R.id.homeDetailFragmentContainer, HomeDetailFragment::class.java, allowStateLoss = true)
|
||||||
|
} else {
|
||||||
|
// nop
|
||||||
|
}
|
||||||
// we might want to delay that to avoid having the drawer animation lagging
|
// we might want to delay that to avoid having the drawer animation lagging
|
||||||
// would be probably better to let the drawer do that? in the on closed callback?
|
// would be probably better to let the drawer do that? in the on closed callback?
|
||||||
views.coordinatorLayout.postDelayed({
|
|
||||||
replaceFragment(R.id.homeDetailFragmentContainer, HomeDetailFragment::class.java, allowStateLoss = true)
|
|
||||||
}, 200)
|
|
||||||
Unit
|
|
||||||
}
|
}
|
||||||
is HomeActivitySharedAction.OpenSpacePreview -> {
|
is HomeActivitySharedAction.OpenSpacePreview -> {
|
||||||
startActivity(SpacePreviewActivity.newIntent(this, sharedAction.spaceId))
|
startActivity(SpacePreviewActivity.newIntent(this, sharedAction.spaceId))
|
||||||
|
@ -24,7 +24,7 @@ import im.vector.app.core.platform.VectorSharedAction
|
|||||||
sealed class HomeActivitySharedAction : VectorSharedAction {
|
sealed class HomeActivitySharedAction : VectorSharedAction {
|
||||||
object OpenDrawer : HomeActivitySharedAction()
|
object OpenDrawer : HomeActivitySharedAction()
|
||||||
object CloseDrawer : HomeActivitySharedAction()
|
object CloseDrawer : HomeActivitySharedAction()
|
||||||
object OpenGroup : HomeActivitySharedAction()
|
data class OpenGroup(val clearFragment: Boolean) : HomeActivitySharedAction()
|
||||||
object AddSpace : HomeActivitySharedAction()
|
object AddSpace : HomeActivitySharedAction()
|
||||||
data class OpenSpacePreview(val spaceId: String) : HomeActivitySharedAction()
|
data class OpenSpacePreview(val spaceId: String) : HomeActivitySharedAction()
|
||||||
data class ShowSpaceSettings(val spaceId: String) : HomeActivitySharedAction()
|
data class ShowSpaceSettings(val spaceId: String) : HomeActivitySharedAction()
|
||||||
|
@ -29,6 +29,7 @@ import com.airbnb.mvrx.fragmentViewModel
|
|||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
import com.google.android.material.badge.BadgeDrawable
|
import com.google.android.material.badge.BadgeDrawable
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
import im.vector.app.RoomGroupingMethod
|
||||||
import im.vector.app.core.extensions.commitTransaction
|
import im.vector.app.core.extensions.commitTransaction
|
||||||
import im.vector.app.core.extensions.toMvRxBundle
|
import im.vector.app.core.extensions.toMvRxBundle
|
||||||
import im.vector.app.core.platform.ToolbarConfigurable
|
import im.vector.app.core.platform.ToolbarConfigurable
|
||||||
@ -48,7 +49,6 @@ import im.vector.app.features.popup.PopupAlertManager
|
|||||||
import im.vector.app.features.popup.VerificationVectorAlert
|
import im.vector.app.features.popup.VerificationVectorAlert
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
import im.vector.app.features.settings.VectorSettingsActivity.Companion.EXTRA_DIRECT_ACCESS_SECURITY_PRIVACY_MANAGE_SESSIONS
|
import im.vector.app.features.settings.VectorSettingsActivity.Companion.EXTRA_DIRECT_ACCESS_SECURITY_PRIVACY_MANAGE_SESSIONS
|
||||||
import im.vector.app.features.spaces.ALL_COMMUNITIES_GROUP_ID
|
|
||||||
import im.vector.app.features.themes.ThemeUtils
|
import im.vector.app.features.themes.ThemeUtils
|
||||||
import im.vector.app.features.workers.signout.BannerState
|
import im.vector.app.features.workers.signout.BannerState
|
||||||
import im.vector.app.features.workers.signout.ServerBackupStatusViewModel
|
import im.vector.app.features.workers.signout.ServerBackupStatusViewModel
|
||||||
@ -125,15 +125,14 @@ class HomeDetailFragment @Inject constructor(
|
|||||||
views.bottomNavigationView.selectedItemId = it.displayMode.toMenuId()
|
views.bottomNavigationView.selectedItemId = it.displayMode.toMenuId()
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModel.selectSubscribe(this, HomeDetailViewState::groupSummary) { groupSummary ->
|
viewModel.selectSubscribe(this, HomeDetailViewState::roomGroupingMethod) { roomGroupingMethod ->
|
||||||
if (!vectorPreferences.labSpaces()) {
|
when (roomGroupingMethod) {
|
||||||
onGroupChange(groupSummary.orNull())
|
is RoomGroupingMethod.ByLegacyGroup -> {
|
||||||
}
|
onGroupChange(roomGroupingMethod.groupSummary)
|
||||||
}
|
}
|
||||||
|
is RoomGroupingMethod.BySpace -> {
|
||||||
viewModel.selectSubscribe(this, HomeDetailViewState::spaceSummary) { spaceSummary ->
|
onSpaceChange(roomGroupingMethod.spaceSummary)
|
||||||
if (vectorPreferences.labSpaces()) {
|
}
|
||||||
onSpaceChange(spaceSummary.orNull())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,8 +256,7 @@ class HomeDetailFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun onGroupChange(groupSummary: GroupSummary?) {
|
private fun onGroupChange(groupSummary: GroupSummary?) {
|
||||||
groupSummary ?: return
|
if (groupSummary == null) {
|
||||||
if (groupSummary.groupId == ALL_COMMUNITIES_GROUP_ID) {
|
|
||||||
views.groupToolbarSpaceTitleView.isVisible = false
|
views.groupToolbarSpaceTitleView.isVisible = false
|
||||||
} else {
|
} else {
|
||||||
views.groupToolbarSpaceTitleView.isVisible = true
|
views.groupToolbarSpaceTitleView.isVisible = true
|
||||||
@ -267,8 +265,7 @@ class HomeDetailFragment @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun onSpaceChange(spaceSummary: RoomSummary?) {
|
private fun onSpaceChange(spaceSummary: RoomSummary?) {
|
||||||
spaceSummary ?: return
|
if (spaceSummary == null) {
|
||||||
if (spaceSummary.roomId == ALL_COMMUNITIES_GROUP_ID) {
|
|
||||||
views.groupToolbarSpaceTitleView.isVisible = false
|
views.groupToolbarSpaceTitleView.isVisible = false
|
||||||
} else {
|
} else {
|
||||||
views.groupToolbarSpaceTitleView.isVisible = true
|
views.groupToolbarSpaceTitleView.isVisible = true
|
||||||
@ -310,11 +307,14 @@ class HomeDetailFragment @Inject constructor(
|
|||||||
|
|
||||||
views.homeToolbarContent.debouncedClicks {
|
views.homeToolbarContent.debouncedClicks {
|
||||||
withState(viewModel) {
|
withState(viewModel) {
|
||||||
if (vectorPreferences.labSpaces()) {
|
when (it.roomGroupingMethod) {
|
||||||
val currentSpace = it.spaceSummary.orNull()
|
is RoomGroupingMethod.ByLegacyGroup -> {
|
||||||
?.takeIf { it.roomId != ALL_COMMUNITIES_GROUP_ID }
|
// nothing do far
|
||||||
if (vectorPreferences.labSpaces() && currentSpace != null) {
|
}
|
||||||
sharedActionViewModel.post(HomeActivitySharedAction.ShowSpaceSettings(currentSpace.roomId))
|
is RoomGroupingMethod.BySpace -> {
|
||||||
|
it.roomGroupingMethod.spaceSummary?.let {
|
||||||
|
sharedActionViewModel.post(HomeActivitySharedAction.ShowSpaceSettings(it.roomId))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,12 +24,12 @@ import dagger.assisted.Assisted
|
|||||||
import dagger.assisted.AssistedFactory
|
import dagger.assisted.AssistedFactory
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
import im.vector.app.AppStateHandler
|
import im.vector.app.AppStateHandler
|
||||||
|
import im.vector.app.RoomGroupingMethod
|
||||||
import im.vector.app.core.di.HasScreenInjector
|
import im.vector.app.core.di.HasScreenInjector
|
||||||
import im.vector.app.core.platform.EmptyViewEvents
|
import im.vector.app.core.platform.EmptyViewEvents
|
||||||
import im.vector.app.core.platform.VectorViewModel
|
import im.vector.app.core.platform.VectorViewModel
|
||||||
import im.vector.app.core.resources.StringProvider
|
|
||||||
import im.vector.app.features.grouplist.SelectedGroupDataSource
|
|
||||||
import im.vector.app.features.ui.UiStateRepository
|
import im.vector.app.features.ui.UiStateRepository
|
||||||
|
import io.reactivex.schedulers.Schedulers
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
|
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
|
||||||
@ -51,9 +51,7 @@ import java.util.concurrent.TimeUnit
|
|||||||
class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: HomeDetailViewState,
|
class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: HomeDetailViewState,
|
||||||
private val session: Session,
|
private val session: Session,
|
||||||
private val uiStateRepository: UiStateRepository,
|
private val uiStateRepository: UiStateRepository,
|
||||||
private val selectedGroupStore: SelectedGroupDataSource,
|
private val appStateHandler: AppStateHandler)
|
||||||
private val appStateHandler: AppStateHandler,
|
|
||||||
private val stringProvider: StringProvider)
|
|
||||||
: VectorViewModel<HomeDetailViewState, HomeDetailAction, EmptyViewEvents>(initialState) {
|
: VectorViewModel<HomeDetailViewState, HomeDetailAction, EmptyViewEvents>(initialState) {
|
||||||
|
|
||||||
@AssistedFactory
|
@AssistedFactory
|
||||||
@ -79,8 +77,7 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho
|
|||||||
|
|
||||||
init {
|
init {
|
||||||
observeSyncState()
|
observeSyncState()
|
||||||
observeSelectedGroupStore()
|
observeRoomGroupingMethod()
|
||||||
observeSelectedSpaceStore()
|
|
||||||
observeRoomSummaries()
|
observeRoomSummaries()
|
||||||
|
|
||||||
session.rx().liveUser(session.myUserId).execute {
|
session.rx().liveUser(session.myUserId).execute {
|
||||||
@ -138,29 +135,22 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho
|
|||||||
.disposeOnClear()
|
.disposeOnClear()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeSelectedGroupStore() {
|
private fun observeRoomGroupingMethod() {
|
||||||
selectedGroupStore
|
appStateHandler.selectedRoomGroupingObservable
|
||||||
.observe()
|
|
||||||
.subscribe {
|
.subscribe {
|
||||||
setState {
|
setState {
|
||||||
copy(groupSummary = it)
|
copy(
|
||||||
}
|
roomGroupingMethod = it
|
||||||
}
|
)
|
||||||
.disposeOnClear()
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun observeSelectedSpaceStore() {
|
|
||||||
appStateHandler.selectedSpaceObservable
|
|
||||||
.subscribe {
|
|
||||||
setState {
|
|
||||||
copy(spaceSummary = it)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.disposeOnClear()
|
.disposeOnClear()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeRoomSummaries() {
|
private fun observeRoomSummaries() {
|
||||||
appStateHandler.selectedSpaceObservable.distinctUntilChanged().switchMap {
|
appStateHandler.selectedRoomGroupingObservable.distinctUntilChanged().switchMap {
|
||||||
|
// we use it as a trigger to all changes in room, but do not really load
|
||||||
|
// the actual models
|
||||||
session.getPagedRoomSummariesLive(
|
session.getPagedRoomSummariesLive(
|
||||||
roomSummaryQueryParams {
|
roomSummaryQueryParams {
|
||||||
memberships = Membership.activeMemberships()
|
memberships = Membership.activeMemberships()
|
||||||
@ -168,50 +158,55 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho
|
|||||||
sortOrder = RoomSortOrder.NONE
|
sortOrder = RoomSortOrder.NONE
|
||||||
).asObservable()
|
).asObservable()
|
||||||
}
|
}
|
||||||
|
.observeOn(Schedulers.computation())
|
||||||
// .asObservable()
|
|
||||||
.throttleFirst(300, TimeUnit.MILLISECONDS)
|
.throttleFirst(300, TimeUnit.MILLISECONDS)
|
||||||
.subscribe {
|
.subscribe {
|
||||||
val activeSpace = appStateHandler.safeActiveSpaceId()
|
when (val groupingMethod = appStateHandler.getCurrentRoomGroupingMethod()) {
|
||||||
val dmInvites = session.getRoomSummaries(
|
is RoomGroupingMethod.ByLegacyGroup -> {
|
||||||
roomSummaryQueryParams {
|
// TODO!!
|
||||||
memberships = listOf(Membership.INVITE)
|
}
|
||||||
roomCategoryFilter = RoomCategoryFilter.ONLY_DM
|
is RoomGroupingMethod.BySpace -> {
|
||||||
}
|
val dmInvites = session.getRoomSummaries(
|
||||||
).size
|
roomSummaryQueryParams {
|
||||||
|
memberships = listOf(Membership.INVITE)
|
||||||
|
roomCategoryFilter = RoomCategoryFilter.ONLY_DM
|
||||||
|
}
|
||||||
|
).size
|
||||||
|
|
||||||
val roomsInvite = session.getRoomSummaries(
|
val roomsInvite = session.getRoomSummaries(
|
||||||
roomSummaryQueryParams {
|
roomSummaryQueryParams {
|
||||||
memberships = listOf(Membership.INVITE)
|
memberships = listOf(Membership.INVITE)
|
||||||
roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||||
}
|
}
|
||||||
).size
|
).size
|
||||||
|
|
||||||
val dmRooms = session.getNotificationCountForRooms(
|
val dmRooms = session.getNotificationCountForRooms(
|
||||||
roomSummaryQueryParams {
|
roomSummaryQueryParams {
|
||||||
memberships = listOf(Membership.JOIN)
|
memberships = listOf(Membership.JOIN)
|
||||||
roomCategoryFilter = RoomCategoryFilter.ONLY_DM
|
roomCategoryFilter = RoomCategoryFilter.ONLY_DM
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
val otherRooms = session.getNotificationCountForRooms(
|
val otherRooms = session.getNotificationCountForRooms(
|
||||||
roomSummaryQueryParams {
|
roomSummaryQueryParams {
|
||||||
memberships = listOf(Membership.JOIN)
|
memberships = listOf(Membership.JOIN)
|
||||||
roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||||
activeSpaceId = ActiveSpaceFilter.ActiveSpace(activeSpace)
|
activeSpaceId = ActiveSpaceFilter.ActiveSpace(groupingMethod.spaceSummary?.roomId)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
setState {
|
setState {
|
||||||
copy(
|
copy(
|
||||||
notificationCountCatchup = dmRooms.totalCount + otherRooms.totalCount + roomsInvite + dmInvites,
|
notificationCountCatchup = dmRooms.totalCount + otherRooms.totalCount + roomsInvite + dmInvites,
|
||||||
notificationHighlightCatchup = dmRooms.isHighlight || otherRooms.isHighlight,
|
notificationHighlightCatchup = dmRooms.isHighlight || otherRooms.isHighlight,
|
||||||
notificationCountPeople = dmRooms.totalCount + dmInvites,
|
notificationCountPeople = dmRooms.totalCount + dmInvites,
|
||||||
notificationHighlightPeople = dmRooms.isHighlight || dmInvites > 0,
|
notificationHighlightPeople = dmRooms.isHighlight || dmInvites > 0,
|
||||||
notificationCountRooms = otherRooms.totalCount + roomsInvite,
|
notificationCountRooms = otherRooms.totalCount + roomsInvite,
|
||||||
notificationHighlightRooms = otherRooms.isHighlight || roomsInvite > 0,
|
notificationHighlightRooms = otherRooms.isHighlight || roomsInvite > 0,
|
||||||
hasUnreadMessages = dmRooms.totalCount + otherRooms.totalCount > 0
|
hasUnreadMessages = dmRooms.totalCount + otherRooms.totalCount > 0
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.disposeOnClear()
|
.disposeOnClear()
|
||||||
|
@ -16,18 +16,16 @@
|
|||||||
|
|
||||||
package im.vector.app.features.home
|
package im.vector.app.features.home
|
||||||
|
|
||||||
import arrow.core.Option
|
|
||||||
import com.airbnb.mvrx.Async
|
import com.airbnb.mvrx.Async
|
||||||
import com.airbnb.mvrx.MvRxState
|
import com.airbnb.mvrx.MvRxState
|
||||||
import com.airbnb.mvrx.Uninitialized
|
import com.airbnb.mvrx.Uninitialized
|
||||||
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
import im.vector.app.RoomGroupingMethod
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
import org.matrix.android.sdk.api.session.sync.SyncState
|
import org.matrix.android.sdk.api.session.sync.SyncState
|
||||||
import org.matrix.android.sdk.api.util.MatrixItem
|
import org.matrix.android.sdk.api.util.MatrixItem
|
||||||
|
|
||||||
data class HomeDetailViewState(
|
data class HomeDetailViewState(
|
||||||
val groupSummary: Option<GroupSummary> = Option.empty(),
|
val roomGroupingMethod: RoomGroupingMethod = RoomGroupingMethod.BySpace(null),
|
||||||
val spaceSummary: Option<RoomSummary> = Option.empty(),
|
|
||||||
val myMatrixItem: MatrixItem? = null,
|
val myMatrixItem: MatrixItem? = null,
|
||||||
val asyncRooms: Async<List<RoomSummary>> = Uninitialized,
|
val asyncRooms: Async<List<RoomSummary>> = Uninitialized,
|
||||||
val displayMode: RoomListDisplayMode = RoomListDisplayMode.PEOPLE,
|
val displayMode: RoomListDisplayMode = RoomListDisplayMode.PEOPLE,
|
||||||
|
@ -30,7 +30,7 @@ import im.vector.app.core.extensions.replaceChildFragment
|
|||||||
import im.vector.app.core.platform.VectorBaseFragment
|
import im.vector.app.core.platform.VectorBaseFragment
|
||||||
import im.vector.app.core.utils.startSharePlainTextIntent
|
import im.vector.app.core.utils.startSharePlainTextIntent
|
||||||
import im.vector.app.databinding.FragmentHomeDrawerBinding
|
import im.vector.app.databinding.FragmentHomeDrawerBinding
|
||||||
import im.vector.app.features.grouplist.GroupListFragment
|
// import im.vector.app.features.grouplist.GroupListFragment
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
import im.vector.app.features.settings.VectorSettingsActivity
|
import im.vector.app.features.settings.VectorSettingsActivity
|
||||||
import im.vector.app.features.spaces.SpaceListFragment
|
import im.vector.app.features.spaces.SpaceListFragment
|
||||||
@ -59,11 +59,11 @@ class HomeDrawerFragment @Inject constructor(
|
|||||||
sharedActionViewModel = activityViewModelProvider.get(HomeSharedActionViewModel::class.java)
|
sharedActionViewModel = activityViewModelProvider.get(HomeSharedActionViewModel::class.java)
|
||||||
|
|
||||||
if (savedInstanceState == null) {
|
if (savedInstanceState == null) {
|
||||||
if (vectorPreferences.labSpaces()) {
|
// if (vectorPreferences.labSpaces()) {
|
||||||
replaceChildFragment(R.id.homeDrawerGroupListContainer, SpaceListFragment::class.java)
|
replaceChildFragment(R.id.homeDrawerGroupListContainer, SpaceListFragment::class.java)
|
||||||
} else {
|
// } else {
|
||||||
replaceChildFragment(R.id.homeDrawerGroupListContainer, GroupListFragment::class.java)
|
// replaceChildFragment(R.id.homeDrawerGroupListContainer, GroupListFragment::class.java)
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
session.getUserLive(session.myUserId).observeK(viewLifecycleOwner) { optionalUser ->
|
session.getUserLive(session.myUserId).observeK(viewLifecycleOwner) { optionalUser ->
|
||||||
val user = optionalUser?.getOrNull()
|
val user = optionalUser?.getOrNull()
|
||||||
|
@ -107,8 +107,8 @@ class UnreadMessagesSharedViewModel @AssistedInject constructor(@Assisted initia
|
|||||||
}.disposeOnClear()
|
}.disposeOnClear()
|
||||||
|
|
||||||
Observable.combineLatest(
|
Observable.combineLatest(
|
||||||
appStateHandler.selectedSpaceObservable.distinctUntilChanged(),
|
appStateHandler.selectedRoomGroupingObservable.distinctUntilChanged(),
|
||||||
appStateHandler.selectedSpaceObservable.switchMap {
|
appStateHandler.selectedRoomGroupingObservable.switchMap {
|
||||||
session.getPagedRoomSummariesLive(
|
session.getPagedRoomSummariesLive(
|
||||||
roomSummaryQueryParams {
|
roomSummaryQueryParams {
|
||||||
this.memberships = Membership.activeMemberships()
|
this.memberships = Membership.activeMemberships()
|
||||||
|
@ -179,14 +179,14 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||||||
observePowerLevel()
|
observePowerLevel()
|
||||||
updateShowDialerOptionState()
|
updateShowDialerOptionState()
|
||||||
room.getRoomSummaryLive()
|
room.getRoomSummaryLive()
|
||||||
viewModelScope.launch {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
tryOrNull { room.markAsRead(ReadService.MarkAsReadParams.READ_RECEIPT) }
|
tryOrNull { room.markAsRead(ReadService.MarkAsReadParams.READ_RECEIPT) }
|
||||||
}
|
}
|
||||||
// Inform the SDK that the room is displayed
|
// Inform the SDK that the room is displayed
|
||||||
viewModelScope.launch {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
session.onRoomDisplayed(initialState.roomId)
|
session.onRoomDisplayed(initialState.roomId)
|
||||||
} catch (_: Exception) {
|
} catch (_: Throwable) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
callManager.addPstnSupportListener(this)
|
callManager.addPstnSupportListener(this)
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
package im.vector.app.features.home.room.list
|
package im.vector.app.features.home.room.list
|
||||||
|
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
|
import im.vector.app.AppStateHandler
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
import im.vector.app.RoomGroupingMethod
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.features.grouplist.ALL_COMMUNITIES_GROUP_ID
|
|
||||||
import im.vector.app.features.grouplist.SelectedGroupDataSource
|
|
||||||
import im.vector.app.features.home.RoomListDisplayMode
|
import im.vector.app.features.home.RoomListDisplayMode
|
||||||
import io.reactivex.disposables.Disposable
|
import io.reactivex.disposables.Disposable
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
@ -37,25 +37,24 @@ class GroupRoomListSectionBuilder(
|
|||||||
val session: Session,
|
val session: Session,
|
||||||
val stringProvider: StringProvider,
|
val stringProvider: StringProvider,
|
||||||
val viewModelScope: CoroutineScope,
|
val viewModelScope: CoroutineScope,
|
||||||
val selectedGroupDataSource: SelectedGroupDataSource,
|
val appStateHandler: AppStateHandler,
|
||||||
val onDisposable: (Disposable) -> Unit,
|
val onDisposable: (Disposable) -> Unit,
|
||||||
val onUdpatable: (UpdatableLivePageResult) -> Unit
|
val onUdpatable: (UpdatableLivePageResult) -> Unit
|
||||||
) : RoomListSectionBuilder {
|
) : RoomListSectionBuilder {
|
||||||
|
|
||||||
override fun buildSections(mode: RoomListDisplayMode): List<RoomsSection> {
|
override fun buildSections(mode: RoomListDisplayMode): List<RoomsSection> {
|
||||||
val activeSpaceAwareQueries = mutableListOf<UpdatableLivePageResult>()
|
val activeGroupAwareQueries = mutableListOf<UpdatableLivePageResult>()
|
||||||
val sections = mutableListOf<RoomsSection>()
|
val sections = mutableListOf<RoomsSection>()
|
||||||
val actualGroupId = selectedGroupDataSource.currentValue?.orNull()
|
val actualGroupId = appStateHandler.safeActiveGroupId()
|
||||||
?.groupId?.takeIf { it != ALL_COMMUNITIES_GROUP_ID }
|
|
||||||
|
|
||||||
when (mode) {
|
when (mode) {
|
||||||
RoomListDisplayMode.PEOPLE -> {
|
RoomListDisplayMode.PEOPLE -> {
|
||||||
// 3 sections Invites / Fav / Dms
|
// 3 sections Invites / Fav / Dms
|
||||||
buildPeopleSections(sections, activeSpaceAwareQueries, actualGroupId)
|
buildPeopleSections(sections, activeGroupAwareQueries, actualGroupId)
|
||||||
}
|
}
|
||||||
RoomListDisplayMode.ROOMS -> {
|
RoomListDisplayMode.ROOMS -> {
|
||||||
// 5 sections invites / Fav / Rooms / Low Priority / Server notice
|
// 5 sections invites / Fav / Rooms / Low Priority / Server notice
|
||||||
buildRoomsSections(sections, activeSpaceAwareQueries, actualGroupId)
|
buildRoomsSections(sections, activeGroupAwareQueries, actualGroupId)
|
||||||
}
|
}
|
||||||
RoomListDisplayMode.FILTERED -> {
|
RoomListDisplayMode.FILTERED -> {
|
||||||
// Used when searching for rooms
|
// Used when searching for rooms
|
||||||
@ -76,7 +75,7 @@ class GroupRoomListSectionBuilder(
|
|||||||
RoomListDisplayMode.NOTIFICATIONS -> {
|
RoomListDisplayMode.NOTIFICATIONS -> {
|
||||||
addSection(
|
addSection(
|
||||||
sections,
|
sections,
|
||||||
activeSpaceAwareQueries,
|
activeGroupAwareQueries,
|
||||||
R.string.invitations_header,
|
R.string.invitations_header,
|
||||||
true
|
true
|
||||||
) {
|
) {
|
||||||
@ -87,7 +86,7 @@ class GroupRoomListSectionBuilder(
|
|||||||
|
|
||||||
addSection(
|
addSection(
|
||||||
sections,
|
sections,
|
||||||
activeSpaceAwareQueries,
|
activeGroupAwareQueries,
|
||||||
R.string.bottom_action_rooms,
|
R.string.bottom_action_rooms,
|
||||||
false
|
false
|
||||||
) {
|
) {
|
||||||
@ -98,11 +97,11 @@ class GroupRoomListSectionBuilder(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedGroupDataSource.observe()
|
appStateHandler.selectedRoomGroupingObservable
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.subscribe { activeSpaceOption ->
|
.subscribe { groupingMethod ->
|
||||||
val selectedGroupId = activeSpaceOption.orNull()?.groupId?.takeIf { it != ALL_COMMUNITIES_GROUP_ID }
|
val selectedGroupId = (groupingMethod as? RoomGroupingMethod.ByLegacyGroup)?.groupSummary?.groupId
|
||||||
activeSpaceAwareQueries.onEach { updater ->
|
activeGroupAwareQueries.onEach { updater ->
|
||||||
updater.updateQuery { query ->
|
updater.updateQuery { query ->
|
||||||
query.copy(activeGroupId = selectedGroupId)
|
query.copy(activeGroupId = selectedGroupId)
|
||||||
}
|
}
|
||||||
|
@ -26,10 +26,10 @@ import com.airbnb.mvrx.MvRxViewModelFactory
|
|||||||
import com.airbnb.mvrx.Success
|
import com.airbnb.mvrx.Success
|
||||||
import com.airbnb.mvrx.ViewModelContext
|
import com.airbnb.mvrx.ViewModelContext
|
||||||
import im.vector.app.AppStateHandler
|
import im.vector.app.AppStateHandler
|
||||||
|
import im.vector.app.RoomGroupingMethod
|
||||||
import im.vector.app.core.extensions.exhaustive
|
import im.vector.app.core.extensions.exhaustive
|
||||||
import im.vector.app.core.platform.VectorViewModel
|
import im.vector.app.core.platform.VectorViewModel
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.features.grouplist.SelectedGroupDataSource
|
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
@ -49,7 +49,6 @@ class RoomListViewModel @Inject constructor(
|
|||||||
private val session: Session,
|
private val session: Session,
|
||||||
private val stringProvider: StringProvider,
|
private val stringProvider: StringProvider,
|
||||||
private val appStateHandler: AppStateHandler,
|
private val appStateHandler: AppStateHandler,
|
||||||
private val selectedGroupDataSource: SelectedGroupDataSource,
|
|
||||||
private val vectorPreferences: VectorPreferences
|
private val vectorPreferences: VectorPreferences
|
||||||
) : VectorViewModel<RoomListViewState, RoomListAction, RoomListViewEvents>(initialState) {
|
) : VectorViewModel<RoomListViewState, RoomListAction, RoomListViewEvents>(initialState) {
|
||||||
|
|
||||||
@ -72,15 +71,14 @@ class RoomListViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
Timber.w("VAL: RoomListViewModel INIT")
|
||||||
observeMembershipChanges()
|
observeMembershipChanges()
|
||||||
|
|
||||||
appStateHandler.selectedSpaceObservable
|
appStateHandler.selectedRoomGroupingObservable
|
||||||
.distinctUntilChanged()
|
|
||||||
.map { it.orNull() }
|
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.execute {
|
.execute {
|
||||||
copy(
|
copy(
|
||||||
currentSpace = it
|
currentRoomGrouping = it
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +111,7 @@ class RoomListViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val sections: List<RoomsSection> by lazy {
|
val sections: List<RoomsSection> by lazy {
|
||||||
if (vectorPreferences.labSpaces()) {
|
if (appStateHandler.getCurrentRoomGroupingMethod() is RoomGroupingMethod.BySpace) {
|
||||||
SpaceRoomListSectionBuilder(
|
SpaceRoomListSectionBuilder(
|
||||||
session,
|
session,
|
||||||
stringProvider,
|
stringProvider,
|
||||||
@ -132,7 +130,7 @@ class RoomListViewModel @Inject constructor(
|
|||||||
session,
|
session,
|
||||||
stringProvider,
|
stringProvider,
|
||||||
viewModelScope,
|
viewModelScope,
|
||||||
selectedGroupDataSource,
|
appStateHandler,
|
||||||
{
|
{
|
||||||
it.disposeOnClear()
|
it.disposeOnClear()
|
||||||
},
|
},
|
||||||
|
@ -18,7 +18,6 @@ package im.vector.app.features.home.room.list
|
|||||||
|
|
||||||
import im.vector.app.AppStateHandler
|
import im.vector.app.AppStateHandler
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.features.grouplist.SelectedGroupDataSource
|
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -27,8 +26,7 @@ import javax.inject.Provider
|
|||||||
class RoomListViewModelFactory @Inject constructor(private val session: Provider<Session>,
|
class RoomListViewModelFactory @Inject constructor(private val session: Provider<Session>,
|
||||||
private val appStateHandler: AppStateHandler,
|
private val appStateHandler: AppStateHandler,
|
||||||
private val stringProvider: StringProvider,
|
private val stringProvider: StringProvider,
|
||||||
private val vectorPreferences: VectorPreferences,
|
private val vectorPreferences: VectorPreferences)
|
||||||
private val selectedGroupDataSource: SelectedGroupDataSource)
|
|
||||||
: RoomListViewModel.Factory {
|
: RoomListViewModel.Factory {
|
||||||
|
|
||||||
override fun create(initialState: RoomListViewState): RoomListViewModel {
|
override fun create(initialState: RoomListViewState): RoomListViewModel {
|
||||||
@ -37,7 +35,6 @@ class RoomListViewModelFactory @Inject constructor(private val session: Provider
|
|||||||
session.get(),
|
session.get(),
|
||||||
stringProvider,
|
stringProvider,
|
||||||
appStateHandler,
|
appStateHandler,
|
||||||
selectedGroupDataSource,
|
|
||||||
vectorPreferences
|
vectorPreferences
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -19,9 +19,9 @@ package im.vector.app.features.home.room.list
|
|||||||
import com.airbnb.mvrx.Async
|
import com.airbnb.mvrx.Async
|
||||||
import com.airbnb.mvrx.MvRxState
|
import com.airbnb.mvrx.MvRxState
|
||||||
import com.airbnb.mvrx.Uninitialized
|
import com.airbnb.mvrx.Uninitialized
|
||||||
|
import im.vector.app.RoomGroupingMethod
|
||||||
import im.vector.app.features.home.RoomListDisplayMode
|
import im.vector.app.features.home.RoomListDisplayMode
|
||||||
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
|
import org.matrix.android.sdk.api.session.room.members.ChangeMembershipState
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
|
||||||
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
||||||
|
|
||||||
data class RoomListViewState(
|
data class RoomListViewState(
|
||||||
@ -30,7 +30,7 @@ data class RoomListViewState(
|
|||||||
val roomMembershipChanges: Map<String, ChangeMembershipState> = emptyMap(),
|
val roomMembershipChanges: Map<String, ChangeMembershipState> = emptyMap(),
|
||||||
val asyncSuggestedRooms: Async<List<SpaceChildInfo>> = Uninitialized,
|
val asyncSuggestedRooms: Async<List<SpaceChildInfo>> = Uninitialized,
|
||||||
val currentUserName: String? = null,
|
val currentUserName: String? = null,
|
||||||
val currentSpace: Async<RoomSummary?> = Uninitialized
|
val currentRoomGrouping: Async<RoomGroupingMethod> = Uninitialized
|
||||||
) : MvRxState {
|
) : MvRxState {
|
||||||
|
|
||||||
constructor(args: RoomListParams) : this(displayMode = args.displayMode)
|
constructor(args: RoomListParams) : this(displayMode = args.displayMode)
|
||||||
|
@ -26,13 +26,13 @@ import im.vector.app.AppStateHandler
|
|||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.features.home.RoomListDisplayMode
|
import im.vector.app.features.home.RoomListDisplayMode
|
||||||
|
import im.vector.app.space
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
import io.reactivex.disposables.Disposable
|
import io.reactivex.disposables.Disposable
|
||||||
import io.reactivex.rxkotlin.Observables
|
import io.reactivex.rxkotlin.Observables
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import org.matrix.android.sdk.api.MatrixPatterns
|
|
||||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
|
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
|
||||||
import org.matrix.android.sdk.api.query.RoomCategoryFilter
|
import org.matrix.android.sdk.api.query.RoomCategoryFilter
|
||||||
@ -110,12 +110,12 @@ class SpaceRoomListSectionBuilder(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
appStateHandler.selectedSpaceObservable
|
appStateHandler.selectedRoomGroupingObservable
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.subscribe { activeSpaceOption ->
|
.subscribe { groupingMethod ->
|
||||||
val selectedSpace = activeSpaceOption.orNull()
|
val selectedSpace = groupingMethod.space()
|
||||||
activeSpaceAwareQueries.onEach { updater ->
|
activeSpaceAwareQueries.onEach { updater ->
|
||||||
updater.updateForSpaceId(selectedSpace?.roomId?.takeIf { MatrixPatterns.isRoomId(it) })
|
updater.updateForSpaceId(selectedSpace?.roomId)
|
||||||
}
|
}
|
||||||
}.also {
|
}.also {
|
||||||
onDisposable.invoke(it)
|
onDisposable.invoke(it)
|
||||||
@ -185,10 +185,10 @@ class SpaceRoomListSectionBuilder(
|
|||||||
|
|
||||||
// add suggested rooms
|
// add suggested rooms
|
||||||
val suggestedRoomsObservable = // MutableLiveData<List<SpaceChildInfo>>()
|
val suggestedRoomsObservable = // MutableLiveData<List<SpaceChildInfo>>()
|
||||||
appStateHandler.selectedSpaceObservable
|
appStateHandler.selectedRoomGroupingObservable
|
||||||
.distinctUntilChanged()
|
.distinctUntilChanged()
|
||||||
.switchMap { activeSpaceOption ->
|
.switchMap { groupingMethod ->
|
||||||
val selectedSpace = activeSpaceOption.orNull()
|
val selectedSpace = groupingMethod.space()
|
||||||
if (selectedSpace == null) {
|
if (selectedSpace == null) {
|
||||||
Observable.just(emptyList())
|
Observable.just(emptyList())
|
||||||
} else {
|
} else {
|
||||||
|
@ -31,6 +31,7 @@ import androidx.core.util.Pair
|
|||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
import im.vector.app.AppStateHandler
|
import im.vector.app.AppStateHandler
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
import im.vector.app.RoomGroupingMethod
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
import im.vector.app.core.error.fatalError
|
import im.vector.app.core.error.fatalError
|
||||||
import im.vector.app.core.platform.VectorBaseActivity
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
@ -76,13 +77,13 @@ import im.vector.app.features.spaces.SpacePreviewActivity
|
|||||||
import im.vector.app.features.terms.ReviewTermsActivity
|
import im.vector.app.features.terms.ReviewTermsActivity
|
||||||
import im.vector.app.features.widgets.WidgetActivity
|
import im.vector.app.features.widgets.WidgetActivity
|
||||||
import im.vector.app.features.widgets.WidgetArgsBuilder
|
import im.vector.app.features.widgets.WidgetArgsBuilder
|
||||||
|
import im.vector.app.space
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.IncomingSasVerificationTransaction
|
import org.matrix.android.sdk.api.session.crypto.verification.IncomingSasVerificationTransaction
|
||||||
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
|
import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom
|
||||||
import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryData
|
import org.matrix.android.sdk.api.session.room.model.thirdparty.RoomDirectoryData
|
||||||
import org.matrix.android.sdk.api.session.terms.TermsService
|
import org.matrix.android.sdk.api.session.terms.TermsService
|
||||||
import org.matrix.android.sdk.api.session.widgets.model.Widget
|
import org.matrix.android.sdk.api.session.widgets.model.Widget
|
||||||
import org.matrix.android.sdk.api.session.widgets.model.WidgetType
|
import org.matrix.android.sdk.api.session.widgets.model.WidgetType
|
||||||
import timber.log.Timber
|
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@ -106,17 +107,11 @@ class DefaultNavigator @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun switchToSpace(context: Context, spaceId: String, roomId: String?, openShareSheet: Boolean) {
|
override fun switchToSpace(context: Context, spaceId: String, roomId: String?, openShareSheet: Boolean) {
|
||||||
if (sessionHolder.getSafeActiveSession()?.spaceService()?.getSpace(spaceId) == null) {
|
if (sessionHolder.getSafeActiveSession()?.getRoomSummary(spaceId) == null) {
|
||||||
fatalError("Trying to open an unknown space $spaceId", vectorPreferences.failFast())
|
fatalError("Trying to open an unknown space $spaceId", vectorPreferences.failFast())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
appStateHandler.setCurrentSpace(spaceId)
|
||||||
sessionHolder.getSafeActiveSession()?.spaceService()?.getSpace(spaceId)?.spaceSummary()?.let {
|
|
||||||
Timber.d("## Nav: Switching to space $spaceId / ${it.name}")
|
|
||||||
appStateHandler.setCurrentSpace(it)
|
|
||||||
} ?: kotlin.run {
|
|
||||||
Timber.d("## Nav: Failed to switch to space $spaceId")
|
|
||||||
}
|
|
||||||
if (roomId != null) {
|
if (roomId != null) {
|
||||||
val args = RoomDetailArgs(roomId, eventId = null, openShareSpaceForId = spaceId.takeIf { openShareSheet })
|
val args = RoomDetailArgs(roomId, eventId = null, openShareSpaceForId = spaceId.takeIf { openShareSheet })
|
||||||
val intent = RoomDetailActivity.newIntent(context, args)
|
val intent = RoomDetailActivity.newIntent(context, args)
|
||||||
@ -251,15 +246,22 @@ class DefaultNavigator @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun openRoomDirectory(context: Context, initialFilter: String) {
|
override fun openRoomDirectory(context: Context, initialFilter: String) {
|
||||||
val selectedSpace = appStateHandler.safeActiveSpace()?.let {
|
when (val groupingMethod = appStateHandler.getCurrentRoomGroupingMethod()) {
|
||||||
sessionHolder.getSafeActiveSession()?.getRoomSummary(it.roomId)
|
is RoomGroupingMethod.ByLegacyGroup -> {
|
||||||
}
|
// TODO should open list of rooms of this group
|
||||||
if (selectedSpace == null) {
|
val intent = RoomDirectoryActivity.getIntent(context, initialFilter)
|
||||||
val intent = RoomDirectoryActivity.getIntent(context, initialFilter)
|
context.startActivity(intent)
|
||||||
context.startActivity(intent)
|
}
|
||||||
} else {
|
is RoomGroupingMethod.BySpace -> {
|
||||||
SpaceExploreActivity.newIntent(context, selectedSpace.roomId).let {
|
val selectedSpace = groupingMethod.space()
|
||||||
context.startActivity(it)
|
if (selectedSpace == null) {
|
||||||
|
val intent = RoomDirectoryActivity.getIntent(context, initialFilter)
|
||||||
|
context.startActivity(intent)
|
||||||
|
} else {
|
||||||
|
SpaceExploreActivity.newIntent(context, selectedSpace.roomId).let {
|
||||||
|
context.startActivity(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -275,29 +277,36 @@ class DefaultNavigator @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun openInviteUsersToRoom(context: Context, roomId: String) {
|
override fun openInviteUsersToRoom(context: Context, roomId: String) {
|
||||||
val selectedSpace = appStateHandler.safeActiveSpace()
|
when (val currentGroupingMethod = appStateHandler.getCurrentRoomGroupingMethod()) {
|
||||||
if (vectorPreferences.labSpaces() && selectedSpace != null) {
|
is RoomGroupingMethod.ByLegacyGroup -> {
|
||||||
// let user decides if he does it from space or room
|
val intent = InviteUsersToRoomActivity.getIntent(context, roomId)
|
||||||
(context as? AppCompatActivity)?.supportFragmentManager?.let { fm ->
|
context.startActivity(intent)
|
||||||
InviteRoomSpaceChooserBottomSheet.newInstance(
|
}
|
||||||
selectedSpace.roomId,
|
is RoomGroupingMethod.BySpace -> {
|
||||||
roomId,
|
if (currentGroupingMethod.spaceSummary != null) {
|
||||||
object : InviteRoomSpaceChooserBottomSheet.InteractionListener {
|
// let user decides if he does it from space or room
|
||||||
override fun inviteToSpace(spaceId: String) {
|
(context as? AppCompatActivity)?.supportFragmentManager?.let { fm ->
|
||||||
val intent = InviteUsersToRoomActivity.getIntent(context, spaceId)
|
InviteRoomSpaceChooserBottomSheet.newInstance(
|
||||||
context.startActivity(intent)
|
currentGroupingMethod.spaceSummary.roomId,
|
||||||
}
|
roomId,
|
||||||
|
object : InviteRoomSpaceChooserBottomSheet.InteractionListener {
|
||||||
override fun inviteToRoom(roomId: String) {
|
override fun inviteToSpace(spaceId: String) {
|
||||||
val intent = InviteUsersToRoomActivity.getIntent(context, roomId)
|
val intent = InviteUsersToRoomActivity.getIntent(context, spaceId)
|
||||||
context.startActivity(intent)
|
context.startActivity(intent)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
).show(fm, InviteRoomSpaceChooserBottomSheet::class.java.name)
|
override fun inviteToRoom(roomId: String) {
|
||||||
|
val intent = InviteUsersToRoomActivity.getIntent(context, roomId)
|
||||||
|
context.startActivity(intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
).show(fm, InviteRoomSpaceChooserBottomSheet::class.java.name)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val intent = InviteUsersToRoomActivity.getIntent(context, roomId)
|
||||||
|
context.startActivity(intent)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
val intent = InviteUsersToRoomActivity.getIntent(context, roomId)
|
|
||||||
context.startActivity(intent)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021 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.app.features.spaces
|
||||||
|
|
||||||
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||||
|
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||||
|
import im.vector.app.core.utils.DebouncedClickListener
|
||||||
|
|
||||||
|
@EpoxyModelClass(layout = R.layout.item_space_add)
|
||||||
|
abstract class SpaceAddItem : VectorEpoxyModel<SpaceAddItem.Holder>() {
|
||||||
|
|
||||||
|
@EpoxyAttribute var listener: (() -> Unit)? = null
|
||||||
|
|
||||||
|
override fun bind(holder: Holder) {
|
||||||
|
super.bind(holder)
|
||||||
|
holder.view.setOnClickListener(
|
||||||
|
DebouncedClickListener({
|
||||||
|
listener?.invoke()
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Holder : VectorEpoxyHolder()
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2020 New Vector Ltd
|
* Copyright (c) 2021 New Vector Ltd
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@ -14,13 +14,15 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package im.vector.app.features.grouplist
|
package im.vector.app.features.spaces
|
||||||
|
|
||||||
import im.vector.app.core.platform.VectorViewEvents
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||||
|
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||||
|
|
||||||
/**
|
@EpoxyModelClass(layout = R.layout.item_space_beta_header)
|
||||||
* Transient events for group list screen
|
abstract class SpaceBetaHeaderItem : VectorEpoxyModel<SpaceBetaHeaderItem.Holder>() {
|
||||||
*/
|
|
||||||
sealed class GroupListViewEvents : VectorViewEvents {
|
class Holder : VectorEpoxyHolder()
|
||||||
object OpenGroupSummary : GroupListViewEvents()
|
|
||||||
}
|
}
|
@ -17,6 +17,7 @@
|
|||||||
package im.vector.app.features.spaces
|
package im.vector.app.features.spaces
|
||||||
|
|
||||||
import im.vector.app.core.platform.VectorViewModelAction
|
import im.vector.app.core.platform.VectorViewModelAction
|
||||||
|
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
|
||||||
sealed class SpaceListAction : VectorViewModelAction {
|
sealed class SpaceListAction : VectorViewModelAction {
|
||||||
@ -25,4 +26,6 @@ sealed class SpaceListAction : VectorViewModelAction {
|
|||||||
data class LeaveSpace(val spaceSummary: RoomSummary) : SpaceListAction()
|
data class LeaveSpace(val spaceSummary: RoomSummary) : SpaceListAction()
|
||||||
data class ToggleExpand(val spaceSummary: RoomSummary) : SpaceListAction()
|
data class ToggleExpand(val spaceSummary: RoomSummary) : SpaceListAction()
|
||||||
object AddSpace : SpaceListAction()
|
object AddSpace : SpaceListAction()
|
||||||
|
|
||||||
|
data class SelectLegacyGroup(val groupSummary: GroupSummary?) : SpaceListAction()
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ import im.vector.app.core.platform.VectorBaseFragment
|
|||||||
import im.vector.app.databinding.FragmentGroupListBinding
|
import im.vector.app.databinding.FragmentGroupListBinding
|
||||||
import im.vector.app.features.home.HomeActivitySharedAction
|
import im.vector.app.features.home.HomeActivitySharedAction
|
||||||
import im.vector.app.features.home.HomeSharedActionViewModel
|
import im.vector.app.features.home.HomeSharedActionViewModel
|
||||||
|
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -56,8 +57,9 @@ class SpaceListFragment @Inject constructor(
|
|||||||
viewModel.observeViewEvents {
|
viewModel.observeViewEvents {
|
||||||
when (it) {
|
when (it) {
|
||||||
is SpaceListViewEvents.OpenSpaceSummary -> sharedActionViewModel.post(HomeActivitySharedAction.OpenSpacePreview(it.id))
|
is SpaceListViewEvents.OpenSpaceSummary -> sharedActionViewModel.post(HomeActivitySharedAction.OpenSpacePreview(it.id))
|
||||||
is SpaceListViewEvents.OpenSpace -> sharedActionViewModel.post(HomeActivitySharedAction.OpenGroup)
|
is SpaceListViewEvents.OpenSpace -> sharedActionViewModel.post(HomeActivitySharedAction.OpenGroup(it.groupingMethodHasChanged))
|
||||||
is SpaceListViewEvents.AddSpace -> sharedActionViewModel.post(HomeActivitySharedAction.AddSpace)
|
is SpaceListViewEvents.AddSpace -> sharedActionViewModel.post(HomeActivitySharedAction.AddSpace)
|
||||||
|
is SpaceListViewEvents.OpenGroup -> sharedActionViewModel.post(HomeActivitySharedAction.OpenGroup(it.groupingMethodHasChanged))
|
||||||
}.exhaustive
|
}.exhaustive
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,4 +96,8 @@ class SpaceListFragment @Inject constructor(
|
|||||||
override fun onAddSpaceSelected() {
|
override fun onAddSpaceSelected() {
|
||||||
viewModel.handle(SpaceListAction.AddSpace)
|
viewModel.handle(SpaceListAction.AddSpace)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onGroupSelected(groupSummary: GroupSummary?) {
|
||||||
|
viewModel.handle(SpaceListAction.SelectLegacyGroup(groupSummary))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,8 @@ import im.vector.app.core.platform.VectorViewEvents
|
|||||||
* Transient events for group list screen
|
* Transient events for group list screen
|
||||||
*/
|
*/
|
||||||
sealed class SpaceListViewEvents : VectorViewEvents {
|
sealed class SpaceListViewEvents : VectorViewEvents {
|
||||||
object OpenSpace : SpaceListViewEvents()
|
data class OpenSpace(val groupingMethodHasChanged: Boolean) : SpaceListViewEvents()
|
||||||
data class OpenSpaceSummary(val id: String) : SpaceListViewEvents()
|
data class OpenSpaceSummary(val id: String) : SpaceListViewEvents()
|
||||||
object AddSpace : SpaceListViewEvents()
|
object AddSpace : SpaceListViewEvents()
|
||||||
|
data class OpenGroup(val groupingMethodHasChanged: Boolean) : SpaceListViewEvents()
|
||||||
}
|
}
|
||||||
|
@ -19,13 +19,18 @@ package im.vector.app.features.spaces
|
|||||||
import com.airbnb.mvrx.Async
|
import com.airbnb.mvrx.Async
|
||||||
import com.airbnb.mvrx.MvRxState
|
import com.airbnb.mvrx.MvRxState
|
||||||
import com.airbnb.mvrx.Uninitialized
|
import com.airbnb.mvrx.Uninitialized
|
||||||
|
import im.vector.app.RoomGroupingMethod
|
||||||
|
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount
|
import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount
|
||||||
|
import org.matrix.android.sdk.api.util.MatrixItem
|
||||||
|
|
||||||
data class SpaceListViewState(
|
data class SpaceListViewState(
|
||||||
|
val myMxItem : Async<MatrixItem.UserItem> = Uninitialized,
|
||||||
val asyncSpaces: Async<List<RoomSummary>> = Uninitialized,
|
val asyncSpaces: Async<List<RoomSummary>> = Uninitialized,
|
||||||
val selectedSpace: RoomSummary? = null,
|
val selectedGroupingMethod: RoomGroupingMethod = RoomGroupingMethod.BySpace(null),
|
||||||
val rootSpaces: List<RoomSummary>? = null,
|
val rootSpaces: List<RoomSummary>? = null,
|
||||||
|
val legacyGroups: List<GroupSummary>? = null,
|
||||||
val expandedStates: Map<String, Boolean> = emptyMap(),
|
val expandedStates: Map<String, Boolean> = emptyMap(),
|
||||||
val homeAggregateCount : RoomAggregateNotificationCount = RoomAggregateNotificationCount(0, 0)
|
val homeAggregateCount : RoomAggregateNotificationCount = RoomAggregateNotificationCount(0, 0)
|
||||||
) : MvRxState
|
) : MvRxState
|
||||||
|
@ -18,14 +18,17 @@ package im.vector.app.features.spaces
|
|||||||
|
|
||||||
import com.airbnb.epoxy.EpoxyController
|
import com.airbnb.epoxy.EpoxyController
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
import im.vector.app.RoomGroupingMethod
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.core.ui.list.genericButtonItem
|
|
||||||
import im.vector.app.core.ui.list.genericFooterItem
|
import im.vector.app.core.ui.list.genericFooterItem
|
||||||
import im.vector.app.core.ui.list.genericItemHeader
|
import im.vector.app.core.ui.list.genericItemHeader
|
||||||
import im.vector.app.core.utils.DebouncedClickListener
|
import im.vector.app.features.grouplist.groupSummaryItem
|
||||||
import im.vector.app.features.grouplist.homeSpaceSummaryItem
|
import im.vector.app.features.grouplist.homeSpaceSummaryItem
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
import im.vector.app.features.home.room.list.UnreadCounterBadgeView
|
import im.vector.app.features.home.room.list.UnreadCounterBadgeView
|
||||||
|
import im.vector.app.group
|
||||||
|
import im.vector.app.space
|
||||||
|
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
||||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount
|
import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount
|
||||||
@ -53,63 +56,101 @@ class SpaceSummaryController @Inject constructor(
|
|||||||
val nonNullViewState = viewState ?: return
|
val nonNullViewState = viewState ?: return
|
||||||
buildGroupModels(
|
buildGroupModels(
|
||||||
nonNullViewState.asyncSpaces(),
|
nonNullViewState.asyncSpaces(),
|
||||||
nonNullViewState.selectedSpace,
|
nonNullViewState.selectedGroupingMethod,
|
||||||
nonNullViewState.rootSpaces,
|
nonNullViewState.rootSpaces,
|
||||||
nonNullViewState.expandedStates,
|
nonNullViewState.expandedStates,
|
||||||
nonNullViewState.homeAggregateCount)
|
nonNullViewState.homeAggregateCount)
|
||||||
|
|
||||||
|
if (!nonNullViewState.legacyGroups.isNullOrEmpty()) {
|
||||||
|
genericFooterItem {
|
||||||
|
id("legacy_space")
|
||||||
|
text(" ")
|
||||||
|
}
|
||||||
|
|
||||||
|
genericItemHeader {
|
||||||
|
id("legacy_groups")
|
||||||
|
text(stringProvider.getString(R.string.groups_header))
|
||||||
|
}
|
||||||
|
|
||||||
|
// add home for communities
|
||||||
|
nonNullViewState.myMxItem.invoke()?.let { mxItem ->
|
||||||
|
groupSummaryItem {
|
||||||
|
avatarRenderer(avatarRenderer)
|
||||||
|
id("all_communities")
|
||||||
|
matrixItem(mxItem.copy(displayName = stringProvider.getString(R.string.group_all_communities)))
|
||||||
|
selected(nonNullViewState.selectedGroupingMethod is RoomGroupingMethod.ByLegacyGroup
|
||||||
|
&& nonNullViewState.selectedGroupingMethod.group() == null)
|
||||||
|
listener { callback?.onGroupSelected(null) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nonNullViewState.legacyGroups.forEach { groupSummary ->
|
||||||
|
groupSummaryItem {
|
||||||
|
avatarRenderer(avatarRenderer)
|
||||||
|
id(groupSummary.groupId)
|
||||||
|
matrixItem(groupSummary.toMatrixItem())
|
||||||
|
selected(nonNullViewState.selectedGroupingMethod is RoomGroupingMethod.ByLegacyGroup
|
||||||
|
&& nonNullViewState.selectedGroupingMethod.group()?.groupId == groupSummary.groupId)
|
||||||
|
listener { callback?.onGroupSelected(groupSummary) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildGroupModels(summaries: List<RoomSummary>?,
|
private fun buildGroupModels(summaries: List<RoomSummary>?,
|
||||||
selected: RoomSummary?,
|
selected: RoomGroupingMethod,
|
||||||
rootSpaces: List<RoomSummary>?,
|
rootSpaces: List<RoomSummary>?,
|
||||||
expandedStates: Map<String, Boolean>,
|
expandedStates: Map<String, Boolean>,
|
||||||
homeCount: RoomAggregateNotificationCount) {
|
homeCount: RoomAggregateNotificationCount) {
|
||||||
if (summaries.isNullOrEmpty()) {
|
if (summaries.isNullOrEmpty()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// show invites on top
|
|
||||||
|
|
||||||
summaries.filter { it.membership == Membership.INVITE }
|
|
||||||
.let { invites ->
|
|
||||||
if (invites.isNotEmpty()) {
|
|
||||||
genericItemHeader {
|
|
||||||
id("invites")
|
|
||||||
text(stringProvider.getString(R.string.spaces_invited_header))
|
|
||||||
}
|
|
||||||
invites.forEach {
|
|
||||||
spaceSummaryItem {
|
|
||||||
avatarRenderer(avatarRenderer)
|
|
||||||
id(it.roomId)
|
|
||||||
matrixItem(it.toMatrixItem())
|
|
||||||
selected(false)
|
|
||||||
listener { callback?.onSpaceInviteSelected(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
genericFooterItem {
|
|
||||||
id("invite_space")
|
|
||||||
text("")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
genericItemHeader {
|
genericItemHeader {
|
||||||
id("spaces")
|
id("spaces")
|
||||||
text(stringProvider.getString(R.string.spaces_header))
|
text(stringProvider.getString(R.string.spaces_header))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spaceBetaHeaderItem { id("beta_header") }
|
||||||
|
|
||||||
|
// show invites on top
|
||||||
|
|
||||||
|
summaries.filter { it.membership == Membership.INVITE }
|
||||||
|
.let { invites ->
|
||||||
|
if (invites.isNotEmpty()) {
|
||||||
|
// genericItemHeader {
|
||||||
|
// id("invites")
|
||||||
|
// text(stringProvider.getString(R.string.spaces_invited_header))
|
||||||
|
// }
|
||||||
|
invites.forEach {
|
||||||
|
spaceSummaryItem {
|
||||||
|
avatarRenderer(avatarRenderer)
|
||||||
|
id(it.roomId)
|
||||||
|
matrixItem(it.toMatrixItem())
|
||||||
|
countState(UnreadCounterBadgeView.State(1, true))
|
||||||
|
selected(false)
|
||||||
|
description(stringProvider.getString(R.string.you_are_invited))
|
||||||
|
listener { callback?.onSpaceInviteSelected(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
summaries.firstOrNull { it.roomId == ALL_COMMUNITIES_GROUP_ID }
|
summaries.firstOrNull { it.roomId == ALL_COMMUNITIES_GROUP_ID }
|
||||||
?.let {
|
?.let {
|
||||||
|
val isSelected = selected is RoomGroupingMethod.BySpace && selected.space() == null
|
||||||
homeSpaceSummaryItem {
|
homeSpaceSummaryItem {
|
||||||
id(it.roomId)
|
id(it.roomId)
|
||||||
selected(it.roomId == selected?.roomId)
|
selected(isSelected)
|
||||||
countState(UnreadCounterBadgeView.State(homeCount.totalCount, homeCount.isHighlight))
|
countState(UnreadCounterBadgeView.State(homeCount.totalCount, homeCount.isHighlight))
|
||||||
listener { callback?.onSpaceSelected(it) }
|
listener { callback?.onSpaceSelected(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rootSpaces
|
rootSpaces
|
||||||
|
?.sortedBy { it.displayName }
|
||||||
?.forEach { groupSummary ->
|
?.forEach { groupSummary ->
|
||||||
val isSelected = groupSummary.roomId == selected?.roomId
|
val isSelected = selected is RoomGroupingMethod.BySpace && groupSummary.roomId == selected.space()?.roomId
|
||||||
// does it have children?
|
// does it have children?
|
||||||
val subSpaces = groupSummary.children?.filter { childInfo ->
|
val subSpaces = groupSummary.children?.filter { childInfo ->
|
||||||
summaries.indexOfFirst { it.roomId == childInfo.childRoomId } != -1
|
summaries.indexOfFirst { it.roomId == childInfo.childRoomId } != -1
|
||||||
@ -139,7 +180,7 @@ class SpaceSummaryController @Inject constructor(
|
|||||||
// it's expanded
|
// it's expanded
|
||||||
subSpaces?.forEach { child ->
|
subSpaces?.forEach { child ->
|
||||||
summaries.firstOrNull { it.roomId == child.childRoomId }?.let { childSum ->
|
summaries.firstOrNull { it.roomId == child.childRoomId }?.let { childSum ->
|
||||||
val isChildSelected = childSum.roomId == selected?.roomId
|
val isChildSelected = selected is RoomGroupingMethod.BySpace && childSum.roomId == selected.space()?.roomId
|
||||||
spaceSummaryItem {
|
spaceSummaryItem {
|
||||||
avatarRenderer(avatarRenderer)
|
avatarRenderer(avatarRenderer)
|
||||||
id(child.childRoomId)
|
id(child.childRoomId)
|
||||||
@ -161,12 +202,9 @@ class SpaceSummaryController @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Temporary item to create a new Space (will move with final design)
|
// Temporary item to create a new Space (will move with final design)
|
||||||
|
spaceAddItem {
|
||||||
genericButtonItem {
|
|
||||||
id("create")
|
id("create")
|
||||||
text(stringProvider.getString(R.string.add_space))
|
listener { callback?.onAddSpaceSelected() }
|
||||||
iconRes(R.drawable.ic_add_black)
|
|
||||||
buttonClickAction(DebouncedClickListener({ callback?.onAddSpaceSelected() }))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,5 +214,7 @@ class SpaceSummaryController @Inject constructor(
|
|||||||
fun onSpaceSettings(spaceSummary: RoomSummary)
|
fun onSpaceSettings(spaceSummary: RoomSummary)
|
||||||
fun onToggleExpand(spaceSummary: RoomSummary)
|
fun onToggleExpand(spaceSummary: RoomSummary)
|
||||||
fun onAddSpaceSelected()
|
fun onAddSpaceSelected()
|
||||||
|
|
||||||
|
fun onGroupSelected(groupSummary: GroupSummary?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ import com.airbnb.epoxy.EpoxyModelClass
|
|||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
import im.vector.app.core.epoxy.VectorEpoxyHolder
|
||||||
import im.vector.app.core.epoxy.VectorEpoxyModel
|
import im.vector.app.core.epoxy.VectorEpoxyModel
|
||||||
|
import im.vector.app.core.extensions.setTextOrHide
|
||||||
import im.vector.app.core.platform.CheckableConstraintLayout
|
import im.vector.app.core.platform.CheckableConstraintLayout
|
||||||
import im.vector.app.core.utils.DebouncedClickListener
|
import im.vector.app.core.utils.DebouncedClickListener
|
||||||
import im.vector.app.features.home.AvatarRenderer
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
@ -46,6 +47,7 @@ abstract class SpaceSummaryItem : VectorEpoxyModel<SpaceSummaryItem.Holder>() {
|
|||||||
@EpoxyAttribute var hasChildren: Boolean = false
|
@EpoxyAttribute var hasChildren: Boolean = false
|
||||||
@EpoxyAttribute var indent: Int = 0
|
@EpoxyAttribute var indent: Int = 0
|
||||||
@EpoxyAttribute var countState : UnreadCounterBadgeView.State = UnreadCounterBadgeView.State(0, false)
|
@EpoxyAttribute var countState : UnreadCounterBadgeView.State = UnreadCounterBadgeView.State(0, false)
|
||||||
|
@EpoxyAttribute var description: String? = null
|
||||||
|
|
||||||
override fun bind(holder: Holder) {
|
override fun bind(holder: Holder) {
|
||||||
super.bind(holder)
|
super.bind(holder)
|
||||||
@ -62,6 +64,7 @@ abstract class SpaceSummaryItem : VectorEpoxyModel<SpaceSummaryItem.Holder>() {
|
|||||||
holder.moreView.isVisible = false
|
holder.moreView.isVisible = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
holder.secondLineText.setTextOrHide(description)
|
||||||
if (hasChildren) {
|
if (hasChildren) {
|
||||||
// holder.collapseIndicator.setOnClickListener(
|
// holder.collapseIndicator.setOnClickListener(
|
||||||
// DebouncedClickListener({ _ ->
|
// DebouncedClickListener({ _ ->
|
||||||
@ -104,6 +107,7 @@ abstract class SpaceSummaryItem : VectorEpoxyModel<SpaceSummaryItem.Holder>() {
|
|||||||
class Holder : VectorEpoxyHolder() {
|
class Holder : VectorEpoxyHolder() {
|
||||||
val avatarImageView by bind<ImageView>(R.id.groupAvatarImageView)
|
val avatarImageView by bind<ImageView>(R.id.groupAvatarImageView)
|
||||||
val groupNameView by bind<TextView>(R.id.groupNameView)
|
val groupNameView by bind<TextView>(R.id.groupNameView)
|
||||||
|
val secondLineText by bind<TextView>(R.id.groupDescView)
|
||||||
val rootView by bind<CheckableConstraintLayout>(R.id.itemGroupLayout)
|
val rootView by bind<CheckableConstraintLayout>(R.id.itemGroupLayout)
|
||||||
val moreView by bind<ImageView>(R.id.groupTmpLeave)
|
val moreView by bind<ImageView>(R.id.groupTmpLeave)
|
||||||
val collapseIndicator by bind<ImageView>(R.id.groupChildrenCollapse)
|
val collapseIndicator by bind<ImageView>(R.id.groupChildrenCollapse)
|
||||||
|
@ -18,16 +18,21 @@ package im.vector.app.features.spaces
|
|||||||
|
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.airbnb.mvrx.FragmentViewModelContext
|
import com.airbnb.mvrx.FragmentViewModelContext
|
||||||
|
import com.airbnb.mvrx.Loading
|
||||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||||
|
import com.airbnb.mvrx.Success
|
||||||
import com.airbnb.mvrx.ViewModelContext
|
import com.airbnb.mvrx.ViewModelContext
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedFactory
|
import dagger.assisted.AssistedFactory
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
import im.vector.app.AppStateHandler
|
import im.vector.app.AppStateHandler
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
|
import im.vector.app.RoomGroupingMethod
|
||||||
import im.vector.app.core.platform.VectorViewModel
|
import im.vector.app.core.platform.VectorViewModel
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.features.ui.UiStateRepository
|
import im.vector.app.features.ui.UiStateRepository
|
||||||
|
import im.vector.app.group
|
||||||
|
import im.vector.app.space
|
||||||
import io.reactivex.Observable
|
import io.reactivex.Observable
|
||||||
import io.reactivex.functions.BiFunction
|
import io.reactivex.functions.BiFunction
|
||||||
import io.reactivex.schedulers.Schedulers
|
import io.reactivex.schedulers.Schedulers
|
||||||
@ -36,10 +41,12 @@ import org.matrix.android.sdk.api.extensions.tryOrNull
|
|||||||
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
|
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
|
||||||
import org.matrix.android.sdk.api.query.QueryStringValue
|
import org.matrix.android.sdk.api.query.QueryStringValue
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
import org.matrix.android.sdk.api.session.group.groupSummaryQueryParams
|
||||||
import org.matrix.android.sdk.api.session.room.RoomSortOrder
|
import org.matrix.android.sdk.api.session.room.RoomSortOrder
|
||||||
import org.matrix.android.sdk.api.session.room.model.Membership
|
import org.matrix.android.sdk.api.session.room.model.Membership
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams
|
||||||
|
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||||
import org.matrix.android.sdk.rx.asObservable
|
import org.matrix.android.sdk.rx.asObservable
|
||||||
import org.matrix.android.sdk.rx.rx
|
import org.matrix.android.sdk.rx.rx
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
@ -67,23 +74,42 @@ class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: Sp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var currentGroupId = ""
|
// private var currentGroupingMethod : RoomGroupingMethod? = null
|
||||||
|
|
||||||
init {
|
init {
|
||||||
observeSpaceSummaries()
|
|
||||||
observeSelectionState()
|
session.getUserLive(session.myUserId).asObservable()
|
||||||
appStateHandler.selectedSpaceObservable
|
|
||||||
.subscribe {
|
.subscribe {
|
||||||
if (currentGroupId != it.orNull()?.roomId) {
|
setState {
|
||||||
setState {
|
copy(
|
||||||
copy(
|
myMxItem = it?.getOrNull()?.toMatrixItem()?.let { Success(it) } ?: Loading()
|
||||||
selectedSpace = it.orNull()
|
)
|
||||||
)
|
}
|
||||||
}
|
}.disposeOnClear()
|
||||||
|
|
||||||
|
observeSpaceSummaries()
|
||||||
|
// observeSelectionState()
|
||||||
|
appStateHandler.selectedRoomGroupingObservable
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.subscribe {
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
selectedGroupingMethod = it
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.disposeOnClear()
|
.disposeOnClear()
|
||||||
|
|
||||||
|
session.getGroupSummariesLive(groupSummaryQueryParams {})
|
||||||
|
.asObservable()
|
||||||
|
.subscribe {
|
||||||
|
setState {
|
||||||
|
copy(
|
||||||
|
legacyGroups = it
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}.disposeOnClear()
|
||||||
|
|
||||||
session.getPagedRoomSummariesLive(
|
session.getPagedRoomSummariesLive(
|
||||||
roomSummaryQueryParams {
|
roomSummaryQueryParams {
|
||||||
this.memberships = listOf(Membership.JOIN)
|
this.memberships = listOf(Membership.JOIN)
|
||||||
@ -107,23 +133,23 @@ class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: Sp
|
|||||||
}.disposeOnClear()
|
}.disposeOnClear()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun observeSelectionState() {
|
// private fun observeSelectionState() {
|
||||||
selectSubscribe(SpaceListViewState::selectedSpace) { spaceSummary ->
|
// selectSubscribe(SpaceListViewState::selectedSpace) { spaceSummary ->
|
||||||
if (spaceSummary != null) {
|
// if (spaceSummary != null) {
|
||||||
// We only want to open group if the updated selectedGroup is a different one.
|
// // We only want to open group if the updated selectedGroup is a different one.
|
||||||
if (currentGroupId != spaceSummary.roomId) {
|
// if (currentGroupId != spaceSummary.roomId) {
|
||||||
currentGroupId = spaceSummary.roomId
|
// currentGroupId = spaceSummary.roomId
|
||||||
_viewEvents.post(SpaceListViewEvents.OpenSpace)
|
// _viewEvents.post(SpaceListViewEvents.OpenSpace)
|
||||||
}
|
// }
|
||||||
appStateHandler.setCurrentSpace(spaceSummary)
|
// appStateHandler.setCurrentSpace(spaceSummary.roomId)
|
||||||
} else {
|
// } else {
|
||||||
// If selected group is null we force to default. It can happens when leaving the selected group.
|
// // If selected group is null we force to default. It can happens when leaving the selected group.
|
||||||
setState {
|
// setState {
|
||||||
copy(selectedSpace = this.asyncSpaces()?.find { it.roomId == ALL_COMMUNITIES_GROUP_ID })
|
// copy(selectedSpace = this.asyncSpaces()?.find { it.roomId == ALL_COMMUNITIES_GROUP_ID })
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
override fun handle(action: SpaceListAction) {
|
override fun handle(action: SpaceListAction) {
|
||||||
when (action) {
|
when (action) {
|
||||||
@ -132,15 +158,31 @@ class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: Sp
|
|||||||
SpaceListAction.AddSpace -> handleAddSpace()
|
SpaceListAction.AddSpace -> handleAddSpace()
|
||||||
is SpaceListAction.ToggleExpand -> handleToggleExpand(action)
|
is SpaceListAction.ToggleExpand -> handleToggleExpand(action)
|
||||||
is SpaceListAction.OpenSpaceInvite -> handleSelectSpaceInvite(action)
|
is SpaceListAction.OpenSpaceInvite -> handleSelectSpaceInvite(action)
|
||||||
|
is SpaceListAction.SelectLegacyGroup -> handleSelectGroup(action)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PRIVATE METHODS *****************************************************************************
|
// PRIVATE METHODS *****************************************************************************
|
||||||
|
|
||||||
private fun handleSelectSpace(action: SpaceListAction.SelectSpace) = withState { state ->
|
private fun handleSelectSpace(action: SpaceListAction.SelectSpace) = withState { state ->
|
||||||
if (state.selectedSpace?.roomId != action.spaceSummary.roomId) {
|
val groupingMethod = state.selectedGroupingMethod
|
||||||
setState { copy(selectedSpace = action.spaceSummary) }
|
if (groupingMethod is RoomGroupingMethod.ByLegacyGroup || groupingMethod.space()?.roomId != action.spaceSummary.roomId) {
|
||||||
uiStateRepository.storeSelectedSpace(action.spaceSummary.roomId, session.sessionId)
|
setState { copy(selectedGroupingMethod = RoomGroupingMethod.BySpace(action.spaceSummary)) }
|
||||||
|
if (action.spaceSummary.roomId == ALL_COMMUNITIES_GROUP_ID) {
|
||||||
|
appStateHandler.setCurrentSpace(null)
|
||||||
|
} else {
|
||||||
|
appStateHandler.setCurrentSpace(action.spaceSummary.roomId)
|
||||||
|
}
|
||||||
|
_viewEvents.post(SpaceListViewEvents.OpenSpace(groupingMethod is RoomGroupingMethod.ByLegacyGroup))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleSelectGroup(action: SpaceListAction.SelectLegacyGroup) = withState { state ->
|
||||||
|
val groupingMethod = state.selectedGroupingMethod
|
||||||
|
if (groupingMethod is RoomGroupingMethod.BySpace || groupingMethod.group()?.groupId != action.groupSummary?.groupId) {
|
||||||
|
setState { copy(selectedGroupingMethod = RoomGroupingMethod.ByLegacyGroup(action.groupSummary)) }
|
||||||
|
appStateHandler.setCurrentGroup(action.groupSummary?.groupId)
|
||||||
|
_viewEvents.post(SpaceListViewEvents.OpenGroup(groupingMethod is RoomGroupingMethod.BySpace))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,15 +241,14 @@ class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: Sp
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
.execute { async ->
|
.execute { async ->
|
||||||
val currentSelectedGroupId = selectedSpace?.roomId
|
// val currentSelectedGroupId = selectedGroupingMethod?.roomId
|
||||||
val newSelectedGroup = if (currentSelectedGroupId != null) {
|
// val newSelectedGroup = if (currentSelectedGroupId != null) {
|
||||||
async()?.find { it.roomId == currentSelectedGroupId }
|
// async()?.find { it.roomId == currentSelectedGroupId }
|
||||||
} else {
|
// } else {
|
||||||
async()?.firstOrNull()
|
// async()?.firstOrNull()
|
||||||
}
|
// }
|
||||||
copy(
|
copy(
|
||||||
asyncSpaces = async,
|
asyncSpaces = async,
|
||||||
selectedSpace = newSelectedGroup,
|
|
||||||
rootSpaces = session.spaceService().getRootSpaceSummaries()
|
rootSpaces = session.spaceService().getRootSpaceSummaries()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,8 @@ import android.content.SharedPreferences
|
|||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import im.vector.app.features.home.RoomListDisplayMode
|
import im.vector.app.features.home.RoomListDisplayMode
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -59,16 +61,38 @@ class SharedPreferencesUiStateRepository @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun storeSelectedSpace(spaceId: String?, sessionId: String) {
|
override fun storeSelectedSpace(spaceId: String?, sessionId: Session?) {
|
||||||
sharedPreferences.edit {
|
Timber.w("VAL: storeSelectedSpace $spaceId")
|
||||||
|
sharedPreferences.edit(true) {
|
||||||
putString("$KEY_SELECTED_SPACE@$sessionId", spaceId)
|
putString("$KEY_SELECTED_SPACE@$sessionId", spaceId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun storeSelectedGroup(groupId: String?, sessionId: Session?) {
|
||||||
|
Timber.w("VAL: storeSelectedSpace $groupId")
|
||||||
|
sharedPreferences.edit(true) {
|
||||||
|
putString("$KEY_SELECTED_GROUP@$sessionId", groupId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun storeGroupingMethod(isSpace: Boolean, sessionId: Session?) {
|
||||||
|
sharedPreferences.edit(true) {
|
||||||
|
putBoolean("$KEY_SELECTED_METHOD@$sessionId", isSpace)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSelectedGroup(sessionId: String): String? {
|
||||||
|
return sharedPreferences.getString("$KEY_SELECTED_GROUP@$sessionId", null)
|
||||||
|
}
|
||||||
|
|
||||||
override fun getSelectedSpace(sessionId: String): String? {
|
override fun getSelectedSpace(sessionId: String): String? {
|
||||||
return sharedPreferences.getString("$KEY_SELECTED_SPACE@$sessionId", null)
|
return sharedPreferences.getString("$KEY_SELECTED_SPACE@$sessionId", null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun isGroupingMethodSpace(sessionId: String): Boolean {
|
||||||
|
return sharedPreferences.getBoolean("$KEY_SELECTED_METHOD@$sessionId", true)
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val KEY_DISPLAY_MODE = "UI_STATE_DISPLAY_MODE"
|
private const val KEY_DISPLAY_MODE = "UI_STATE_DISPLAY_MODE"
|
||||||
private const val VALUE_DISPLAY_MODE_CATCHUP = 0
|
private const val VALUE_DISPLAY_MODE_CATCHUP = 0
|
||||||
@ -76,5 +100,7 @@ class SharedPreferencesUiStateRepository @Inject constructor(
|
|||||||
private const val VALUE_DISPLAY_MODE_ROOMS = 2
|
private const val VALUE_DISPLAY_MODE_ROOMS = 2
|
||||||
|
|
||||||
private const val KEY_SELECTED_SPACE = "UI_STATE_SELECTED_SPACE"
|
private const val KEY_SELECTED_SPACE = "UI_STATE_SELECTED_SPACE"
|
||||||
|
private const val KEY_SELECTED_GROUP = "UI_STATE_SELECTED_GROUP"
|
||||||
|
private const val KEY_SELECTED_METHOD = "UI_STATE_SELECTED_METHOD"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package im.vector.app.features.ui
|
package im.vector.app.features.ui
|
||||||
|
|
||||||
import im.vector.app.features.home.RoomListDisplayMode
|
import im.vector.app.features.home.RoomListDisplayMode
|
||||||
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This interface is used to persist UI state across application restart
|
* This interface is used to persist UI state across application restart
|
||||||
@ -32,7 +33,12 @@ interface UiStateRepository {
|
|||||||
|
|
||||||
fun storeDisplayMode(displayMode: RoomListDisplayMode)
|
fun storeDisplayMode(displayMode: RoomListDisplayMode)
|
||||||
|
|
||||||
fun storeSelectedSpace(spaceId: String?, sessionId: String)
|
fun storeSelectedSpace(spaceId: String?, sessionId: Session?)
|
||||||
|
fun storeSelectedGroup(groupId: String?, sessionId: Session?)
|
||||||
|
|
||||||
|
fun storeGroupingMethod(isSpace: Boolean, sessionId: Session?)
|
||||||
|
|
||||||
fun getSelectedSpace(sessionId: String): String?
|
fun getSelectedSpace(sessionId: String): String?
|
||||||
|
fun getSelectedGroup(sessionId: String): String?
|
||||||
|
fun isGroupingMethodSpace(sessionId: String): Boolean
|
||||||
}
|
}
|
||||||
|
11
vector/src/main/res/drawable/rounded_rect_stroke_8.xml
Normal file
11
vector/src/main/res/drawable/rounded_rect_stroke_8.xml
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
|
||||||
|
<size android:width="40dp" android:height="40dp"/>
|
||||||
|
|
||||||
|
<stroke android:width="1dp" android:color="?riotx_list_bottom_sheet_divider_color" />
|
||||||
|
|
||||||
|
<corners android:radius="8dp" />
|
||||||
|
|
||||||
|
</shape>
|
@ -39,20 +39,20 @@
|
|||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="4dp"
|
android:layout_marginStart="4dp"
|
||||||
android:layout_marginEnd="4dp"
|
android:layout_marginEnd="4dp"
|
||||||
android:paddingStart="4dp"
|
|
||||||
android:paddingEnd="4dp"
|
|
||||||
android:gravity="center"
|
android:gravity="center"
|
||||||
android:minWidth="16dp"
|
android:minWidth="16dp"
|
||||||
android:minHeight="16dp"
|
android:minHeight="16dp"
|
||||||
|
android:paddingStart="4dp"
|
||||||
|
android:paddingEnd="4dp"
|
||||||
android:textColor="@android:color/white"
|
android:textColor="@android:color/white"
|
||||||
android:textSize="10sp"
|
android:textSize="10sp"
|
||||||
|
android:visibility="gone"
|
||||||
app:layout_constraintCircle="@+id/groupAvatarImageView"
|
app:layout_constraintCircle="@+id/groupAvatarImageView"
|
||||||
app:layout_constraintCircleAngle="45"
|
app:layout_constraintCircleAngle="45"
|
||||||
app:layout_constraintCircleRadius="24dp"
|
app:layout_constraintCircleRadius="24dp"
|
||||||
android:visibility="gone"
|
|
||||||
tools:visibility="visible"
|
|
||||||
tools:background="@drawable/bg_unread_highlight"
|
tools:background="@drawable/bg_unread_highlight"
|
||||||
tools:text="147" />
|
tools:text="147"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
@ -66,10 +66,30 @@
|
|||||||
android:textColor="?riotx_text_primary"
|
android:textColor="?riotx_text_primary"
|
||||||
android:textSize="15sp"
|
android:textSize="15sp"
|
||||||
android:textStyle="bold"
|
android:textStyle="bold"
|
||||||
app:layout_constraintBottom_toTopOf="@+id/groupBottomSeparator"
|
app:layout_constraintBottom_toTopOf="@+id/groupDescView"
|
||||||
app:layout_constraintEnd_toStartOf="@+id/groupChildrenCollapse"
|
app:layout_constraintEnd_toStartOf="@+id/groupChildrenCollapse"
|
||||||
app:layout_constraintStart_toEndOf="@+id/groupAvatarImageView"
|
app:layout_constraintStart_toEndOf="@+id/groupAvatarImageView"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_chainStyle="packed"
|
||||||
|
tools:text="@tools:sample/lorem/random" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/groupDescView"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||||
|
android:layout_marginEnd="@dimen/layout_horizontal_margin"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:textColor="?riotx_text_secondary"
|
||||||
|
android:textSize="15sp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/groupBottomSeparator"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/groupChildrenCollapse"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/groupAvatarImageView"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/groupNameView"
|
||||||
|
app:layout_constraintVertical_chainStyle="packed"
|
||||||
tools:text="@tools:sample/lorem/random" />
|
tools:text="@tools:sample/lorem/random" />
|
||||||
|
|
||||||
|
|
||||||
|
55
vector/src/main/res/layout/item_space_add.xml
Normal file
55
vector/src/main/res/layout/item_space_add.xml
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<im.vector.app.core.platform.CheckableConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/itemGroupLayout"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="65dp"
|
||||||
|
android:background="@drawable/bg_space_item"
|
||||||
|
android:clickable="true"
|
||||||
|
android:focusable="true"
|
||||||
|
android:foreground="?attr/selectableItemBackground">
|
||||||
|
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/groupAvatarImageView"
|
||||||
|
android:layout_width="42dp"
|
||||||
|
android:layout_height="42dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||||
|
android:background="@drawable/rounded_rect_shape_8"
|
||||||
|
android:backgroundTint="?colorPrimary"
|
||||||
|
android:contentDescription="@string/avatar"
|
||||||
|
android:duplicateParentState="true"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:padding="10dp"
|
||||||
|
android:src="@drawable/ic_fab_add"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/groupNameView"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="@dimen/layout_horizontal_margin"
|
||||||
|
android:layout_marginEnd="@dimen/layout_horizontal_margin"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="@string/add_space"
|
||||||
|
android:textColor="?colorPrimary"
|
||||||
|
android:textSize="15sp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/groupAvatarImageView"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<!-- <View-->
|
||||||
|
<!-- android:id="@+id/groupBottomSeparator"-->
|
||||||
|
<!-- android:layout_width="0dp"-->
|
||||||
|
<!-- android:layout_height="1dp"-->
|
||||||
|
<!-- android:background="?riotx_header_panel_border_mobile"-->
|
||||||
|
<!-- app:layout_constraintBottom_toBottomOf="parent"-->
|
||||||
|
<!-- app:layout_constraintEnd_toEndOf="parent"-->
|
||||||
|
<!-- app:layout_constraintStart_toStartOf="parent" />-->
|
||||||
|
|
||||||
|
</im.vector.app.core.platform.CheckableConstraintLayout>
|
47
vector/src/main/res/layout/item_space_beta_header.xml
Normal file
47
vector/src/main/res/layout/item_space_beta_header.xml
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="@drawable/rounded_rect_stroke_8"
|
||||||
|
android:padding="8dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:src="@drawable/ic_beta_pill" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="@string/spaces_beta_welcome_to_spaces"
|
||||||
|
android:textColor="?riotx_text_primary"
|
||||||
|
android:textSize="15sp"
|
||||||
|
android:textStyle="bold" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:text="@string/spaces_beta_welcome_to_spaces_desc"
|
||||||
|
android:textColor="?riotx_text_secondary"
|
||||||
|
android:textSize="15sp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</FrameLayout>
|
||||||
|
|
||||||
|
|
||||||
|
</FrameLayout>
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
<ProgressBar
|
<ProgressBar
|
||||||
android:id="@+id/progressBar"
|
android:id="@+id/progressBar"
|
||||||
|
style="?progressBarStyle"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center" />
|
android:layout_gravity="center" />
|
||||||
|
@ -3337,4 +3337,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<string name="space_add_existing_rooms">Add existing rooms and space</string>
|
<string name="space_add_existing_rooms">Add existing rooms and space</string>
|
||||||
|
<string name="spaces_beta_welcome_to_spaces">Welcome to Spaces!</string>
|
||||||
|
<string name="spaces_beta_welcome_to_spaces_desc">Spaces are ways to group rooms and people for work, fun or just yourself.</string>
|
||||||
|
<string name="you_are_invited">You are invited</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user