Skip to content

Commit 88ca379

Browse files
authored
Merge pull request #1520 from vector-im/feature/bma/sessionDb
Improve session db and improve deleted session behavior
2 parents 6a28814 + 33943b2 commit 88ca379

File tree

43 files changed

+968
-49
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+968
-49
lines changed

appnav/src/main/kotlin/io/element/android/appnav/RootFlowNode.kt

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import io.element.android.appnav.root.RootView
4545
import io.element.android.features.login.api.oidc.OidcAction
4646
import io.element.android.features.login.api.oidc.OidcActionFlow
4747
import io.element.android.features.rageshake.api.bugreport.BugReportEntryPoint
48+
import io.element.android.features.signedout.api.SignedOutEntryPoint
4849
import io.element.android.libraries.architecture.BackstackNode
4950
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler
5051
import io.element.android.libraries.architecture.createNode
@@ -54,6 +55,7 @@ import io.element.android.libraries.designsystem.theme.components.CircularProgre
5455
import io.element.android.libraries.di.AppScope
5556
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
5657
import io.element.android.libraries.matrix.api.core.SessionId
58+
import io.element.android.libraries.sessionstorage.api.LoggedInState
5759
import kotlinx.coroutines.flow.distinctUntilChanged
5860
import kotlinx.coroutines.flow.launchIn
5961
import kotlinx.coroutines.flow.onEach
@@ -69,6 +71,7 @@ class RootFlowNode @AssistedInject constructor(
6971
private val matrixClientsHolder: MatrixClientsHolder,
7072
private val presenter: RootPresenter,
7173
private val bugReportEntryPoint: BugReportEntryPoint,
74+
private val signedOutEntryPoint: SignedOutEntryPoint,
7275
private val intentResolver: IntentResolver,
7376
private val oidcActionFlow: OidcActionFlow,
7477
) : BackstackNode<RootFlowNode.NavTarget>(
@@ -97,13 +100,20 @@ class RootFlowNode @AssistedInject constructor(
97100
.distinctUntilChanged()
98101
.onEach { navState ->
99102
Timber.v("navState=$navState")
100-
if (navState.isLoggedIn) {
101-
tryToRestoreLatestSession(
102-
onSuccess = { sessionId -> switchToLoggedInFlow(sessionId, navState.cacheIndex) },
103-
onFailure = { switchToNotLoggedInFlow() }
104-
)
105-
} else {
106-
switchToNotLoggedInFlow()
103+
when (navState.loggedInState) {
104+
is LoggedInState.LoggedIn -> {
105+
if (navState.loggedInState.isTokenValid) {
106+
tryToRestoreLatestSession(
107+
onSuccess = { sessionId -> switchToLoggedInFlow(sessionId, navState.cacheIndex) },
108+
onFailure = { switchToNotLoggedInFlow() }
109+
)
110+
} else {
111+
switchToSignedOutFlow(SessionId(navState.loggedInState.sessionId))
112+
}
113+
}
114+
LoggedInState.NotLoggedIn -> {
115+
switchToNotLoggedInFlow()
116+
}
107117
}
108118
}
109119
.launchIn(lifecycleScope)
@@ -118,6 +128,10 @@ class RootFlowNode @AssistedInject constructor(
118128
backstack.safeRoot(NavTarget.NotLoggedInFlow)
119129
}
120130

131+
private fun switchToSignedOutFlow(sessionId: SessionId) {
132+
backstack.safeRoot(NavTarget.SignedOutFlow(sessionId))
133+
}
134+
121135
private suspend fun restoreSessionIfNeeded(
122136
sessionId: SessionId,
123137
onFailure: () -> Unit = {},
@@ -179,6 +193,11 @@ class RootFlowNode @AssistedInject constructor(
179193
val navId: Int
180194
) : NavTarget
181195

196+
@Parcelize
197+
data class SignedOutFlow(
198+
val sessionId: SessionId
199+
) : NavTarget
200+
182201
@Parcelize
183202
data object BugReport : NavTarget
184203
}
@@ -198,6 +217,15 @@ class RootFlowNode @AssistedInject constructor(
198217
createNode<LoggedInAppScopeFlowNode>(buildContext, plugins = listOf(inputs, callback))
199218
}
200219
NavTarget.NotLoggedInFlow -> createNode<NotLoggedInFlowNode>(buildContext)
220+
is NavTarget.SignedOutFlow -> {
221+
signedOutEntryPoint.nodeBuilder(this, buildContext)
222+
.params(
223+
SignedOutEntryPoint.Params(
224+
sessionId = navTarget.sessionId
225+
)
226+
)
227+
.build()
228+
}
201229
NavTarget.SplashScreen -> splashNode(buildContext)
202230
NavTarget.BugReport -> {
203231
val callback = object : BugReportEntryPoint.Callback {

appnav/src/main/kotlin/io/element/android/appnav/root/RootNavState.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package io.element.android.appnav.root
1818

19+
import io.element.android.libraries.sessionstorage.api.LoggedInState
20+
1921
/**
2022
* [RootNavState] produced by [RootNavStateFlowFactory].
2123
*/
@@ -26,7 +28,7 @@ data class RootNavState(
2628
*/
2729
val cacheIndex: Int,
2830
/**
29-
* true if we are currently loggedIn.
31+
* LoggedInState.
3032
*/
31-
val isLoggedIn: Boolean
33+
val loggedInState: LoggedInState,
3234
)

appnav/src/main/kotlin/io/element/android/appnav/root/RootNavStateFlowFactory.kt

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ import io.element.android.appnav.di.MatrixClientsHolder
2222
import io.element.android.features.login.api.LoginUserStory
2323
import io.element.android.features.preferences.api.CacheService
2424
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
25+
import io.element.android.libraries.sessionstorage.api.LoggedInState
2526
import kotlinx.coroutines.flow.Flow
2627
import kotlinx.coroutines.flow.combine
27-
import kotlinx.coroutines.flow.distinctUntilChanged
2828
import kotlinx.coroutines.flow.flow
2929
import kotlinx.coroutines.flow.onEach
3030
import javax.inject.Inject
@@ -47,9 +47,14 @@ class RootNavStateFlowFactory @Inject constructor(
4747
fun create(savedStateMap: SavedStateMap?): Flow<RootNavState> {
4848
return combine(
4949
cacheIndexFlow(savedStateMap),
50-
isUserLoggedInFlow(),
51-
) { cacheIndex, isLoggedIn ->
52-
RootNavState(cacheIndex = cacheIndex, isLoggedIn = isLoggedIn)
50+
authenticationService.loggedInStateFlow(),
51+
loginUserStory.loginFlowIsDone,
52+
) { cacheIndex, loggedInState, loginFlowIsDone ->
53+
if (loginFlowIsDone) {
54+
RootNavState(cacheIndex = cacheIndex, loggedInState = loggedInState)
55+
} else {
56+
RootNavState(cacheIndex = cacheIndex, loggedInState = LoggedInState.NotLoggedIn)
57+
}
5358
}
5459
}
5560

@@ -72,16 +77,6 @@ class RootNavStateFlowFactory @Inject constructor(
7277
}
7378
}
7479

75-
private fun isUserLoggedInFlow(): Flow<Boolean> {
76-
return combine(
77-
authenticationService.isLoggedIn(),
78-
loginUserStory.loginFlowIsDone
79-
) { isLoggedIn, loginFlowIsDone ->
80-
isLoggedIn && loginFlowIsDone
81-
}
82-
.distinctUntilChanged()
83-
}
84-
8580
/**
8681
* @return a flow of integer that increments the value by one each time a new element is emitted upstream.
8782
*/

changelog.d/1520.feature

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improve deleted session behavior.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* Copyright (c) 2023 New Vector Ltd
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
plugins {
18+
id("io.element.android-library")
19+
}
20+
21+
android {
22+
namespace = "io.element.android.features.signedout.api"
23+
}
24+
25+
dependencies {
26+
implementation(projects.libraries.architecture)
27+
implementation(projects.libraries.matrix.api)
28+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright (c) 2023 New Vector Ltd
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.element.android.features.signedout.api
18+
19+
import com.bumble.appyx.core.modality.BuildContext
20+
import com.bumble.appyx.core.node.Node
21+
import io.element.android.libraries.architecture.FeatureEntryPoint
22+
import io.element.android.libraries.matrix.api.core.SessionId
23+
24+
interface SignedOutEntryPoint : FeatureEntryPoint {
25+
26+
data class Params(
27+
val sessionId: SessionId,
28+
)
29+
30+
fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder
31+
32+
interface NodeBuilder {
33+
fun params(params: Params): NodeBuilder
34+
fun build(): Node
35+
}
36+
}
37+
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright (c) 2023 New Vector Ltd
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
plugins {
18+
id("io.element.android-compose-library")
19+
alias(libs.plugins.anvil)
20+
alias(libs.plugins.ksp)
21+
id("kotlin-parcelize")
22+
}
23+
24+
android {
25+
namespace = "io.element.android.features.signedout.impl"
26+
}
27+
28+
anvil {
29+
generateDaggerFactories.set(true)
30+
}
31+
32+
dependencies {
33+
implementation(projects.anvilannotations)
34+
anvil(projects.anvilcodegen)
35+
api(projects.features.signedout.api)
36+
implementation(projects.libraries.core)
37+
implementation(projects.libraries.architecture)
38+
implementation(projects.libraries.matrix.api)
39+
implementation(projects.libraries.matrixui)
40+
implementation(projects.libraries.designsystem)
41+
implementation(projects.libraries.uiStrings)
42+
43+
testImplementation(libs.test.junit)
44+
testImplementation(libs.coroutines.test)
45+
testImplementation(libs.molecule.runtime)
46+
testImplementation(libs.test.truth)
47+
testImplementation(libs.test.turbine)
48+
testImplementation(projects.libraries.matrix.test)
49+
testImplementation(projects.libraries.sessionStorage.implMemory)
50+
testImplementation(projects.tests.testutils)
51+
52+
ksp(libs.showkase.processor)
53+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright (c) 2023 New Vector Ltd
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.element.android.features.signedout.impl
18+
19+
import com.bumble.appyx.core.modality.BuildContext
20+
import com.bumble.appyx.core.node.Node
21+
import com.bumble.appyx.core.plugin.Plugin
22+
import com.squareup.anvil.annotations.ContributesBinding
23+
import io.element.android.features.signedout.api.SignedOutEntryPoint
24+
import io.element.android.libraries.architecture.createNode
25+
import io.element.android.libraries.di.AppScope
26+
import javax.inject.Inject
27+
28+
@ContributesBinding(AppScope::class)
29+
class DefaultSignedOutEntryPoint @Inject constructor() : SignedOutEntryPoint {
30+
31+
override fun nodeBuilder(parentNode: Node, buildContext: BuildContext): SignedOutEntryPoint.NodeBuilder {
32+
val plugins = ArrayList<Plugin>()
33+
34+
return object : SignedOutEntryPoint.NodeBuilder {
35+
36+
override fun params(params: SignedOutEntryPoint.Params): SignedOutEntryPoint.NodeBuilder {
37+
plugins += SignedOutNode.Inputs(params.sessionId)
38+
return this
39+
}
40+
41+
override fun build(): Node {
42+
return parentNode.createNode<SignedOutNode>(buildContext, plugins)
43+
}
44+
}
45+
}
46+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright (c) 2023 New Vector Ltd
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.element.android.features.signedout.impl
18+
19+
sealed interface SignedOutEvents {
20+
data object SignInAgain : SignedOutEvents
21+
}

0 commit comments

Comments
 (0)