Merge pull request #4101 from vector-im/feature/bca/spaces_fix_3932

Add "Create room" shortcut in Explore Space screen
This commit is contained in:
Benoit Marty 2022-01-13 13:44:35 +01:00 committed by GitHub
commit 1c948c19af
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 261 additions and 48 deletions

1
changelog.d/3932.bugfix Normal file
View File

@ -0,0 +1 @@
Explore Rooms overflow menu - content update include "Create room"

View File

@ -309,8 +309,8 @@ class DefaultNavigator @Inject constructor(
} }
} }
override fun openCreateRoom(context: Context, initialName: String) { override fun openCreateRoom(context: Context, initialName: String, openAfterCreate: Boolean) {
val intent = CreateRoomActivity.getIntent(context, initialName) val intent = CreateRoomActivity.getIntent(context = context, initialName = initialName, openAfterCreate = openAfterCreate)
context.startActivity(intent) context.startActivity(intent)
} }

View File

@ -76,7 +76,7 @@ interface Navigator {
fun openMatrixToBottomSheet(context: Context, link: String) fun openMatrixToBottomSheet(context: Context, link: String)
fun openCreateRoom(context: Context, initialName: String = "") fun openCreateRoom(context: Context, initialName: String = "", openAfterCreate: Boolean = true)
fun openCreateDirectRoom(context: Context) fun openCreateDirectRoom(context: Context)

View File

@ -25,5 +25,6 @@ sealed class RoomDirectorySharedAction : VectorSharedAction {
object Back : RoomDirectorySharedAction() object Back : RoomDirectorySharedAction()
object CreateRoom : RoomDirectorySharedAction() object CreateRoom : RoomDirectorySharedAction()
object Close : RoomDirectorySharedAction() object Close : RoomDirectorySharedAction()
data class CreateRoomSuccess(val createdRoomId: String) : RoomDirectorySharedAction()
object ChangeProtocol : RoomDirectorySharedAction() object ChangeProtocol : RoomDirectorySharedAction()
} }

View File

@ -16,10 +16,12 @@
package im.vector.app.features.roomdirectory.createroom package im.vector.app.features.roomdirectory.createroom
import android.app.Activity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import com.airbnb.mvrx.Mavericks
import com.google.android.material.appbar.MaterialToolbar import com.google.android.material.appbar.MaterialToolbar
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.extensions.addFragment import im.vector.app.core.extensions.addFragment
@ -49,13 +51,11 @@ class CreateRoomActivity : VectorBaseActivity<ActivitySimpleBinding>(), ToolbarC
override fun initUiAndData() { override fun initUiAndData() {
if (isFirstCreation()) { if (isFirstCreation()) {
val fragmentArgs: CreateRoomArgs = intent?.extras?.getParcelable(Mavericks.KEY_ARG) ?: return
addFragment( addFragment(
views.simpleFragmentContainer, views.simpleFragmentContainer,
CreateRoomFragment::class.java, CreateRoomFragment::class.java,
CreateRoomArgs( fragmentArgs
intent?.getStringExtra(INITIAL_NAME) ?: "",
isSpace = intent?.getBooleanExtra(IS_SPACE, false) ?: false
)
) )
} }
} }
@ -68,21 +68,40 @@ class CreateRoomActivity : VectorBaseActivity<ActivitySimpleBinding>(), ToolbarC
.onEach { sharedAction -> .onEach { sharedAction ->
when (sharedAction) { when (sharedAction) {
is RoomDirectorySharedAction.Back, is RoomDirectorySharedAction.Back,
is RoomDirectorySharedAction.Close -> finish() is RoomDirectorySharedAction.Close -> finish()
is RoomDirectorySharedAction.CreateRoomSuccess -> {
setResult(Activity.RESULT_OK, Intent().apply { putExtra(RESULT_CREATED_ROOM_ID, sharedAction.createdRoomId) })
finish()
}
else -> {
// nop
}
} }
} }
.launchIn(lifecycleScope) .launchIn(lifecycleScope)
} }
companion object { companion object {
private const val INITIAL_NAME = "INITIAL_NAME"
private const val IS_SPACE = "IS_SPACE"
fun getIntent(context: Context, initialName: String = "", isSpace: Boolean = false): Intent { private const val RESULT_CREATED_ROOM_ID = "RESULT_CREATED_ROOM_ID"
fun getIntent(context: Context,
initialName: String = "",
isSpace: Boolean = false,
openAfterCreate: Boolean = true,
currentSpaceId: String? = null): Intent {
return Intent(context, CreateRoomActivity::class.java).apply { return Intent(context, CreateRoomActivity::class.java).apply {
putExtra(INITIAL_NAME, initialName) putExtra(Mavericks.KEY_ARG, CreateRoomArgs(
putExtra(IS_SPACE, isSpace) initialName = initialName,
isSpace = isSpace,
openAfterCreate = openAfterCreate,
parentSpaceId = currentSpaceId
))
} }
} }
fun getCreatedRoomId(data: Intent?): String? {
return data?.extras?.getString(RESULT_CREATED_ROOM_ID)
}
} }
} }

View File

@ -56,7 +56,8 @@ import javax.inject.Inject
data class CreateRoomArgs( data class CreateRoomArgs(
val initialName: String, val initialName: String,
val parentSpaceId: String? = null, val parentSpaceId: String? = null,
val isSpace: Boolean = false val isSpace: Boolean = false,
val openAfterCreate: Boolean = true
) : Parcelable ) : Parcelable
class CreateRoomFragment @Inject constructor( class CreateRoomFragment @Inject constructor(
@ -226,16 +227,19 @@ class CreateRoomFragment @Inject constructor(
views.waitingView.root.isVisible = async is Loading views.waitingView.root.isVisible = async is Loading
if (async is Success) { if (async is Success) {
// Navigate to freshly created room // Navigate to freshly created room
if (state.isSubSpace) { if (state.openAfterCreate) {
navigator.switchToSpace( if (state.isSubSpace) {
requireContext(), navigator.switchToSpace(
async(), requireContext(),
Navigator.PostSwitchSpaceAction.None async(),
) Navigator.PostSwitchSpaceAction.None
} else { )
navigator.openRoom(requireActivity(), async()) } else {
navigator.openRoom(requireActivity(), async())
}
} }
sharedActionViewModel.post(RoomDirectorySharedAction.CreateRoomSuccess(async()))
sharedActionViewModel.post(RoomDirectorySharedAction.Close) sharedActionViewModel.post(RoomDirectorySharedAction.Close)
} else { } else {
// Populate list with Epoxy // Populate list with Epoxy

View File

@ -25,6 +25,7 @@ import com.airbnb.mvrx.Uninitialized
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import im.vector.app.AppStateHandler
import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.MavericksAssistedViewModelFactory
import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory
import im.vector.app.core.extensions.exhaustive import im.vector.app.core.extensions.exhaustive
@ -53,7 +54,8 @@ import timber.log.Timber
class CreateRoomViewModel @AssistedInject constructor(@Assisted private val initialState: CreateRoomViewState, class CreateRoomViewModel @AssistedInject constructor(@Assisted private val initialState: CreateRoomViewState,
private val session: Session, private val session: Session,
private val rawService: RawService private val rawService: RawService,
appStateHandler: AppStateHandler
) : VectorViewModel<CreateRoomViewState, CreateRoomAction, CreateRoomViewEvents>(initialState) { ) : VectorViewModel<CreateRoomViewState, CreateRoomAction, CreateRoomViewEvents>(initialState) {
@AssistedFactory @AssistedFactory
@ -67,10 +69,12 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted private val init
initHomeServerName() initHomeServerName()
initAdminE2eByDefault() initAdminE2eByDefault()
val parentSpaceId = initialState.parentSpaceId ?: appStateHandler.safeActiveSpaceId()
val restrictedSupport = session.getHomeServerCapabilities().isFeatureSupported(HomeServerCapabilities.ROOM_CAP_RESTRICTED) val restrictedSupport = session.getHomeServerCapabilities().isFeatureSupported(HomeServerCapabilities.ROOM_CAP_RESTRICTED)
val createRestricted = restrictedSupport == HomeServerCapabilities.RoomCapabilitySupport.SUPPORTED val createRestricted = restrictedSupport == HomeServerCapabilities.RoomCapabilitySupport.SUPPORTED
val defaultJoinRules = if (initialState.parentSpaceId != null && createRestricted) { val defaultJoinRules = if (parentSpaceId != null && createRestricted) {
RoomJoinRules.RESTRICTED RoomJoinRules.RESTRICTED
} else { } else {
RoomJoinRules.INVITE RoomJoinRules.INVITE
@ -78,9 +82,10 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted private val init
setState { setState {
copy( copy(
parentSpaceId = parentSpaceId,
supportsRestricted = createRestricted, supportsRestricted = createRestricted,
roomJoinRules = defaultJoinRules, roomJoinRules = defaultJoinRules,
parentSpaceSummary = initialState.parentSpaceId?.let { session.getRoomSummary(it) } parentSpaceSummary = parentSpaceId?.let { session.getRoomSummary(it) }
) )
} }
} }
@ -156,7 +161,7 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted private val init
CreateRoomViewState( CreateRoomViewState(
isEncrypted = adminE2EByDefault, isEncrypted = adminE2EByDefault,
hsAdminHasDisabledE2E = !adminE2EByDefault, hsAdminHasDisabledE2E = !adminE2EByDefault,
parentSpaceId = initialState.parentSpaceId parentSpaceId = this.parentSpaceId
) )
} }
@ -292,11 +297,11 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted private val init
runCatching { session.createRoom(createRoomParams) }.fold( runCatching { session.createRoom(createRoomParams) }.fold(
{ roomId -> { roomId ->
if (initialState.parentSpaceId != null) { if (state.parentSpaceId != null) {
// add it as a child // add it as a child
try { try {
session.spaceService() session.spaceService()
.getSpace(initialState.parentSpaceId) .getSpace(state.parentSpaceId)
?.addChildren(roomId, viaServers = null, order = null) ?.addChildren(roomId, viaServers = null, order = null)
} catch (failure: Throwable) { } catch (failure: Throwable) {
Timber.w(failure, "Failed to add as a child") Timber.w(failure, "Failed to add as a child")

View File

@ -39,13 +39,15 @@ data class CreateRoomViewState(
val parentSpaceSummary: RoomSummary? = null, val parentSpaceSummary: RoomSummary? = null,
val supportsRestricted: Boolean = false, val supportsRestricted: Boolean = false,
val aliasLocalPart: String? = null, val aliasLocalPart: String? = null,
val isSubSpace: Boolean = false val isSubSpace: Boolean = false,
val openAfterCreate: Boolean = true
) : MavericksState { ) : MavericksState {
constructor(args: CreateRoomArgs) : this( constructor(args: CreateRoomArgs) : this(
roomName = args.initialName, roomName = args.initialName,
parentSpaceId = args.parentSpaceId, parentSpaceId = args.parentSpaceId,
isSubSpace = args.isSpace isSubSpace = args.isSpace,
openAfterCreate = args.openAfterCreate
) )
/** /**

View File

@ -16,6 +16,7 @@
package im.vector.app.features.spaces package im.vector.app.features.spaces
import android.app.Activity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
@ -25,13 +26,16 @@ import com.airbnb.mvrx.Mavericks
import com.airbnb.mvrx.viewModel import com.airbnb.mvrx.viewModel
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.extensions.registerStartForActivityResult
import im.vector.app.core.extensions.replaceFragment import im.vector.app.core.extensions.replaceFragment
import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.databinding.ActivitySimpleBinding import im.vector.app.databinding.ActivitySimpleBinding
import im.vector.app.features.matrixto.MatrixToBottomSheet import im.vector.app.features.matrixto.MatrixToBottomSheet
import im.vector.app.features.navigation.Navigator import im.vector.app.features.navigation.Navigator
import im.vector.app.features.roomdirectory.createroom.CreateRoomActivity
import im.vector.app.features.spaces.explore.SpaceDirectoryArgs import im.vector.app.features.spaces.explore.SpaceDirectoryArgs
import im.vector.app.features.spaces.explore.SpaceDirectoryFragment import im.vector.app.features.spaces.explore.SpaceDirectoryFragment
import im.vector.app.features.spaces.explore.SpaceDirectoryViewAction
import im.vector.app.features.spaces.explore.SpaceDirectoryViewEvents import im.vector.app.features.spaces.explore.SpaceDirectoryViewEvents
import im.vector.app.features.spaces.explore.SpaceDirectoryViewModel import im.vector.app.features.spaces.explore.SpaceDirectoryViewModel
@ -44,6 +48,15 @@ class SpaceExploreActivity : VectorBaseActivity<ActivitySimpleBinding>(), Matrix
val sharedViewModel: SpaceDirectoryViewModel by viewModel() val sharedViewModel: SpaceDirectoryViewModel by viewModel()
private val createRoomResultLauncher = registerStartForActivityResult { activityResult ->
if (activityResult.resultCode == Activity.RESULT_OK) {
CreateRoomActivity.getCreatedRoomId(activityResult.data)?.let {
// we want to refresh from API
sharedViewModel.handle(SpaceDirectoryViewAction.RefreshUntilFound(it))
}
}
}
private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() { private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentResumed(fm: FragmentManager, f: Fragment) { override fun onFragmentResumed(fm: FragmentManager, f: Fragment) {
if (f is MatrixToBottomSheet) { if (f is MatrixToBottomSheet) {
@ -84,6 +97,13 @@ class SpaceExploreActivity : VectorBaseActivity<ActivitySimpleBinding>(), Matrix
is SpaceDirectoryViewEvents.NavigateToMxToBottomSheet -> { is SpaceDirectoryViewEvents.NavigateToMxToBottomSheet -> {
MatrixToBottomSheet.withLink(it.link).show(supportFragmentManager, "ShowChild") MatrixToBottomSheet.withLink(it.link).show(supportFragmentManager, "ShowChild")
} }
is SpaceDirectoryViewEvents.NavigateToCreateNewRoom -> {
createRoomResultLauncher.launch(CreateRoomActivity.getIntent(
this,
openAfterCreate = false,
currentSpaceId = it.currentSpaceId
))
}
} }
} }
} }

View File

@ -26,6 +26,7 @@ import android.view.ViewGroup
import androidx.core.text.toSpannable import androidx.core.text.toSpannable
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.RecyclerView
import com.airbnb.epoxy.EpoxyVisibilityTracker import com.airbnb.epoxy.EpoxyVisibilityTracker
import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.withState import com.airbnb.mvrx.withState
@ -83,13 +84,16 @@ class SpaceDirectoryFragment @Inject constructor(
bundle.getString(SpaceAddRoomSpaceChooserBottomSheet.BUNDLE_KEY_ACTION)?.let { action -> bundle.getString(SpaceAddRoomSpaceChooserBottomSheet.BUNDLE_KEY_ACTION)?.let { action ->
val spaceId = withState(viewModel) { it.spaceId } val spaceId = withState(viewModel) { it.spaceId }
when (action) { when (action) {
SpaceAddRoomSpaceChooserBottomSheet.ACTION_ADD_ROOMS -> { SpaceAddRoomSpaceChooserBottomSheet.ACTION_ADD_ROOMS -> {
addExistingRoomActivityResult.launch(SpaceManageActivity.newIntent(requireContext(), spaceId, ManageType.AddRooms)) addExistingRoomActivityResult.launch(SpaceManageActivity.newIntent(requireContext(), spaceId, ManageType.AddRooms))
} }
SpaceAddRoomSpaceChooserBottomSheet.ACTION_ADD_SPACES -> { SpaceAddRoomSpaceChooserBottomSheet.ACTION_ADD_SPACES -> {
addExistingRoomActivityResult.launch(SpaceManageActivity.newIntent(requireContext(), spaceId, ManageType.AddRoomsOnlySpaces)) addExistingRoomActivityResult.launch(SpaceManageActivity.newIntent(requireContext(), spaceId, ManageType.AddRoomsOnlySpaces))
} }
else -> { SpaceAddRoomSpaceChooserBottomSheet.ACTION_CREATE_ROOM -> {
viewModel.handle(SpaceDirectoryViewAction.CreateNewRoom)
}
else -> {
// nop // nop
} }
} }
@ -114,8 +118,32 @@ class SpaceDirectoryFragment @Inject constructor(
invalidateOptionsMenu() invalidateOptionsMenu()
} }
views.addOrCreateChatRoomButton.debouncedClicks {
withState(viewModel) {
addExistingRooms(it.spaceId)
}
}
views.spaceCard.matrixToCardMainButton.isVisible = false views.spaceCard.matrixToCardMainButton.isVisible = false
views.spaceCard.matrixToCardSecondaryButton.isVisible = false views.spaceCard.matrixToCardSecondaryButton.isVisible = false
// Hide FAB when list is scrolling
views.spaceDirectoryList.addOnScrollListener(
object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
views.addOrCreateChatRoomButton.removeCallbacks(showFabRunnable)
when (newState) {
RecyclerView.SCROLL_STATE_IDLE -> {
views.addOrCreateChatRoomButton.postDelayed(showFabRunnable, 250)
}
RecyclerView.SCROLL_STATE_DRAGGING,
RecyclerView.SCROLL_STATE_SETTLING -> {
views.addOrCreateChatRoomButton.hide()
}
}
}
})
} }
override fun onDestroyView() { override fun onDestroyView() {
@ -125,6 +153,12 @@ class SpaceDirectoryFragment @Inject constructor(
super.onDestroyView() super.onDestroyView()
} }
private val showFabRunnable = Runnable {
if (isAdded) {
views.addOrCreateChatRoomButton.show()
}
}
override fun invalidate() = withState(viewModel) { state -> override fun invalidate() = withState(viewModel) { state ->
epoxyController.setData(state) epoxyController.setData(state)
@ -142,6 +176,7 @@ class SpaceDirectoryFragment @Inject constructor(
} }
spaceCardRenderer.render(state.currentRootSummary, emptyList(), this, views.spaceCard) spaceCardRenderer.render(state.currentRootSummary, emptyList(), this, views.spaceCard)
views.addOrCreateChatRoomButton.isVisible = state.canAddRooms
} }
override fun onPrepareOptionsMenu(menu: Menu) = withState(viewModel) { state -> override fun onPrepareOptionsMenu(menu: Menu) = withState(viewModel) { state ->

View File

@ -24,7 +24,9 @@ sealed class SpaceDirectoryViewAction : VectorViewModelAction {
data class JoinOrOpen(val spaceChildInfo: SpaceChildInfo) : SpaceDirectoryViewAction() data class JoinOrOpen(val spaceChildInfo: SpaceChildInfo) : SpaceDirectoryViewAction()
data class ShowDetails(val spaceChildInfo: SpaceChildInfo) : SpaceDirectoryViewAction() data class ShowDetails(val spaceChildInfo: SpaceChildInfo) : SpaceDirectoryViewAction()
data class NavigateToRoom(val roomId: String) : SpaceDirectoryViewAction() data class NavigateToRoom(val roomId: String) : SpaceDirectoryViewAction()
object CreateNewRoom : SpaceDirectoryViewAction()
object HandleBack : SpaceDirectoryViewAction() object HandleBack : SpaceDirectoryViewAction()
object Retry : SpaceDirectoryViewAction() object Retry : SpaceDirectoryViewAction()
data class RefreshUntilFound(val roomIdToFind: String) : SpaceDirectoryViewAction()
object LoadAdditionalItemsIfNeeded : SpaceDirectoryViewAction() object LoadAdditionalItemsIfNeeded : SpaceDirectoryViewAction()
} }

View File

@ -22,4 +22,5 @@ sealed class SpaceDirectoryViewEvents : VectorViewEvents {
object Dismiss : SpaceDirectoryViewEvents() object Dismiss : SpaceDirectoryViewEvents()
data class NavigateToRoom(val roomId: String) : SpaceDirectoryViewEvents() data class NavigateToRoom(val roomId: String) : SpaceDirectoryViewEvents()
data class NavigateToMxToBottomSheet(val link: String) : SpaceDirectoryViewEvents() data class NavigateToMxToBottomSheet(val link: String) : SpaceDirectoryViewEvents()
data class NavigateToCreateNewRoom(val currentSpaceId: String) : SpaceDirectoryViewEvents()
} }

View File

@ -55,7 +55,9 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
override fun create(initialState: SpaceDirectoryState): SpaceDirectoryViewModel override fun create(initialState: SpaceDirectoryState): SpaceDirectoryViewModel
} }
companion object : MavericksViewModelFactory<SpaceDirectoryViewModel, SpaceDirectoryState> by hiltMavericksViewModelFactory() companion object : MavericksViewModelFactory<SpaceDirectoryViewModel, SpaceDirectoryState> by hiltMavericksViewModelFactory() {
private const val PAGE_LENGTH = 10
}
init { init {
@ -71,6 +73,27 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
observeJoinedRooms() observeJoinedRooms()
observeMembershipChanges() observeMembershipChanges()
observePermissions() observePermissions()
observeKnownSummaries()
}
private fun observeKnownSummaries() {
// A we prefer to use known summaries to have better name resolution
// it's important to have them up to date. Particularly after creation where
// resolved name is sometimes just "New Room"
session.flow().liveRoomSummaries(
roomSummaryQueryParams {
memberships = listOf(Membership.JOIN)
includeType = null
}
).execute {
val updatedRoomSummaries = it
copy(
knownRoomSummaries = this.knownRoomSummaries.map { rs ->
updatedRoomSummaries.invoke()?.firstOrNull { it.roomId == rs.roomId }
?: rs
}
)
}
} }
private fun observePermissions() { private fun observePermissions() {
@ -103,7 +126,7 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
try { try {
val query = session.spaceService().querySpaceChildren( val query = session.spaceService().querySpaceChildren(
spaceId, spaceId,
limit = 10 limit = PAGE_LENGTH
) )
val knownSummaries = query.children.mapNotNull { val knownSummaries = query.children.mapNotNull {
session.getRoomSummary(it.childRoomId) session.getRoomSummary(it.childRoomId)
@ -181,9 +204,17 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
SpaceDirectoryViewAction.Retry -> { SpaceDirectoryViewAction.Retry -> {
handleRetry() handleRetry()
} }
is SpaceDirectoryViewAction.RefreshUntilFound -> {
handleRefreshUntilFound(action.roomIdToFind)
}
SpaceDirectoryViewAction.LoadAdditionalItemsIfNeeded -> { SpaceDirectoryViewAction.LoadAdditionalItemsIfNeeded -> {
loadAdditionalItemsIfNeeded() loadAdditionalItemsIfNeeded()
} }
is SpaceDirectoryViewAction.CreateNewRoom -> {
withState { state ->
_viewEvents.post(SpaceDirectoryViewEvents.NavigateToCreateNewRoom(state.currentRootSummary?.roomId ?: initialState.spaceId))
}
}
} }
} }
@ -207,6 +238,66 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
refreshFromApi(state.hierarchyStack.lastOrNull() ?: initialState.spaceId) refreshFromApi(state.hierarchyStack.lastOrNull() ?: initialState.spaceId)
} }
private fun handleRefreshUntilFound(roomIdToFind: String?) = withState { state ->
val currentRootId = state.hierarchyStack.lastOrNull() ?: initialState.spaceId
val mutablePaginationStatus = state.paginationStatus.toMutableMap().apply {
this[currentRootId] = Loading()
}
// mark as paginating
setState {
copy(
paginationStatus = mutablePaginationStatus
)
}
viewModelScope.launch(Dispatchers.IO) {
var query = session.spaceService().querySpaceChildren(
currentRootId,
limit = PAGE_LENGTH
)
var knownSummaries = query.children.mapNotNull {
session.getRoomSummary(it.childRoomId)
?.takeIf { it.membership == Membership.JOIN } // only take if joined because it will be up to date (synced)
}.distinctBy { it.roomId }
while (!query.children.any { it.childRoomId == roomIdToFind } && query.nextToken != null) {
// continue to paginate until found
val paginate = session.spaceService().querySpaceChildren(
currentRootId,
limit = PAGE_LENGTH,
from = query.nextToken,
knownStateList = query.childrenState
)
knownSummaries = (
knownSummaries +
(paginate.children.mapNotNull {
session.getRoomSummary(it.childRoomId)
?.takeIf { it.membership == Membership.JOIN } // only take if joined because it will be up to date (synced)
})
).distinctBy { it.roomId }
query = query.copy(
children = query.children + paginate.children,
nextToken = paginate.nextToken
)
}
setState {
copy(
apiResults = this.apiResults.toMutableMap().apply {
this[currentRootId] = Success(query)
},
paginationStatus = this.paginationStatus.toMutableMap().apply { this[currentRootId] = Success(Unit) }.toMap(),
knownRoomSummaries = (state.knownRoomSummaries + knownSummaries).distinctBy { it.roomId },
)
}
}
}
private fun handleExploreSubSpace(action: SpaceDirectoryViewAction.ExploreSubSpace) = withState { state -> private fun handleExploreSubSpace(action: SpaceDirectoryViewAction.ExploreSubSpace) = withState { state ->
val newRootId = action.spaceChildInfo.childRoomId val newRootId = action.spaceChildInfo.childRoomId
val curSum = RoomSummary( val curSum = RoomSummary(
@ -252,7 +343,9 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
if (mutablePaginationStatus[currentRootId] is Loading) return@withState if (mutablePaginationStatus[currentRootId] is Loading) return@withState
setState { setState {
copy(paginationStatus = mutablePaginationStatus.toMap()) copy(paginationStatus = mutablePaginationStatus.apply {
this[currentRootId] = Loading()
})
} }
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
@ -268,7 +361,7 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
} }
val query = session.spaceService().querySpaceChildren( val query = session.spaceService().querySpaceChildren(
currentRootId, currentRootId,
limit = 10, limit = PAGE_LENGTH,
from = currentResponse.nextToken, from = currentResponse.nextToken,
knownStateList = currentResponse.childrenState knownStateList = currentResponse.childrenState
) )

View File

@ -34,6 +34,13 @@ class SpaceAddRoomSpaceChooserBottomSheet : VectorBaseBottomSheetDialogFragment<
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
views.createRooms.views.bottomSheetActionClickableZone.debouncedClicks {
setFragmentResult(REQUEST_KEY, Bundle().apply {
putString(BUNDLE_KEY_ACTION, ACTION_CREATE_ROOM)
})
dismiss()
}
views.addSpaces.views.bottomSheetActionClickableZone.debouncedClicks { views.addSpaces.views.bottomSheetActionClickableZone.debouncedClicks {
setFragmentResult(REQUEST_KEY, Bundle().apply { setFragmentResult(REQUEST_KEY, Bundle().apply {
putString(BUNDLE_KEY_ACTION, ACTION_ADD_SPACES) putString(BUNDLE_KEY_ACTION, ACTION_ADD_SPACES)
@ -55,6 +62,7 @@ class SpaceAddRoomSpaceChooserBottomSheet : VectorBaseBottomSheetDialogFragment<
const val BUNDLE_KEY_ACTION = "SpaceAddRoomSpaceChooserBottomSheet.Action" const val BUNDLE_KEY_ACTION = "SpaceAddRoomSpaceChooserBottomSheet.Action"
const val ACTION_ADD_ROOMS = "Action.AddRoom" const val ACTION_ADD_ROOMS = "Action.AddRoom"
const val ACTION_ADD_SPACES = "Action.AddSpaces" const val ACTION_ADD_SPACES = "Action.AddSpaces"
const val ACTION_CREATE_ROOM = "Action.CreateRoom"
fun newInstance(): SpaceAddRoomSpaceChooserBottomSheet { fun newInstance(): SpaceAddRoomSpaceChooserBottomSheet {
return SpaceAddRoomSpaceChooserBottomSheet() return SpaceAddRoomSpaceChooserBottomSheet()

View File

@ -7,24 +7,34 @@
android:background="?android:colorBackground" android:background="?android:colorBackground"
android:orientation="vertical"> android:orientation="vertical">
<TextView <!-- <TextView-->
android:id="@+id/headerText" <!-- android:id="@+id/headerText"-->
style="@style/Widget.Vector.TextView.Subtitle" <!-- style="@style/Widget.Vector.TextView.Subtitle"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- android:layout_marginTop="16dp"-->
<!-- android:layout_marginBottom="16dp"-->
<!-- android:gravity="center"-->
<!-- android:text="@string/space_add_rooms"-->
<!-- android:textColor="?vctr_content_primary"-->
<!-- android:textStyle="bold"-->
<!-- app:layout_constraintTop_toTopOf="parent" />-->
<im.vector.app.core.ui.views.BottomSheetActionButton
android:id="@+id/createRooms"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="16dp" app:actionTitle="@string/create_new_room"
android:layout_marginBottom="16dp" app:leftIcon="@drawable/ic_fab_add"
android:gravity="center" app:tint="?vctr_content_primary"
android:text="@string/space_add_existing_rooms" app:titleTextColor="?vctr_content_primary"
android:textColor="?vctr_content_primary" tools:actionDescription="" />
android:textStyle="bold"
app:layout_constraintTop_toTopOf="parent" />
<im.vector.app.core.ui.views.BottomSheetActionButton <im.vector.app.core.ui.views.BottomSheetActionButton
android:id="@+id/addRooms" android:id="@+id/addRooms"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:actionTitle="@string/space_add_child_title" app:actionTitle="@string/space_add_existing_rooms_only"
app:leftIcon="@drawable/ic_fab_add" app:leftIcon="@drawable/ic_fab_add"
app:tint="?vctr_content_primary" app:tint="?vctr_content_primary"
app:titleTextColor="?vctr_content_primary" app:titleTextColor="?vctr_content_primary"

View File

@ -51,4 +51,16 @@
app:layout_behavior="@string/appbar_scrolling_view_behavior" app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:listitem="@layout/item_room_directory" /> tools:listitem="@layout/item_room_directory" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/addOrCreateChatRoomButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp "
android:contentDescription="@string/a11y_create_room"
android:scaleType="center"
android:src="@drawable/ic_fab_add"
app:maxImageSize="20dp" />
</androidx.coordinatorlayout.widget.CoordinatorLayout> </androidx.coordinatorlayout.widget.CoordinatorLayout>