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.LifecycleObserver
|
||||
import androidx.lifecycle.OnLifecycleEvent
|
||||
import arrow.core.Option
|
||||
import im.vector.app.core.di.ActiveSessionHolder
|
||||
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 io.reactivex.disposables.CompositeDisposable
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
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.session.Session
|
||||
import org.matrix.android.sdk.api.session.group.model.GroupSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
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.
|
||||
* It requires to be added to ProcessLifecycleOwner.get().lifecycle
|
||||
|
@ -42,48 +51,83 @@ import javax.inject.Singleton
|
|||
class AppStateHandler @Inject constructor(
|
||||
sessionDataSource: ActiveSessionDataSource,
|
||||
private val uiStateRepository: UiStateRepository,
|
||||
private val activeSessionHolder: ActiveSessionHolder
|
||||
private val activeSessionHolder: ActiveSessionHolder,
|
||||
vectorPreferences: VectorPreferences
|
||||
) : LifecycleObserver {
|
||||
|
||||
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?) {
|
||||
if (space == selectedSpaceDataSource.currentValue?.orNull()) return
|
||||
selectedSpaceDataSource.post(space?.let { Option.just(it) } ?: Option.empty())
|
||||
if (space != null && space.roomId != ALL_COMMUNITIES_GROUP_ID) {
|
||||
fun getCurrentRoomGroupingMethod(): RoomGroupingMethod = selectedSpaceDataSource.currentValue ?: RoomGroupingMethod.BySpace(null)
|
||||
|
||||
fun setCurrentSpace(spaceId: String?, session: Session? = null) {
|
||||
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 {
|
||||
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 {
|
||||
// restore current space from ui state
|
||||
sessionDataSource.currentValue?.orNull()?.let { session ->
|
||||
uiStateRepository.getSelectedSpace(session.sessionId)?.let { selectedSpaceId ->
|
||||
session.getRoomSummary(selectedSpaceId)?.let {
|
||||
setCurrentSpace(it)
|
||||
}
|
||||
}
|
||||
|
||||
sessionDataSource.observe()
|
||||
.distinctUntilChanged()
|
||||
.subscribe {
|
||||
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? {
|
||||
return selectedSpaceDataSource.currentValue?.orNull()?.roomId?.takeIf {
|
||||
MatrixPatterns.isRoomId(it)
|
||||
}
|
||||
return (selectedSpaceDataSource.currentValue as? RoomGroupingMethod.BySpace)?.spaceSummary?.roomId
|
||||
}
|
||||
|
||||
fun safeActiveSpace(): RoomSummary? {
|
||||
return selectedSpaceDataSource.currentValue?.orNull()?.takeIf {
|
||||
MatrixPatterns.isRoomId(it.roomId)
|
||||
}
|
||||
fun safeActiveGroupId(): String? {
|
||||
return (selectedSpaceDataSource.currentValue as? RoomGroupingMethod.ByLegacyGroup)?.groupSummary?.groupId
|
||||
}
|
||||
|
||||
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
|
||||
|
@ -93,5 +137,19 @@ class AppStateHandler @Inject constructor(
|
|||
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
|
||||
fun entersBackground() {
|
||||
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.discovery.DiscoverySettingsFragment
|
||||
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.HomeDrawerFragment
|
||||
import im.vector.app.features.home.LoadingFragment
|
||||
|
@ -150,11 +149,6 @@ interface FragmentModule {
|
|||
@FragmentKey(LocalePickerFragment::class)
|
||||
fun bindLocalePickerFragment(fragment: LocalePickerFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@FragmentKey(GroupListFragment::class)
|
||||
fun bindGroupListFragment(fragment: GroupListFragment): Fragment
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@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.crypto.keysrequest.KeyRequestHandler
|
||||
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.CurrentSpaceSuggestedRoomListDataSource
|
||||
import im.vector.app.features.home.room.detail.RoomDetailPendingActionStore
|
||||
|
@ -115,8 +114,6 @@ interface VectorComponent {
|
|||
|
||||
fun errorFormatter(): ErrorFormatter
|
||||
|
||||
fun selectedGroupStore(): SelectedGroupDataSource
|
||||
|
||||
fun appStateHandler(): AppStateHandler
|
||||
|
||||
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 com.airbnb.mvrx.MvRx
|
||||
import com.airbnb.mvrx.viewModel
|
||||
import im.vector.app.AppStateHandler
|
||||
import im.vector.app.R
|
||||
import im.vector.app.core.di.ActiveSessionHolder
|
||||
import im.vector.app.core.di.ScreenComponent
|
||||
|
@ -108,6 +109,7 @@ class HomeActivity :
|
|||
@Inject lateinit var permalinkHandler: PermalinkHandler
|
||||
@Inject lateinit var avatarRenderer: AvatarRenderer
|
||||
@Inject lateinit var initSyncStepFormatter: InitSyncStepFormatter
|
||||
@Inject lateinit var appStateHandler: AppStateHandler
|
||||
|
||||
private val createSpaceResultLauncher = registerStartForActivityResult { activityResult ->
|
||||
if (activityResult.resultCode == Activity.RESULT_OK) {
|
||||
|
@ -152,10 +154,15 @@ class HomeActivity :
|
|||
sharedActionViewModel = viewModelProvider.get(HomeSharedActionViewModel::class.java)
|
||||
views.drawerLayout.addDrawerListener(drawerListener)
|
||||
if (isFirstCreation()) {
|
||||
replaceFragment(R.id.homeDetailFragmentContainer, LoadingFragment::class.java)
|
||||
replaceFragment(R.id.homeDetailFragmentContainer, HomeDetailFragment::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
|
||||
.observe()
|
||||
.subscribe { sharedAction ->
|
||||
|
@ -164,13 +171,17 @@ class HomeActivity :
|
|||
is HomeActivitySharedAction.CloseDrawer -> views.drawerLayout.closeDrawer(GravityCompat.START)
|
||||
is HomeActivitySharedAction.OpenGroup -> {
|
||||
views.drawerLayout.closeDrawer(GravityCompat.START)
|
||||
|
||||
// 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
|
||||
// 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 -> {
|
||||
startActivity(SpacePreviewActivity.newIntent(this, sharedAction.spaceId))
|
||||
|
|
|
@ -24,7 +24,7 @@ import im.vector.app.core.platform.VectorSharedAction
|
|||
sealed class HomeActivitySharedAction : VectorSharedAction {
|
||||
object OpenDrawer : HomeActivitySharedAction()
|
||||
object CloseDrawer : HomeActivitySharedAction()
|
||||
object OpenGroup : HomeActivitySharedAction()
|
||||
data class OpenGroup(val clearFragment: Boolean) : HomeActivitySharedAction()
|
||||
object AddSpace : HomeActivitySharedAction()
|
||||
data class OpenSpacePreview(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.google.android.material.badge.BadgeDrawable
|
||||
import im.vector.app.R
|
||||
import im.vector.app.RoomGroupingMethod
|
||||
import im.vector.app.core.extensions.commitTransaction
|
||||
import im.vector.app.core.extensions.toMvRxBundle
|
||||
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.settings.VectorPreferences
|
||||
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.workers.signout.BannerState
|
||||
import im.vector.app.features.workers.signout.ServerBackupStatusViewModel
|
||||
|
@ -125,15 +125,14 @@ class HomeDetailFragment @Inject constructor(
|
|||
views.bottomNavigationView.selectedItemId = it.displayMode.toMenuId()
|
||||
}
|
||||
|
||||
viewModel.selectSubscribe(this, HomeDetailViewState::groupSummary) { groupSummary ->
|
||||
if (!vectorPreferences.labSpaces()) {
|
||||
onGroupChange(groupSummary.orNull())
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.selectSubscribe(this, HomeDetailViewState::spaceSummary) { spaceSummary ->
|
||||
if (vectorPreferences.labSpaces()) {
|
||||
onSpaceChange(spaceSummary.orNull())
|
||||
viewModel.selectSubscribe(this, HomeDetailViewState::roomGroupingMethod) { roomGroupingMethod ->
|
||||
when (roomGroupingMethod) {
|
||||
is RoomGroupingMethod.ByLegacyGroup -> {
|
||||
onGroupChange(roomGroupingMethod.groupSummary)
|
||||
}
|
||||
is RoomGroupingMethod.BySpace -> {
|
||||
onSpaceChange(roomGroupingMethod.spaceSummary)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -257,8 +256,7 @@ class HomeDetailFragment @Inject constructor(
|
|||
}
|
||||
|
||||
private fun onGroupChange(groupSummary: GroupSummary?) {
|
||||
groupSummary ?: return
|
||||
if (groupSummary.groupId == ALL_COMMUNITIES_GROUP_ID) {
|
||||
if (groupSummary == null) {
|
||||
views.groupToolbarSpaceTitleView.isVisible = false
|
||||
} else {
|
||||
views.groupToolbarSpaceTitleView.isVisible = true
|
||||
|
@ -267,8 +265,7 @@ class HomeDetailFragment @Inject constructor(
|
|||
}
|
||||
|
||||
private fun onSpaceChange(spaceSummary: RoomSummary?) {
|
||||
spaceSummary ?: return
|
||||
if (spaceSummary.roomId == ALL_COMMUNITIES_GROUP_ID) {
|
||||
if (spaceSummary == null) {
|
||||
views.groupToolbarSpaceTitleView.isVisible = false
|
||||
} else {
|
||||
views.groupToolbarSpaceTitleView.isVisible = true
|
||||
|
@ -310,11 +307,14 @@ class HomeDetailFragment @Inject constructor(
|
|||
|
||||
views.homeToolbarContent.debouncedClicks {
|
||||
withState(viewModel) {
|
||||
if (vectorPreferences.labSpaces()) {
|
||||
val currentSpace = it.spaceSummary.orNull()
|
||||
?.takeIf { it.roomId != ALL_COMMUNITIES_GROUP_ID }
|
||||
if (vectorPreferences.labSpaces() && currentSpace != null) {
|
||||
sharedActionViewModel.post(HomeActivitySharedAction.ShowSpaceSettings(currentSpace.roomId))
|
||||
when (it.roomGroupingMethod) {
|
||||
is RoomGroupingMethod.ByLegacyGroup -> {
|
||||
// nothing do far
|
||||
}
|
||||
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.AssistedInject
|
||||
import im.vector.app.AppStateHandler
|
||||
import im.vector.app.RoomGroupingMethod
|
||||
import im.vector.app.core.di.HasScreenInjector
|
||||
import im.vector.app.core.platform.EmptyViewEvents
|
||||
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 io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.matrix.android.sdk.api.query.ActiveSpaceFilter
|
||||
|
@ -51,9 +51,7 @@ import java.util.concurrent.TimeUnit
|
|||
class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: HomeDetailViewState,
|
||||
private val session: Session,
|
||||
private val uiStateRepository: UiStateRepository,
|
||||
private val selectedGroupStore: SelectedGroupDataSource,
|
||||
private val appStateHandler: AppStateHandler,
|
||||
private val stringProvider: StringProvider)
|
||||
private val appStateHandler: AppStateHandler)
|
||||
: VectorViewModel<HomeDetailViewState, HomeDetailAction, EmptyViewEvents>(initialState) {
|
||||
|
||||
@AssistedFactory
|
||||
|
@ -79,8 +77,7 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho
|
|||
|
||||
init {
|
||||
observeSyncState()
|
||||
observeSelectedGroupStore()
|
||||
observeSelectedSpaceStore()
|
||||
observeRoomGroupingMethod()
|
||||
observeRoomSummaries()
|
||||
|
||||
session.rx().liveUser(session.myUserId).execute {
|
||||
|
@ -138,29 +135,22 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho
|
|||
.disposeOnClear()
|
||||
}
|
||||
|
||||
private fun observeSelectedGroupStore() {
|
||||
selectedGroupStore
|
||||
.observe()
|
||||
private fun observeRoomGroupingMethod() {
|
||||
appStateHandler.selectedRoomGroupingObservable
|
||||
.subscribe {
|
||||
setState {
|
||||
copy(groupSummary = it)
|
||||
}
|
||||
}
|
||||
.disposeOnClear()
|
||||
}
|
||||
|
||||
private fun observeSelectedSpaceStore() {
|
||||
appStateHandler.selectedSpaceObservable
|
||||
.subscribe {
|
||||
setState {
|
||||
copy(spaceSummary = it)
|
||||
}
|
||||
setState {
|
||||
copy(
|
||||
roomGroupingMethod = it
|
||||
)
|
||||
}
|
||||
}
|
||||
.disposeOnClear()
|
||||
}
|
||||
|
||||
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(
|
||||
roomSummaryQueryParams {
|
||||
memberships = Membership.activeMemberships()
|
||||
|
@ -168,50 +158,55 @@ class HomeDetailViewModel @AssistedInject constructor(@Assisted initialState: Ho
|
|||
sortOrder = RoomSortOrder.NONE
|
||||
).asObservable()
|
||||
}
|
||||
|
||||
// .asObservable()
|
||||
.observeOn(Schedulers.computation())
|
||||
.throttleFirst(300, TimeUnit.MILLISECONDS)
|
||||
.subscribe {
|
||||
val activeSpace = appStateHandler.safeActiveSpaceId()
|
||||
val dmInvites = session.getRoomSummaries(
|
||||
roomSummaryQueryParams {
|
||||
memberships = listOf(Membership.INVITE)
|
||||
roomCategoryFilter = RoomCategoryFilter.ONLY_DM
|
||||
}
|
||||
).size
|
||||
when (val groupingMethod = appStateHandler.getCurrentRoomGroupingMethod()) {
|
||||
is RoomGroupingMethod.ByLegacyGroup -> {
|
||||
// TODO!!
|
||||
}
|
||||
is RoomGroupingMethod.BySpace -> {
|
||||
val dmInvites = session.getRoomSummaries(
|
||||
roomSummaryQueryParams {
|
||||
memberships = listOf(Membership.INVITE)
|
||||
roomCategoryFilter = RoomCategoryFilter.ONLY_DM
|
||||
}
|
||||
).size
|
||||
|
||||
val roomsInvite = session.getRoomSummaries(
|
||||
roomSummaryQueryParams {
|
||||
memberships = listOf(Membership.INVITE)
|
||||
roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
}
|
||||
).size
|
||||
val roomsInvite = session.getRoomSummaries(
|
||||
roomSummaryQueryParams {
|
||||
memberships = listOf(Membership.INVITE)
|
||||
roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
}
|
||||
).size
|
||||
|
||||
val dmRooms = session.getNotificationCountForRooms(
|
||||
roomSummaryQueryParams {
|
||||
memberships = listOf(Membership.JOIN)
|
||||
roomCategoryFilter = RoomCategoryFilter.ONLY_DM
|
||||
}
|
||||
)
|
||||
val dmRooms = session.getNotificationCountForRooms(
|
||||
roomSummaryQueryParams {
|
||||
memberships = listOf(Membership.JOIN)
|
||||
roomCategoryFilter = RoomCategoryFilter.ONLY_DM
|
||||
}
|
||||
)
|
||||
|
||||
val otherRooms = session.getNotificationCountForRooms(
|
||||
roomSummaryQueryParams {
|
||||
memberships = listOf(Membership.JOIN)
|
||||
roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
activeSpaceId = ActiveSpaceFilter.ActiveSpace(activeSpace)
|
||||
}
|
||||
)
|
||||
val otherRooms = session.getNotificationCountForRooms(
|
||||
roomSummaryQueryParams {
|
||||
memberships = listOf(Membership.JOIN)
|
||||
roomCategoryFilter = RoomCategoryFilter.ONLY_ROOMS
|
||||
activeSpaceId = ActiveSpaceFilter.ActiveSpace(groupingMethod.spaceSummary?.roomId)
|
||||
}
|
||||
)
|
||||
|
||||
setState {
|
||||
copy(
|
||||
notificationCountCatchup = dmRooms.totalCount + otherRooms.totalCount + roomsInvite + dmInvites,
|
||||
notificationHighlightCatchup = dmRooms.isHighlight || otherRooms.isHighlight,
|
||||
notificationCountPeople = dmRooms.totalCount + dmInvites,
|
||||
notificationHighlightPeople = dmRooms.isHighlight || dmInvites > 0,
|
||||
notificationCountRooms = otherRooms.totalCount + roomsInvite,
|
||||
notificationHighlightRooms = otherRooms.isHighlight || roomsInvite > 0,
|
||||
hasUnreadMessages = dmRooms.totalCount + otherRooms.totalCount > 0
|
||||
)
|
||||
setState {
|
||||
copy(
|
||||
notificationCountCatchup = dmRooms.totalCount + otherRooms.totalCount + roomsInvite + dmInvites,
|
||||
notificationHighlightCatchup = dmRooms.isHighlight || otherRooms.isHighlight,
|
||||
notificationCountPeople = dmRooms.totalCount + dmInvites,
|
||||
notificationHighlightPeople = dmRooms.isHighlight || dmInvites > 0,
|
||||
notificationCountRooms = otherRooms.totalCount + roomsInvite,
|
||||
notificationHighlightRooms = otherRooms.isHighlight || roomsInvite > 0,
|
||||
hasUnreadMessages = dmRooms.totalCount + otherRooms.totalCount > 0
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.disposeOnClear()
|
||||
|
|
|
@ -16,18 +16,16 @@
|
|||
|
||||
package im.vector.app.features.home
|
||||
|
||||
import arrow.core.Option
|
||||
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
|
||||
import im.vector.app.RoomGroupingMethod
|
||||
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.util.MatrixItem
|
||||
|
||||
data class HomeDetailViewState(
|
||||
val groupSummary: Option<GroupSummary> = Option.empty(),
|
||||
val spaceSummary: Option<RoomSummary> = Option.empty(),
|
||||
val roomGroupingMethod: RoomGroupingMethod = RoomGroupingMethod.BySpace(null),
|
||||
val myMatrixItem: MatrixItem? = null,
|
||||
val asyncRooms: Async<List<RoomSummary>> = Uninitialized,
|
||||
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.utils.startSharePlainTextIntent
|
||||
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.VectorSettingsActivity
|
||||
import im.vector.app.features.spaces.SpaceListFragment
|
||||
|
@ -59,11 +59,11 @@ class HomeDrawerFragment @Inject constructor(
|
|||
sharedActionViewModel = activityViewModelProvider.get(HomeSharedActionViewModel::class.java)
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
if (vectorPreferences.labSpaces()) {
|
||||
// if (vectorPreferences.labSpaces()) {
|
||||
replaceChildFragment(R.id.homeDrawerGroupListContainer, SpaceListFragment::class.java)
|
||||
} else {
|
||||
replaceChildFragment(R.id.homeDrawerGroupListContainer, GroupListFragment::class.java)
|
||||
}
|
||||
// } else {
|
||||
// replaceChildFragment(R.id.homeDrawerGroupListContainer, GroupListFragment::class.java)
|
||||
// }
|
||||
}
|
||||
session.getUserLive(session.myUserId).observeK(viewLifecycleOwner) { optionalUser ->
|
||||
val user = optionalUser?.getOrNull()
|
||||
|
|
|
@ -107,8 +107,8 @@ class UnreadMessagesSharedViewModel @AssistedInject constructor(@Assisted initia
|
|||
}.disposeOnClear()
|
||||
|
||||
Observable.combineLatest(
|
||||
appStateHandler.selectedSpaceObservable.distinctUntilChanged(),
|
||||
appStateHandler.selectedSpaceObservable.switchMap {
|
||||
appStateHandler.selectedRoomGroupingObservable.distinctUntilChanged(),
|
||||
appStateHandler.selectedRoomGroupingObservable.switchMap {
|
||||
session.getPagedRoomSummariesLive(
|
||||
roomSummaryQueryParams {
|
||||
this.memberships = Membership.activeMemberships()
|
||||
|
|
|
@ -179,14 +179,14 @@ class RoomDetailViewModel @AssistedInject constructor(
|
|||
observePowerLevel()
|
||||
updateShowDialerOptionState()
|
||||
room.getRoomSummaryLive()
|
||||
viewModelScope.launch {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
tryOrNull { room.markAsRead(ReadService.MarkAsReadParams.READ_RECEIPT) }
|
||||
}
|
||||
// Inform the SDK that the room is displayed
|
||||
viewModelScope.launch {
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
try {
|
||||
session.onRoomDisplayed(initialState.roomId)
|
||||
} catch (_: Exception) {
|
||||
} catch (_: Throwable) {
|
||||
}
|
||||
}
|
||||
callManager.addPstnSupportListener(this)
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
package im.vector.app.features.home.room.list
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import im.vector.app.AppStateHandler
|
||||
import im.vector.app.R
|
||||
import im.vector.app.RoomGroupingMethod
|
||||
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 io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
|
@ -37,25 +37,24 @@ class GroupRoomListSectionBuilder(
|
|||
val session: Session,
|
||||
val stringProvider: StringProvider,
|
||||
val viewModelScope: CoroutineScope,
|
||||
val selectedGroupDataSource: SelectedGroupDataSource,
|
||||
val appStateHandler: AppStateHandler,
|
||||
val onDisposable: (Disposable) -> Unit,
|
||||
val onUdpatable: (UpdatableLivePageResult) -> Unit
|
||||
) : RoomListSectionBuilder {
|
||||
|
||||
override fun buildSections(mode: RoomListDisplayMode): List<RoomsSection> {
|
||||
val activeSpaceAwareQueries = mutableListOf<UpdatableLivePageResult>()
|
||||
val activeGroupAwareQueries = mutableListOf<UpdatableLivePageResult>()
|
||||
val sections = mutableListOf<RoomsSection>()
|
||||
val actualGroupId = selectedGroupDataSource.currentValue?.orNull()
|
||||
?.groupId?.takeIf { it != ALL_COMMUNITIES_GROUP_ID }
|
||||
val actualGroupId = appStateHandler.safeActiveGroupId()
|
||||
|
||||
when (mode) {
|
||||
RoomListDisplayMode.PEOPLE -> {
|
||||
// 3 sections Invites / Fav / Dms
|
||||
buildPeopleSections(sections, activeSpaceAwareQueries, actualGroupId)
|
||||
buildPeopleSections(sections, activeGroupAwareQueries, actualGroupId)
|
||||
}
|
||||
RoomListDisplayMode.ROOMS -> {
|
||||
// 5 sections invites / Fav / Rooms / Low Priority / Server notice
|
||||
buildRoomsSections(sections, activeSpaceAwareQueries, actualGroupId)
|
||||
buildRoomsSections(sections, activeGroupAwareQueries, actualGroupId)
|
||||
}
|
||||
RoomListDisplayMode.FILTERED -> {
|
||||
// Used when searching for rooms
|
||||
|
@ -76,7 +75,7 @@ class GroupRoomListSectionBuilder(
|
|||
RoomListDisplayMode.NOTIFICATIONS -> {
|
||||
addSection(
|
||||
sections,
|
||||
activeSpaceAwareQueries,
|
||||
activeGroupAwareQueries,
|
||||
R.string.invitations_header,
|
||||
true
|
||||
) {
|
||||
|
@ -87,7 +86,7 @@ class GroupRoomListSectionBuilder(
|
|||
|
||||
addSection(
|
||||
sections,
|
||||
activeSpaceAwareQueries,
|
||||
activeGroupAwareQueries,
|
||||
R.string.bottom_action_rooms,
|
||||
false
|
||||
) {
|
||||
|
@ -98,11 +97,11 @@ class GroupRoomListSectionBuilder(
|
|||
}
|
||||
}
|
||||
|
||||
selectedGroupDataSource.observe()
|
||||
appStateHandler.selectedRoomGroupingObservable
|
||||
.distinctUntilChanged()
|
||||
.subscribe { activeSpaceOption ->
|
||||
val selectedGroupId = activeSpaceOption.orNull()?.groupId?.takeIf { it != ALL_COMMUNITIES_GROUP_ID }
|
||||
activeSpaceAwareQueries.onEach { updater ->
|
||||
.subscribe { groupingMethod ->
|
||||
val selectedGroupId = (groupingMethod as? RoomGroupingMethod.ByLegacyGroup)?.groupSummary?.groupId
|
||||
activeGroupAwareQueries.onEach { updater ->
|
||||
updater.updateQuery { query ->
|
||||
query.copy(activeGroupId = selectedGroupId)
|
||||
}
|
||||
|
|
|
@ -26,10 +26,10 @@ import com.airbnb.mvrx.MvRxViewModelFactory
|
|||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
import im.vector.app.AppStateHandler
|
||||
import im.vector.app.RoomGroupingMethod
|
||||
import im.vector.app.core.extensions.exhaustive
|
||||
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.settings.VectorPreferences
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -49,7 +49,6 @@ class RoomListViewModel @Inject constructor(
|
|||
private val session: Session,
|
||||
private val stringProvider: StringProvider,
|
||||
private val appStateHandler: AppStateHandler,
|
||||
private val selectedGroupDataSource: SelectedGroupDataSource,
|
||||
private val vectorPreferences: VectorPreferences
|
||||
) : VectorViewModel<RoomListViewState, RoomListAction, RoomListViewEvents>(initialState) {
|
||||
|
||||
|
@ -72,15 +71,14 @@ class RoomListViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
init {
|
||||
Timber.w("VAL: RoomListViewModel INIT")
|
||||
observeMembershipChanges()
|
||||
|
||||
appStateHandler.selectedSpaceObservable
|
||||
.distinctUntilChanged()
|
||||
.map { it.orNull() }
|
||||
appStateHandler.selectedRoomGroupingObservable
|
||||
.distinctUntilChanged()
|
||||
.execute {
|
||||
copy(
|
||||
currentSpace = it
|
||||
currentRoomGrouping = it
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -113,7 +111,7 @@ class RoomListViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
val sections: List<RoomsSection> by lazy {
|
||||
if (vectorPreferences.labSpaces()) {
|
||||
if (appStateHandler.getCurrentRoomGroupingMethod() is RoomGroupingMethod.BySpace) {
|
||||
SpaceRoomListSectionBuilder(
|
||||
session,
|
||||
stringProvider,
|
||||
|
@ -132,7 +130,7 @@ class RoomListViewModel @Inject constructor(
|
|||
session,
|
||||
stringProvider,
|
||||
viewModelScope,
|
||||
selectedGroupDataSource,
|
||||
appStateHandler,
|
||||
{
|
||||
it.disposeOnClear()
|
||||
},
|
||||
|
|
|
@ -18,7 +18,6 @@ package im.vector.app.features.home.room.list
|
|||
|
||||
import im.vector.app.AppStateHandler
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.features.grouplist.SelectedGroupDataSource
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import javax.inject.Inject
|
||||
|
@ -27,8 +26,7 @@ import javax.inject.Provider
|
|||
class RoomListViewModelFactory @Inject constructor(private val session: Provider<Session>,
|
||||
private val appStateHandler: AppStateHandler,
|
||||
private val stringProvider: StringProvider,
|
||||
private val vectorPreferences: VectorPreferences,
|
||||
private val selectedGroupDataSource: SelectedGroupDataSource)
|
||||
private val vectorPreferences: VectorPreferences)
|
||||
: RoomListViewModel.Factory {
|
||||
|
||||
override fun create(initialState: RoomListViewState): RoomListViewModel {
|
||||
|
@ -37,7 +35,6 @@ class RoomListViewModelFactory @Inject constructor(private val session: Provider
|
|||
session.get(),
|
||||
stringProvider,
|
||||
appStateHandler,
|
||||
selectedGroupDataSource,
|
||||
vectorPreferences
|
||||
)
|
||||
}
|
||||
|
|
|
@ -19,9 +19,9 @@ package im.vector.app.features.home.room.list
|
|||
import com.airbnb.mvrx.Async
|
||||
import com.airbnb.mvrx.MvRxState
|
||||
import com.airbnb.mvrx.Uninitialized
|
||||
import im.vector.app.RoomGroupingMethod
|
||||
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.model.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo
|
||||
|
||||
data class RoomListViewState(
|
||||
|
@ -30,7 +30,7 @@ data class RoomListViewState(
|
|||
val roomMembershipChanges: Map<String, ChangeMembershipState> = emptyMap(),
|
||||
val asyncSuggestedRooms: Async<List<SpaceChildInfo>> = Uninitialized,
|
||||
val currentUserName: String? = null,
|
||||
val currentSpace: Async<RoomSummary?> = Uninitialized
|
||||
val currentRoomGrouping: Async<RoomGroupingMethod> = Uninitialized
|
||||
) : MvRxState {
|
||||
|
||||
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.core.resources.StringProvider
|
||||
import im.vector.app.features.home.RoomListDisplayMode
|
||||
import im.vector.app.space
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.rxkotlin.Observables
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
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.query.ActiveSpaceFilter
|
||||
import org.matrix.android.sdk.api.query.RoomCategoryFilter
|
||||
|
@ -110,12 +110,12 @@ class SpaceRoomListSectionBuilder(
|
|||
}
|
||||
}
|
||||
|
||||
appStateHandler.selectedSpaceObservable
|
||||
appStateHandler.selectedRoomGroupingObservable
|
||||
.distinctUntilChanged()
|
||||
.subscribe { activeSpaceOption ->
|
||||
val selectedSpace = activeSpaceOption.orNull()
|
||||
.subscribe { groupingMethod ->
|
||||
val selectedSpace = groupingMethod.space()
|
||||
activeSpaceAwareQueries.onEach { updater ->
|
||||
updater.updateForSpaceId(selectedSpace?.roomId?.takeIf { MatrixPatterns.isRoomId(it) })
|
||||
updater.updateForSpaceId(selectedSpace?.roomId)
|
||||
}
|
||||
}.also {
|
||||
onDisposable.invoke(it)
|
||||
|
@ -185,10 +185,10 @@ class SpaceRoomListSectionBuilder(
|
|||
|
||||
// add suggested rooms
|
||||
val suggestedRoomsObservable = // MutableLiveData<List<SpaceChildInfo>>()
|
||||
appStateHandler.selectedSpaceObservable
|
||||
appStateHandler.selectedRoomGroupingObservable
|
||||
.distinctUntilChanged()
|
||||
.switchMap { activeSpaceOption ->
|
||||
val selectedSpace = activeSpaceOption.orNull()
|
||||
.switchMap { groupingMethod ->
|
||||
val selectedSpace = groupingMethod.space()
|
||||
if (selectedSpace == null) {
|
||||
Observable.just(emptyList())
|
||||
} else {
|
||||
|
|
|
@ -31,6 +31,7 @@ import androidx.core.util.Pair
|
|||
import androidx.core.view.ViewCompat
|
||||
import im.vector.app.AppStateHandler
|
||||
import im.vector.app.R
|
||||
import im.vector.app.RoomGroupingMethod
|
||||
import im.vector.app.core.di.ActiveSessionHolder
|
||||
import im.vector.app.core.error.fatalError
|
||||
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.widgets.WidgetActivity
|
||||
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.room.model.roomdirectory.PublicRoom
|
||||
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.widgets.model.Widget
|
||||
import org.matrix.android.sdk.api.session.widgets.model.WidgetType
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
@ -106,17 +107,11 @@ class DefaultNavigator @Inject constructor(
|
|||
}
|
||||
|
||||
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())
|
||||
return
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
appStateHandler.setCurrentSpace(spaceId)
|
||||
if (roomId != null) {
|
||||
val args = RoomDetailArgs(roomId, eventId = null, openShareSpaceForId = spaceId.takeIf { openShareSheet })
|
||||
val intent = RoomDetailActivity.newIntent(context, args)
|
||||
|
@ -251,15 +246,22 @@ class DefaultNavigator @Inject constructor(
|
|||
}
|
||||
|
||||
override fun openRoomDirectory(context: Context, initialFilter: String) {
|
||||
val selectedSpace = appStateHandler.safeActiveSpace()?.let {
|
||||
sessionHolder.getSafeActiveSession()?.getRoomSummary(it.roomId)
|
||||
}
|
||||
if (selectedSpace == null) {
|
||||
val intent = RoomDirectoryActivity.getIntent(context, initialFilter)
|
||||
context.startActivity(intent)
|
||||
} else {
|
||||
SpaceExploreActivity.newIntent(context, selectedSpace.roomId).let {
|
||||
context.startActivity(it)
|
||||
when (val groupingMethod = appStateHandler.getCurrentRoomGroupingMethod()) {
|
||||
is RoomGroupingMethod.ByLegacyGroup -> {
|
||||
// TODO should open list of rooms of this group
|
||||
val intent = RoomDirectoryActivity.getIntent(context, initialFilter)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
is RoomGroupingMethod.BySpace -> {
|
||||
val selectedSpace = groupingMethod.space()
|
||||
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) {
|
||||
val selectedSpace = appStateHandler.safeActiveSpace()
|
||||
if (vectorPreferences.labSpaces() && selectedSpace != null) {
|
||||
// let user decides if he does it from space or room
|
||||
(context as? AppCompatActivity)?.supportFragmentManager?.let { fm ->
|
||||
InviteRoomSpaceChooserBottomSheet.newInstance(
|
||||
selectedSpace.roomId,
|
||||
roomId,
|
||||
object : InviteRoomSpaceChooserBottomSheet.InteractionListener {
|
||||
override fun inviteToSpace(spaceId: String) {
|
||||
val intent = InviteUsersToRoomActivity.getIntent(context, spaceId)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
override fun inviteToRoom(roomId: String) {
|
||||
val intent = InviteUsersToRoomActivity.getIntent(context, roomId)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
).show(fm, InviteRoomSpaceChooserBottomSheet::class.java.name)
|
||||
when (val currentGroupingMethod = appStateHandler.getCurrentRoomGroupingMethod()) {
|
||||
is RoomGroupingMethod.ByLegacyGroup -> {
|
||||
val intent = InviteUsersToRoomActivity.getIntent(context, roomId)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
is RoomGroupingMethod.BySpace -> {
|
||||
if (currentGroupingMethod.spaceSummary != null) {
|
||||
// let user decides if he does it from space or room
|
||||
(context as? AppCompatActivity)?.supportFragmentManager?.let { fm ->
|
||||
InviteRoomSpaceChooserBottomSheet.newInstance(
|
||||
currentGroupingMethod.spaceSummary.roomId,
|
||||
roomId,
|
||||
object : InviteRoomSpaceChooserBottomSheet.InteractionListener {
|
||||
override fun inviteToSpace(spaceId: String) {
|
||||
val intent = InviteUsersToRoomActivity.getIntent(context, spaceId)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
|
||||
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");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -14,13 +14,15 @@
|
|||
* 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
|
||||
|
||||
/**
|
||||
* Transient events for group list screen
|
||||
*/
|
||||
sealed class GroupListViewEvents : VectorViewEvents {
|
||||
object OpenGroupSummary : GroupListViewEvents()
|
||||
@EpoxyModelClass(layout = R.layout.item_space_beta_header)
|
||||
abstract class SpaceBetaHeaderItem : VectorEpoxyModel<SpaceBetaHeaderItem.Holder>() {
|
||||
|
||||
class Holder : VectorEpoxyHolder()
|
||||
}
|
|
@ -17,6 +17,7 @@
|
|||
package im.vector.app.features.spaces
|
||||
|
||||
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
|
||||
|
||||
sealed class SpaceListAction : VectorViewModelAction {
|
||||
|
@ -25,4 +26,6 @@ sealed class SpaceListAction : VectorViewModelAction {
|
|||
data class LeaveSpace(val spaceSummary: RoomSummary) : SpaceListAction()
|
||||
data class ToggleExpand(val spaceSummary: RoomSummary) : 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.features.home.HomeActivitySharedAction
|
||||
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 javax.inject.Inject
|
||||
|
||||
|
@ -56,8 +57,9 @@ class SpaceListFragment @Inject constructor(
|
|||
viewModel.observeViewEvents {
|
||||
when (it) {
|
||||
is SpaceListViewEvents.OpenSpaceSummary -> sharedActionViewModel.post(HomeActivitySharedAction.OpenSpacePreview(it.id))
|
||||
is SpaceListViewEvents.OpenSpace -> sharedActionViewModel.post(HomeActivitySharedAction.OpenGroup)
|
||||
is SpaceListViewEvents.AddSpace -> sharedActionViewModel.post(HomeActivitySharedAction.AddSpace)
|
||||
is SpaceListViewEvents.OpenSpace -> sharedActionViewModel.post(HomeActivitySharedAction.OpenGroup(it.groupingMethodHasChanged))
|
||||
is SpaceListViewEvents.AddSpace -> sharedActionViewModel.post(HomeActivitySharedAction.AddSpace)
|
||||
is SpaceListViewEvents.OpenGroup -> sharedActionViewModel.post(HomeActivitySharedAction.OpenGroup(it.groupingMethodHasChanged))
|
||||
}.exhaustive
|
||||
}
|
||||
}
|
||||
|
@ -94,4 +96,8 @@ class SpaceListFragment @Inject constructor(
|
|||
override fun onAddSpaceSelected() {
|
||||
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
|
||||
*/
|
||||
sealed class SpaceListViewEvents : VectorViewEvents {
|
||||
object OpenSpace : SpaceListViewEvents()
|
||||
data class OpenSpace(val groupingMethodHasChanged: Boolean) : SpaceListViewEvents()
|
||||
data class OpenSpaceSummary(val id: String) : 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.MvRxState
|
||||
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.summary.RoomAggregateNotificationCount
|
||||
import org.matrix.android.sdk.api.util.MatrixItem
|
||||
|
||||
data class SpaceListViewState(
|
||||
val myMxItem : Async<MatrixItem.UserItem> = Uninitialized,
|
||||
val asyncSpaces: Async<List<RoomSummary>> = Uninitialized,
|
||||
val selectedSpace: RoomSummary? = null,
|
||||
val selectedGroupingMethod: RoomGroupingMethod = RoomGroupingMethod.BySpace(null),
|
||||
val rootSpaces: List<RoomSummary>? = null,
|
||||
val legacyGroups: List<GroupSummary>? = null,
|
||||
val expandedStates: Map<String, Boolean> = emptyMap(),
|
||||
val homeAggregateCount : RoomAggregateNotificationCount = RoomAggregateNotificationCount(0, 0)
|
||||
) : MvRxState
|
||||
|
|
|
@ -18,14 +18,17 @@ package im.vector.app.features.spaces
|
|||
|
||||
import com.airbnb.epoxy.EpoxyController
|
||||
import im.vector.app.R
|
||||
import im.vector.app.RoomGroupingMethod
|
||||
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.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.home.AvatarRenderer
|
||||
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.RoomSummary
|
||||
import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount
|
||||
|
@ -53,63 +56,101 @@ class SpaceSummaryController @Inject constructor(
|
|||
val nonNullViewState = viewState ?: return
|
||||
buildGroupModels(
|
||||
nonNullViewState.asyncSpaces(),
|
||||
nonNullViewState.selectedSpace,
|
||||
nonNullViewState.selectedGroupingMethod,
|
||||
nonNullViewState.rootSpaces,
|
||||
nonNullViewState.expandedStates,
|
||||
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>?,
|
||||
selected: RoomSummary?,
|
||||
selected: RoomGroupingMethod,
|
||||
rootSpaces: List<RoomSummary>?,
|
||||
expandedStates: Map<String, Boolean>,
|
||||
homeCount: RoomAggregateNotificationCount) {
|
||||
if (summaries.isNullOrEmpty()) {
|
||||
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 {
|
||||
id("spaces")
|
||||
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 }
|
||||
?.let {
|
||||
val isSelected = selected is RoomGroupingMethod.BySpace && selected.space() == null
|
||||
homeSpaceSummaryItem {
|
||||
id(it.roomId)
|
||||
selected(it.roomId == selected?.roomId)
|
||||
selected(isSelected)
|
||||
countState(UnreadCounterBadgeView.State(homeCount.totalCount, homeCount.isHighlight))
|
||||
listener { callback?.onSpaceSelected(it) }
|
||||
}
|
||||
}
|
||||
|
||||
rootSpaces
|
||||
?.sortedBy { it.displayName }
|
||||
?.forEach { groupSummary ->
|
||||
val isSelected = groupSummary.roomId == selected?.roomId
|
||||
val isSelected = selected is RoomGroupingMethod.BySpace && groupSummary.roomId == selected.space()?.roomId
|
||||
// does it have children?
|
||||
val subSpaces = groupSummary.children?.filter { childInfo ->
|
||||
summaries.indexOfFirst { it.roomId == childInfo.childRoomId } != -1
|
||||
|
@ -139,7 +180,7 @@ class SpaceSummaryController @Inject constructor(
|
|||
// it's expanded
|
||||
subSpaces?.forEach { child ->
|
||||
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 {
|
||||
avatarRenderer(avatarRenderer)
|
||||
id(child.childRoomId)
|
||||
|
@ -161,12 +202,9 @@ class SpaceSummaryController @Inject constructor(
|
|||
}
|
||||
|
||||
// Temporary item to create a new Space (will move with final design)
|
||||
|
||||
genericButtonItem {
|
||||
spaceAddItem {
|
||||
id("create")
|
||||
text(stringProvider.getString(R.string.add_space))
|
||||
iconRes(R.drawable.ic_add_black)
|
||||
buttonClickAction(DebouncedClickListener({ callback?.onAddSpaceSelected() }))
|
||||
listener { callback?.onAddSpaceSelected() }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,5 +214,7 @@ class SpaceSummaryController @Inject constructor(
|
|||
fun onSpaceSettings(spaceSummary: RoomSummary)
|
||||
fun onToggleExpand(spaceSummary: RoomSummary)
|
||||
fun onAddSpaceSelected()
|
||||
|
||||
fun onGroupSelected(groupSummary: GroupSummary?)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ 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.extensions.setTextOrHide
|
||||
import im.vector.app.core.platform.CheckableConstraintLayout
|
||||
import im.vector.app.core.utils.DebouncedClickListener
|
||||
import im.vector.app.features.home.AvatarRenderer
|
||||
|
@ -46,6 +47,7 @@ abstract class SpaceSummaryItem : VectorEpoxyModel<SpaceSummaryItem.Holder>() {
|
|||
@EpoxyAttribute var hasChildren: Boolean = false
|
||||
@EpoxyAttribute var indent: Int = 0
|
||||
@EpoxyAttribute var countState : UnreadCounterBadgeView.State = UnreadCounterBadgeView.State(0, false)
|
||||
@EpoxyAttribute var description: String? = null
|
||||
|
||||
override fun bind(holder: Holder) {
|
||||
super.bind(holder)
|
||||
|
@ -62,6 +64,7 @@ abstract class SpaceSummaryItem : VectorEpoxyModel<SpaceSummaryItem.Holder>() {
|
|||
holder.moreView.isVisible = false
|
||||
}
|
||||
|
||||
holder.secondLineText.setTextOrHide(description)
|
||||
if (hasChildren) {
|
||||
// holder.collapseIndicator.setOnClickListener(
|
||||
// DebouncedClickListener({ _ ->
|
||||
|
@ -104,6 +107,7 @@ abstract class SpaceSummaryItem : VectorEpoxyModel<SpaceSummaryItem.Holder>() {
|
|||
class Holder : VectorEpoxyHolder() {
|
||||
val avatarImageView by bind<ImageView>(R.id.groupAvatarImageView)
|
||||
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 moreView by bind<ImageView>(R.id.groupTmpLeave)
|
||||
val collapseIndicator by bind<ImageView>(R.id.groupChildrenCollapse)
|
||||
|
|
|
@ -18,16 +18,21 @@ package im.vector.app.features.spaces
|
|||
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.airbnb.mvrx.FragmentViewModelContext
|
||||
import com.airbnb.mvrx.Loading
|
||||
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||
import com.airbnb.mvrx.Success
|
||||
import com.airbnb.mvrx.ViewModelContext
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedFactory
|
||||
import dagger.assisted.AssistedInject
|
||||
import im.vector.app.AppStateHandler
|
||||
import im.vector.app.R
|
||||
import im.vector.app.RoomGroupingMethod
|
||||
import im.vector.app.core.platform.VectorViewModel
|
||||
import im.vector.app.core.resources.StringProvider
|
||||
import im.vector.app.features.ui.UiStateRepository
|
||||
import im.vector.app.group
|
||||
import im.vector.app.space
|
||||
import io.reactivex.Observable
|
||||
import io.reactivex.functions.BiFunction
|
||||
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.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.room.RoomSortOrder
|
||||
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.roomSummaryQueryParams
|
||||
import org.matrix.android.sdk.api.util.toMatrixItem
|
||||
import org.matrix.android.sdk.rx.asObservable
|
||||
import org.matrix.android.sdk.rx.rx
|
||||
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 {
|
||||
observeSpaceSummaries()
|
||||
observeSelectionState()
|
||||
appStateHandler.selectedSpaceObservable
|
||||
|
||||
session.getUserLive(session.myUserId).asObservable()
|
||||
.subscribe {
|
||||
if (currentGroupId != it.orNull()?.roomId) {
|
||||
setState {
|
||||
copy(
|
||||
selectedSpace = it.orNull()
|
||||
)
|
||||
}
|
||||
setState {
|
||||
copy(
|
||||
myMxItem = it?.getOrNull()?.toMatrixItem()?.let { Success(it) } ?: Loading()
|
||||
)
|
||||
}
|
||||
}.disposeOnClear()
|
||||
|
||||
observeSpaceSummaries()
|
||||
// observeSelectionState()
|
||||
appStateHandler.selectedRoomGroupingObservable
|
||||
.distinctUntilChanged()
|
||||
.subscribe {
|
||||
setState {
|
||||
copy(
|
||||
selectedGroupingMethod = it
|
||||
)
|
||||
}
|
||||
}
|
||||
.disposeOnClear()
|
||||
|
||||
session.getGroupSummariesLive(groupSummaryQueryParams {})
|
||||
.asObservable()
|
||||
.subscribe {
|
||||
setState {
|
||||
copy(
|
||||
legacyGroups = it
|
||||
)
|
||||
}
|
||||
}.disposeOnClear()
|
||||
|
||||
session.getPagedRoomSummariesLive(
|
||||
roomSummaryQueryParams {
|
||||
this.memberships = listOf(Membership.JOIN)
|
||||
|
@ -107,23 +133,23 @@ class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: Sp
|
|||
}.disposeOnClear()
|
||||
}
|
||||
|
||||
private fun observeSelectionState() {
|
||||
selectSubscribe(SpaceListViewState::selectedSpace) { spaceSummary ->
|
||||
if (spaceSummary != null) {
|
||||
// We only want to open group if the updated selectedGroup is a different one.
|
||||
if (currentGroupId != spaceSummary.roomId) {
|
||||
currentGroupId = spaceSummary.roomId
|
||||
_viewEvents.post(SpaceListViewEvents.OpenSpace)
|
||||
}
|
||||
appStateHandler.setCurrentSpace(spaceSummary)
|
||||
} else {
|
||||
// If selected group is null we force to default. It can happens when leaving the selected group.
|
||||
setState {
|
||||
copy(selectedSpace = this.asyncSpaces()?.find { it.roomId == ALL_COMMUNITIES_GROUP_ID })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// private fun observeSelectionState() {
|
||||
// selectSubscribe(SpaceListViewState::selectedSpace) { spaceSummary ->
|
||||
// if (spaceSummary != null) {
|
||||
// // We only want to open group if the updated selectedGroup is a different one.
|
||||
// if (currentGroupId != spaceSummary.roomId) {
|
||||
// currentGroupId = spaceSummary.roomId
|
||||
// _viewEvents.post(SpaceListViewEvents.OpenSpace)
|
||||
// }
|
||||
// appStateHandler.setCurrentSpace(spaceSummary.roomId)
|
||||
// } else {
|
||||
// // If selected group is null we force to default. It can happens when leaving the selected group.
|
||||
// setState {
|
||||
// copy(selectedSpace = this.asyncSpaces()?.find { it.roomId == ALL_COMMUNITIES_GROUP_ID })
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
override fun handle(action: SpaceListAction) {
|
||||
when (action) {
|
||||
|
@ -132,15 +158,31 @@ class SpacesListViewModel @AssistedInject constructor(@Assisted initialState: Sp
|
|||
SpaceListAction.AddSpace -> handleAddSpace()
|
||||
is SpaceListAction.ToggleExpand -> handleToggleExpand(action)
|
||||
is SpaceListAction.OpenSpaceInvite -> handleSelectSpaceInvite(action)
|
||||
is SpaceListAction.SelectLegacyGroup -> handleSelectGroup(action)
|
||||
}
|
||||
}
|
||||
|
||||
// PRIVATE METHODS *****************************************************************************
|
||||
|
||||
private fun handleSelectSpace(action: SpaceListAction.SelectSpace) = withState { state ->
|
||||
if (state.selectedSpace?.roomId != action.spaceSummary.roomId) {
|
||||
setState { copy(selectedSpace = action.spaceSummary) }
|
||||
uiStateRepository.storeSelectedSpace(action.spaceSummary.roomId, session.sessionId)
|
||||
val groupingMethod = state.selectedGroupingMethod
|
||||
if (groupingMethod is RoomGroupingMethod.ByLegacyGroup || groupingMethod.space()?.roomId != action.spaceSummary.roomId) {
|
||||
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 ->
|
||||
val currentSelectedGroupId = selectedSpace?.roomId
|
||||
val newSelectedGroup = if (currentSelectedGroupId != null) {
|
||||
async()?.find { it.roomId == currentSelectedGroupId }
|
||||
} else {
|
||||
async()?.firstOrNull()
|
||||
}
|
||||
// val currentSelectedGroupId = selectedGroupingMethod?.roomId
|
||||
// val newSelectedGroup = if (currentSelectedGroupId != null) {
|
||||
// async()?.find { it.roomId == currentSelectedGroupId }
|
||||
// } else {
|
||||
// async()?.firstOrNull()
|
||||
// }
|
||||
copy(
|
||||
asyncSpaces = async,
|
||||
selectedSpace = newSelectedGroup,
|
||||
rootSpaces = session.spaceService().getRootSpaceSummaries()
|
||||
)
|
||||
}
|
||||
|
|
|
@ -20,6 +20,8 @@ import android.content.SharedPreferences
|
|||
import androidx.core.content.edit
|
||||
import im.vector.app.features.home.RoomListDisplayMode
|
||||
import im.vector.app.features.settings.VectorPreferences
|
||||
import org.matrix.android.sdk.api.session.Session
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
|
@ -59,16 +61,38 @@ class SharedPreferencesUiStateRepository @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
override fun storeSelectedSpace(spaceId: String?, sessionId: String) {
|
||||
sharedPreferences.edit {
|
||||
override fun storeSelectedSpace(spaceId: String?, sessionId: Session?) {
|
||||
Timber.w("VAL: storeSelectedSpace $spaceId")
|
||||
sharedPreferences.edit(true) {
|
||||
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? {
|
||||
return sharedPreferences.getString("$KEY_SELECTED_SPACE@$sessionId", null)
|
||||
}
|
||||
|
||||
override fun isGroupingMethodSpace(sessionId: String): Boolean {
|
||||
return sharedPreferences.getBoolean("$KEY_SELECTED_METHOD@$sessionId", true)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val KEY_DISPLAY_MODE = "UI_STATE_DISPLAY_MODE"
|
||||
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 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
|
||||
|
||||
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
|
||||
|
@ -32,7 +33,12 @@ interface UiStateRepository {
|
|||
|
||||
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 getSelectedGroup(sessionId: String): String?
|
||||
fun isGroupingMethodSpace(sessionId: String): Boolean
|
||||
}
|
||||
|
|
|
@ -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_marginStart="4dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:gravity="center"
|
||||
android:minWidth="16dp"
|
||||
android:minHeight="16dp"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="10sp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintCircle="@+id/groupAvatarImageView"
|
||||
app:layout_constraintCircleAngle="45"
|
||||
app:layout_constraintCircleRadius="24dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible"
|
||||
tools:background="@drawable/bg_unread_highlight"
|
||||
tools:text="147" />
|
||||
tools:text="147"
|
||||
tools:visibility="visible" />
|
||||
|
||||
|
||||
<TextView
|
||||
|
@ -66,10 +66,30 @@
|
|||
android:textColor="?riotx_text_primary"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toTopOf="@+id/groupBottomSeparator"
|
||||
app:layout_constraintBottom_toTopOf="@+id/groupDescView"
|
||||
app:layout_constraintEnd_toStartOf="@+id/groupChildrenCollapse"
|
||||
app:layout_constraintStart_toEndOf="@+id/groupAvatarImageView"
|
||||
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" />
|
||||
|
||||
|
||||
|
|
|
@ -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>
|
|
@ -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
|
||||
android:id="@+id/progressBar"
|
||||
style="?progressBarStyle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center" />
|
||||
|
|
|
@ -3337,4 +3337,7 @@
|
|||
|
||||
|
||||
<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>
|
||||
|
|
Loading…
Reference in New Issue