diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt index 8fdc563edb..c68f4db146 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/space/DefaultSpaceService.kt @@ -127,24 +127,30 @@ internal class DefaultSpaceService @Inject constructor( ), second = response.rooms ?.filter { it.roomId != spaceId } - ?.map { childSummary -> - val childStateEv = response.events - ?.firstOrNull { it.stateKey == childSummary.roomId && it.type == EventType.STATE_SPACE_CHILD } - val childStateEvContent = childStateEv?.content.toModel() - SpaceChildInfo( - childRoomId = childSummary.roomId, - isKnown = true, - roomType = childSummary.roomType, - name = childSummary.name, - topic = childSummary.topic, - avatarUrl = childSummary.avatarUrl, - order = childStateEvContent?.order, - autoJoin = childStateEvContent?.autoJoin ?: false, - viaServers = childStateEvContent?.via ?: emptyList(), - activeMemberCount = childSummary.numJoinedMembers, - parentRoomId = childStateEv?.roomId - ) - }.orEmpty() + ?.flatMap { childSummary -> + response.events + ?.filter { it.stateKey == childSummary.roomId && it.type == EventType.STATE_SPACE_CHILD } + ?.mapNotNull { childStateEv -> + // create a child entry for everytime this room is the child of a space + // beware that a room could appear then twice in this list + childStateEv.content.toModel()?.let { childStateEvContent -> + SpaceChildInfo( + childRoomId = childSummary.roomId, + isKnown = true, + roomType = childSummary.roomType, + name = childSummary.name, + topic = childSummary.topic, + avatarUrl = childSummary.avatarUrl, + order = childStateEvContent.order, + autoJoin = childStateEvContent.autoJoin ?: false, + viaServers = childStateEvContent.via.orEmpty(), + activeMemberCount = childSummary.numJoinedMembers, + parentRoomId = childStateEv.roomId + ) + } + }.orEmpty() + } + .orEmpty() ) } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/SpaceRoomListSectionBuilder.kt b/vector/src/main/java/im/vector/app/features/home/room/list/SpaceRoomListSectionBuilder.kt index f7e527a710..351c72ab48 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/SpaceRoomListSectionBuilder.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/SpaceRoomListSectionBuilder.kt @@ -194,7 +194,7 @@ class SpaceRoomListSectionBuilder( } else { liveData(context = viewModelScope.coroutineContext + Dispatchers.IO) { val spaceSum = tryOrNull { session.spaceService().querySpaceChildren(selectedSpace.roomId, suggestedOnly = true) } - val value = spaceSum?.second ?: emptyList() + val value = spaceSum?.second.orEmpty().distinctBy { it.childRoomId } // i need to check if it's already joined. val filtered = value.filter { session.getRoomSummary(it.childRoomId)?.membership?.isActive() != true diff --git a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt index b9ef833850..61e4accba2 100644 --- a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheet.kt @@ -36,6 +36,7 @@ import im.vector.app.databinding.BottomSheetMatrixToCardBinding import im.vector.app.features.home.AvatarRenderer import kotlinx.parcelize.Parcelize import org.matrix.android.sdk.api.session.permalinks.PermalinkData +import java.lang.ref.WeakReference import javax.inject.Inject import kotlin.reflect.KClass @@ -56,7 +57,13 @@ class MatrixToBottomSheet : injector.inject(this) } - private var interactionListener: InteractionListener? = null + private var weakReference = WeakReference(null) + + var interactionListener: InteractionListener? + set(value) { + weakReference = WeakReference(value) + } + get() = weakReference.get() override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): BottomSheetMatrixToCardBinding { return BottomSheetMatrixToCardBinding.inflate(inflater, container, false) diff --git a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt index 0d633ac422..694f324025 100644 --- a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToBottomSheetViewModel.kt @@ -120,6 +120,7 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor( ?.roomSummary() // don't take if not active, as it could be outdated ?.takeIf { it.membership.isActive() } + // XXX fix that val forceRefresh = true if (!forceRefresh && knownRoom != null) { setState { @@ -147,7 +148,7 @@ class MatrixToBottomSheetViewModel @AssistedInject constructor( topic = peekResult.topic ?: "", memberCount = peekResult.numJoinedMembers, alias = peekResult.alias, - membership = Membership.NONE, + membership = knownRoom?.membership ?: Membership.NONE, roomType = peekResult.roomType, viaServers = peekResult.viaServers.takeIf { it.isNotEmpty() } ?: permalinkData.viaParameters ).also { diff --git a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToRoomSpaceFragment.kt b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToRoomSpaceFragment.kt index 7a5a740b93..04f72000fa 100644 --- a/vector/src/main/java/im/vector/app/features/matrixto/MatrixToRoomSpaceFragment.kt +++ b/vector/src/main/java/im/vector/app/features/matrixto/MatrixToRoomSpaceFragment.kt @@ -21,7 +21,6 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.core.view.isGone -import androidx.core.view.isInvisible import androidx.core.view.isVisible import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading @@ -31,6 +30,7 @@ import com.airbnb.mvrx.parentFragmentViewModel import com.airbnb.mvrx.withState import im.vector.app.R import im.vector.app.core.extensions.setTextOrHide +import im.vector.app.core.platform.ButtonStateView import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.databinding.FragmentMatrixToRoomSpaceCardBinding import im.vector.app.features.home.AvatarRenderer @@ -50,11 +50,18 @@ class MatrixToRoomSpaceFragment @Inject constructor( override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - views.matrixToCardMainButton.debouncedClicks { - mainButtonClicked() + views.matrixToCardMainButton.callback = object : ButtonStateView.Callback { + override fun onButtonClicked() { + mainButtonClicked() + } + + override fun onRetryClicked() = onButtonClicked() } - views.matrixToCardSecondaryButton.debouncedClicks { - secondaryButtonClicked() + views.matrixToCardSecondaryButton.callback = object : ButtonStateView.Callback { + override fun onButtonClicked() { + secondaryButtonClicked() + } + override fun onRetryClicked() = onButtonClicked() } } @@ -164,16 +171,20 @@ class MatrixToRoomSpaceFragment @Inject constructor( when (state.peopleYouKnow) { is Success -> { val someYouKnow = state.peopleYouKnow.invoke() - someYouKnow.forEachIndexed { index, item -> - images[index].isVisible = true - avatarRenderer.render(item, images[index]) + if (someYouKnow.isEmpty()) { + views.peopleYouMayKnowText.isVisible = false + } else { + someYouKnow.forEachIndexed { index, item -> + images[index].isVisible = true + avatarRenderer.render(item, images[index]) + } + views.peopleYouMayKnowText.setTextOrHide( + resources.getQuantityString(R.plurals.space_people_you_know, + someYouKnow.count(), + someYouKnow.count() + ) + ) } - views.peopleYouMayKnowText.setTextOrHide( - resources.getQuantityString(R.plurals.space_people_you_know, - someYouKnow.count(), - someYouKnow.count() - ) - ) } else -> { views.peopleYouMayKnowText.isVisible = false @@ -182,21 +193,17 @@ class MatrixToRoomSpaceFragment @Inject constructor( when (state.startChattingState) { Uninitialized -> { - views.matrixToCardButtonLoading.isVisible = false -// views.matrixToCardMainButton.isVisible = false + views.matrixToCardMainButton.render(ButtonStateView.State.Button) } is Success -> { - views.matrixToCardButtonLoading.isVisible = false - views.matrixToCardMainButton.isVisible = true + views.matrixToCardMainButton.render(ButtonStateView.State.Button) } is Fail -> { - views.matrixToCardButtonLoading.isVisible = false - views.matrixToCardMainButton.isVisible = true + views.matrixToCardMainButton.render(ButtonStateView.State.Error) // TODO display some error copy? } is Loading -> { - views.matrixToCardButtonLoading.isVisible = true - views.matrixToCardMainButton.isInvisible = true + views.matrixToCardMainButton.render(ButtonStateView.State.Loading) } } } diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceExploreActivity.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceExploreActivity.kt index e07896de50..dbe92d4d93 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceExploreActivity.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceExploreActivity.kt @@ -19,6 +19,8 @@ package im.vector.app.features.spaces import android.content.Context import android.content.Intent import android.os.Bundle +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager import com.airbnb.mvrx.MvRx import com.airbnb.mvrx.viewModel import im.vector.app.R @@ -26,6 +28,7 @@ import im.vector.app.core.di.ScreenComponent import im.vector.app.core.extensions.commitTransaction import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.databinding.ActivitySimpleBinding +import im.vector.app.features.matrixto.MatrixToBottomSheet import im.vector.app.features.spaces.explore.SpaceDirectoryArgs import im.vector.app.features.spaces.explore.SpaceDirectoryFragment import im.vector.app.features.spaces.explore.SpaceDirectoryState @@ -33,7 +36,7 @@ import im.vector.app.features.spaces.explore.SpaceDirectoryViewEvents import im.vector.app.features.spaces.explore.SpaceDirectoryViewModel import javax.inject.Inject -class SpaceExploreActivity : VectorBaseActivity(), SpaceDirectoryViewModel.Factory { +class SpaceExploreActivity : VectorBaseActivity(), SpaceDirectoryViewModel.Factory, MatrixToBottomSheet.InteractionListener { @Inject lateinit var spaceDirectoryViewModelFactory: SpaceDirectoryViewModel.Factory @@ -47,8 +50,25 @@ class SpaceExploreActivity : VectorBaseActivity(), SpaceD val sharedViewModel: SpaceDirectoryViewModel by viewModel() + private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() { + override fun onFragmentAttached(fm: FragmentManager, f: Fragment, context: Context) { + if (f is MatrixToBottomSheet) { + f.interactionListener = this@SpaceExploreActivity + } + super.onFragmentAttached(fm, f, context) + } + + override fun onFragmentDetached(fm: FragmentManager, f: Fragment) { + if (f is MatrixToBottomSheet) { + f.interactionListener = null + } + super.onFragmentDetached(fm, f) + } + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, false) if (isFirstCreation()) { val simpleName = SpaceDirectoryFragment::class.java.simpleName @@ -72,10 +92,18 @@ class SpaceExploreActivity : VectorBaseActivity(), SpaceD is SpaceDirectoryViewEvents.NavigateToRoom -> { navigator.openRoom(this, it.roomId) } + is SpaceDirectoryViewEvents.NavigateToMxToBottomSheet -> { + MatrixToBottomSheet.withLink(it.link, this).show(supportFragmentManager, "ShowChild") + } } } } + override fun onDestroy() { + supportFragmentManager.unregisterFragmentLifecycleCallbacks(fragmentLifecycleCallbacks) + super.onDestroy() + } + companion object { fun newIntent(context: Context, spaceId: String): Intent { return Intent(context, SpaceExploreActivity::class.java).apply { @@ -86,4 +114,8 @@ class SpaceExploreActivity : VectorBaseActivity(), SpaceD override fun create(initialState: SpaceDirectoryState): SpaceDirectoryViewModel = spaceDirectoryViewModelFactory.create(initialState) + + override fun navigateToRoom(roomId: String) { + navigator.openRoom(this, roomId) + } } diff --git a/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryController.kt b/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryController.kt index 44d98766d5..f8e45dcd5e 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryController.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryController.kt @@ -38,6 +38,7 @@ class SpaceDirectoryController @Inject constructor( interface InteractionListener { fun onButtonClick(spaceChildInfo: SpaceChildInfo) fun onSpaceChildClick(spaceChildInfo: SpaceChildInfo) + fun onRoomClick(spaceChildInfo: SpaceChildInfo) } var listener: InteractionListener? = null @@ -81,6 +82,8 @@ class SpaceDirectoryController @Inject constructor( apply { if (isSpace) { itemClickListener(View.OnClickListener { listener?.onSpaceChildClick(info) }) + } else { + itemClickListener(View.OnClickListener { listener?.onRoomClick(info) }) } } buttonClickListener(View.OnClickListener { listener?.onButtonClick(info) }) diff --git a/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryFragment.kt b/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryFragment.kt index 567012675e..41ab8d9006 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryFragment.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryFragment.kt @@ -23,13 +23,13 @@ import android.view.View import android.view.ViewGroup import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.withState +import im.vector.app.R import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.OnBackPressed import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.databinding.FragmentRoomDirectoryPickerBinding import kotlinx.parcelize.Parcelize -import org.matrix.android.sdk.api.session.room.model.RoomType import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo import javax.inject.Inject @@ -68,8 +68,13 @@ class SpaceDirectoryFragment @Inject constructor( super.onDestroyView() } - override fun invalidate() = withState(viewModel) { - epoxyController.setData(it) + override fun invalidate() = withState(viewModel) { state -> + epoxyController.setData(state) + + val title = state.hierarchyStack.lastOrNull()?.let { currentParent -> + state.spaceSummaryApiResult.invoke()?.firstOrNull { it.childRoomId == currentParent } + }?.name ?: getString(R.string.space_explore_activity_title) + views.toolbar.title = title } override fun onButtonClick(spaceChildInfo: SpaceChildInfo) { @@ -77,13 +82,19 @@ class SpaceDirectoryFragment @Inject constructor( } override fun onSpaceChildClick(spaceChildInfo: SpaceChildInfo) { - if (spaceChildInfo.roomType == RoomType.SPACE) { - viewModel.handle(SpaceDirectoryViewAction.ExploreSubSpace(spaceChildInfo)) - } + viewModel.handle(SpaceDirectoryViewAction.ExploreSubSpace(spaceChildInfo)) + } + + override fun onRoomClick(spaceChildInfo: SpaceChildInfo) { + viewModel.handle(SpaceDirectoryViewAction.ShowDetails(spaceChildInfo)) } override fun onBackPressed(toolbarButton: Boolean): Boolean { viewModel.handle(SpaceDirectoryViewAction.HandleBack) return true } + +// override fun navigateToRoom(roomId: String) { +// viewModel.handle(SpaceDirectoryViewAction.NavigateToRoom(roomId)) +// } } diff --git a/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryViewAction.kt b/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryViewAction.kt index a74662759e..a7e1482e24 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryViewAction.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryViewAction.kt @@ -22,5 +22,7 @@ import org.matrix.android.sdk.api.session.room.model.SpaceChildInfo sealed class SpaceDirectoryViewAction : VectorViewModelAction { data class ExploreSubSpace(val spaceChildInfo: SpaceChildInfo) : SpaceDirectoryViewAction() data class JoinOrOpen(val spaceChildInfo: SpaceChildInfo) : SpaceDirectoryViewAction() + data class ShowDetails(val spaceChildInfo: SpaceChildInfo) : SpaceDirectoryViewAction() + data class NavigateToRoom(val roomId: String) : SpaceDirectoryViewAction() object HandleBack : SpaceDirectoryViewAction() } diff --git a/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryViewEvents.kt b/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryViewEvents.kt index ef6f5385d3..3ac0426de9 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryViewEvents.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryViewEvents.kt @@ -21,4 +21,5 @@ import im.vector.app.core.platform.VectorViewEvents sealed class SpaceDirectoryViewEvents : VectorViewEvents { object Dismiss : SpaceDirectoryViewEvents() data class NavigateToRoom(val roomId: String) : SpaceDirectoryViewEvents() + data class NavigateToMxToBottomSheet(val link: String) : SpaceDirectoryViewEvents() } diff --git a/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryViewModel.kt b/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryViewModel.kt index fbe405e641..9d74849386 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/explore/SpaceDirectoryViewModel.kt @@ -91,6 +91,7 @@ class SpaceDirectoryViewModel @AssistedInject constructor( private fun observeJoinedRooms() { val queryParams = roomSummaryQueryParams { memberships = listOf(Membership.JOIN) + excludeType = null } session .rx() @@ -135,6 +136,16 @@ class SpaceDirectoryViewModel @AssistedInject constructor( is SpaceDirectoryViewAction.JoinOrOpen -> { handleJoinOrOpen(action.spaceChildInfo) } + is SpaceDirectoryViewAction.NavigateToRoom -> { + _viewEvents.post(SpaceDirectoryViewEvents.NavigateToRoom(action.roomId)) + } + is SpaceDirectoryViewAction.ShowDetails -> { + // This is temporary for now to at least display something for the space beta + // It's not ideal as it's doing some peeking that is not needed. + session.permalinkService().createRoomPermalink(action.spaceChildInfo.childRoomId)?.let { + _viewEvents.post(SpaceDirectoryViewEvents.NavigateToMxToBottomSheet(it)) + } + } } }