Merge branch 'feature/eric/new-layout-navigation' into feature/eric/new-layout-debug

# Conflicts:
#	vector/src/test/java/im/vector/app/features/navigation/DefaultNavigatorTest.kt
This commit is contained in:
ericdecanini 2022-08-19 14:33:49 +02:00
commit add7bd9052
17 changed files with 34 additions and 125 deletions

View File

@ -1 +1 @@
[New Layout] Adds space backstack for back navigation and space sheet header
[New Layout] Adds back navigation through spaces

View File

@ -42,20 +42,18 @@ interface SpaceStateHandler : DefaultLifecycleObserver {
* @param session the current active session
* @param persistNow if true, the current space will immediately be persisted in shared prefs
* @param isForwardNavigation whether this navigation is a forward action to properly handle backstack
* @param overriddenSpaceName overrides the display name of the space being set
*/
fun setCurrentSpace(
spaceId: String?,
session: Session? = null,
persistNow: Boolean = false,
isForwardNavigation: Boolean = true,
overriddenSpaceName: String? = null,
)
/**
* Gets the Space ID of the space on top of the backstack.
*
* May return null to indicate the All Chats space
* May return null to indicate the All Chats space.
*/
fun popSpaceBackstack(): String?

View File

@ -72,13 +72,10 @@ class SpaceStateHandlerImpl @Inject constructor(
session: Session?,
persistNow: Boolean,
isForwardNavigation: Boolean,
overriddenSpaceName: String?,
) {
val activeSession = session ?: activeSessionHolder.getSafeActiveSession() ?: return
val spaceToLeave = selectedSpaceDataSource.currentValue?.orNull()
val spaceToSet = spaceId?.let { activeSession.getRoomSummary(spaceId) }?.let {
if (overriddenSpaceName != null) it.copy(displayName = overriddenSpaceName) else it
}
val spaceToSet = spaceId?.let { activeSession.getRoomSummary(spaceId) }
val sameSpaceSelected = spaceId == spaceToLeave?.roomId
if (sameSpaceSelected) {

View File

@ -144,7 +144,6 @@ class HomeActivity :
private val createSpaceResultLauncher = registerStartForActivityResult { activityResult ->
if (activityResult.resultCode == Activity.RESULT_OK) {
val spaceId = SpaceCreationActivity.getCreatedSpaceId(activityResult.data)
val spaceName = SpaceCreationActivity.getCreatedSpaceName(activityResult.data)
val defaultRoomId = SpaceCreationActivity.getDefaultRoomId(activityResult.data)
val isJustMe = SpaceCreationActivity.isJustMeSpace(activityResult.data)
views.drawerLayout.closeDrawer(GravityCompat.START)
@ -162,7 +161,6 @@ class HomeActivity :
context = this,
spaceId = spaceId,
postSwitchOption,
overriddenSpaceName = spaceName,
)
roomListSharedActionViewModel.post(RoomListSharedAction.CloseBottomSheet)
}

View File

@ -180,13 +180,12 @@ class DefaultNavigator @Inject constructor(
context: Context,
spaceId: String,
postSwitchSpaceAction: Navigator.PostSwitchSpaceAction,
overriddenSpaceName: String?,
) {
if (sessionHolder.getSafeActiveSession()?.getRoomSummary(spaceId) == null) {
fatalError("Trying to open an unknown space $spaceId", vectorPreferences.failFast())
return
}
spaceStateHandler.setCurrentSpace(spaceId, overriddenSpaceName = overriddenSpaceName)
spaceStateHandler.setCurrentSpace(spaceId)
handlePostSwitchAction(context, spaceId, postSwitchSpaceAction)
}

View File

@ -72,7 +72,6 @@ interface Navigator {
context: Context,
spaceId: String,
postSwitchSpaceAction: PostSwitchSpaceAction,
overriddenSpaceName: String? = null,
)
fun openSpacePreview(context: Context, spaceId: String)

View File

@ -1,56 +0,0 @@
/*
* 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 android.content.Context
import android.widget.TextView
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
@EpoxyModelClass
abstract class NewSpaceListHeaderItem : VectorEpoxyModel<NewSpaceListHeaderItem.Holder>(R.layout.item_new_space_list_header) {
@EpoxyAttribute var currentSpace: String? = null
@EpoxyAttribute var spaceHistory: List<Pair<String?, String>> = emptyList()
override fun bind(holder: Holder) {
super.bind(holder)
holder.spaceHeader.text = buildSpaceHeaderText(holder.spaceHeader.context)
}
private fun buildSpaceHeaderText(context: Context): String {
val allChats = context.getString(R.string.all_chats)
var spaceHeaderText = allChats
val nonRootSpaceHistory = spaceHistory.filter { it.second.isNotEmpty() }
if (nonRootSpaceHistory.isNotEmpty()) {
spaceHeaderText += " > ${nonRootSpaceHistory.joinToString(" > ") { it.second }}"
}
if (currentSpace != null) {
spaceHeaderText += " > $currentSpace"
}
return spaceHeaderText
}
class Holder : VectorEpoxyHolder() {
val spaceHeader by bind<TextView>(R.id.space_header)
}
}

View File

@ -51,7 +51,6 @@ class NewSpaceSummaryController @Inject constructor(
nonNullViewState.selectedSpace,
nonNullViewState.rootSpacesOrdered,
nonNullViewState.homeAggregateCount,
nonNullViewState.spaceHistory,
)
}
@ -60,16 +59,9 @@ class NewSpaceSummaryController @Inject constructor(
selectedSpace: RoomSummary?,
rootSpaces: List<RoomSummary>?,
homeCount: RoomAggregateNotificationCount,
spaceHistory: List<Pair<String?, String>>,
) {
val host = this
newSpaceListHeaderItem {
id("space_list_header")
currentSpace(selectedSpace?.displayName)
spaceHistory(spaceHistory)
}
if (selectedSpace != null) {
addSubSpaces(selectedSpace, spaceSummaries, homeCount)
} else {

View File

@ -104,7 +104,6 @@ class SpaceCreationActivity : SimpleFragmentActivity() {
is CreateSpaceEvents.FinishSuccess -> {
setResult(RESULT_OK, Intent().apply {
putExtra(RESULT_DATA_CREATED_SPACE_ID, it.spaceId)
putExtra(RESULT_DATA_CREATED_SPACE_NAME, it.spaceName)
putExtra(RESULT_DATA_DEFAULT_ROOM_ID, it.defaultRoomId)
putExtra(RESULT_DATA_CREATED_SPACE_IS_JUST_ME, it.topology == SpaceTopology.JustMe)
})
@ -160,7 +159,6 @@ class SpaceCreationActivity : SimpleFragmentActivity() {
companion object {
private const val RESULT_DATA_CREATED_SPACE_ID = "RESULT_DATA_CREATED_SPACE_ID"
private const val RESULT_DATA_CREATED_SPACE_NAME = "RESULT_DATA_CREATED_SPACE_NAME"
private const val RESULT_DATA_DEFAULT_ROOM_ID = "RESULT_DATA_DEFAULT_ROOM_ID"
private const val RESULT_DATA_CREATED_SPACE_IS_JUST_ME = "RESULT_DATA_CREATED_SPACE_IS_JUST_ME"
@ -174,10 +172,6 @@ class SpaceCreationActivity : SimpleFragmentActivity() {
return data?.extras?.getString(RESULT_DATA_CREATED_SPACE_ID)
}
fun getCreatedSpaceName(data: Intent?): String? {
return data?.extras?.getString(RESULT_DATA_CREATED_SPACE_NAME)
}
fun getDefaultRoomId(data: Intent?): String? {
return data?.extras?.getString(RESULT_DATA_DEFAULT_ROOM_ID)
}

View File

@ -85,15 +85,10 @@ class SpaceListViewModel @AssistedInject constructor(
}
observeSpaceSummaries()
val spaceHistory = spaceStateHandler.getSpaceBackstack()
.map { it to it?.let { session.roomService().getRoomSummary(it)?.displayName }.orEmpty() }
spaceStateHandler.getSelectedSpaceFlow()
.distinctUntilChanged()
.setOnEach { selectedSpaceOption ->
copy(
selectedSpace = selectedSpaceOption.orNull(),
spaceHistory = spaceHistory,
)
copy(selectedSpace = selectedSpaceOption.orNull())
}
// XXX there should be a way to refactor this and share it

View File

@ -32,6 +32,5 @@ data class SpaceListViewState(
val spaceOrderInfo: Map<String, String?>? = null,
val spaceOrderLocalEchos: Map<String, String?>? = null,
val expandedStates: Map<String, Boolean> = emptyMap(),
val spaceHistory: List<Pair<String?, String>> = emptyList(), // List of space id to display name
val homeAggregateCount: RoomAggregateNotificationCount = RoomAggregateNotificationCount(0, 0)
) : MavericksState

View File

@ -25,7 +25,7 @@ sealed class CreateSpaceEvents : VectorViewEvents {
object NavigateToAdd3Pid : CreateSpaceEvents()
object NavigateToChoosePrivateType : CreateSpaceEvents()
object Dismiss : CreateSpaceEvents()
data class FinishSuccess(val spaceId: String, val spaceName: String, val defaultRoomId: String?, val topology: SpaceTopology?) : CreateSpaceEvents()
data class FinishSuccess(val spaceId: String, val defaultRoomId: String?, val topology: SpaceTopology?) : CreateSpaceEvents()
data class ShowModalError(val errorMessage: String) : CreateSpaceEvents()
object HideModalLoading : CreateSpaceEvents()
data class ShowModalLoading(val message: String?) : CreateSpaceEvents()

View File

@ -380,7 +380,6 @@ class CreateSpaceViewModel @AssistedInject constructor(
_viewEvents.post(
CreateSpaceEvents.FinishSuccess(
result.spaceId,
spaceName,
result.childIds.firstOrNull(),
state.spaceTopology
)
@ -394,7 +393,6 @@ class CreateSpaceViewModel @AssistedInject constructor(
_viewEvents.post(
CreateSpaceEvents.FinishSuccess(
result.spaceId,
spaceName,
result.childIds.firstOrNull(),
state.spaceTopology
)

View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/space_header"
style="@style/TextAppearance.Vector.Body.Medium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_space_item"
android:ellipsize="middle"
android:orientation="vertical"
android:padding="16dp"
android:singleLine="true"
android:text="@string/change_space"
android:textAllCaps="true"
android:textColor="?vctr_content_tertiary"
android:textSize="14sp"
tools:viewBindingIgnore="true" />

View File

@ -19,6 +19,7 @@ package im.vector.app.features.navigation
import im.vector.app.test.fakes.FakeActiveSessionHolder
import im.vector.app.test.fakes.FakeAnalyticsTracker
import im.vector.app.test.fakes.FakeContext
import im.vector.app.test.fakes.FakeDebugNavigator
import im.vector.app.test.fakes.FakeSpaceStateHandler
import im.vector.app.test.fakes.FakeSupportedVerificationMethodsProvider
import im.vector.app.test.fakes.FakeVectorFeatures
@ -36,6 +37,7 @@ internal class DefaultNavigatorTest {
private val supportedVerificationMethodsProvider = FakeSupportedVerificationMethodsProvider()
private val features = FakeVectorFeatures()
private val analyticsTracker = FakeAnalyticsTracker()
private val debugNavigator = FakeDebugNavigator()
private val navigator = DefaultNavigator(
sessionHolder.instance,
@ -45,10 +47,11 @@ internal class DefaultNavigatorTest {
supportedVerificationMethodsProvider.instance,
features,
analyticsTracker,
debugNavigator,
)
/**
* The below tests are by no means all that we want to test in [DefaultNavigator].
* The below test is by no means all that we want to test in [DefaultNavigator].
* Please add relevant tests as you make changes to or related to other functions in the class.
*/
@ -62,16 +65,4 @@ internal class DefaultNavigatorTest {
spaceStateHandler.verifySetCurrentSpace(spaceId)
}
@Test
fun `given non-null overriddenSpaceName, when switchToSpace, then current space set`() {
val spaceId = "space-id"
val spaceSummary = aRoomSummary(spaceId)
sessionHolder.fakeSession.fakeRoomService.getRoomSummaryReturns(spaceSummary)
val overriddenSpaceName = "new-space-name"
navigator.switchToSpace(FakeContext().instance, spaceId, Navigator.PostSwitchSpaceAction.None, overriddenSpaceName)
spaceStateHandler.verifySetCurrentSpace(spaceId, overriddenSpaceName = overriddenSpaceName)
}
}

View File

@ -0,0 +1,22 @@
/*
* Copyright (c) 2022 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.test.fakes
import im.vector.app.core.debug.DebugNavigator
import io.mockk.mockk
class FakeDebugNavigator : DebugNavigator by mockk()

View File

@ -22,7 +22,7 @@ import io.mockk.verify
class FakeSpaceStateHandler : SpaceStateHandler by mockk(relaxUnitFun = true) {
fun verifySetCurrentSpace(spaceId: String, overriddenSpaceName: String? = null) {
verify { setCurrentSpace(spaceId, overriddenSpaceName = overriddenSpaceName) }
fun verifySetCurrentSpace(spaceId: String) {
verify { setCurrentSpace(spaceId) }
}
}