Skip to content

Commit dd7a7d5

Browse files
authored
Merge pull request #7567 from hayaksi1/fix/4099-server-unreachable
Say when the server cannot be reached instead of showing nothing
2 parents c56001f + 594a561 commit dd7a7d5

19 files changed

Lines changed: 101 additions & 34 deletions

appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInPresenter.kt

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,18 @@ class LoggedInPresenter(
105105
}
106106
val syncIndicator by matrixClient.roomListService.syncIndicator.collectAsState()
107107
val isOnline by syncService.isOnline.collectAsState()
108-
val showSyncSpinner by remember {
108+
val hasNetwork by networkMonitor.connectivity.collectAsState()
109+
val syncIndicatorState by remember {
109110
derivedStateOf {
110-
isOnline && syncIndicator == RoomListService.SyncIndicator.Show
111+
when {
112+
isOnline -> if (syncIndicator == RoomListService.SyncIndicator.Show) {
113+
SyncIndicatorState.Syncing
114+
} else {
115+
SyncIndicatorState.Hidden
116+
}
117+
hasNetwork == NetworkStatus.Connected -> SyncIndicatorState.ServerUnreachable
118+
else -> SyncIndicatorState.Hidden
119+
}
111120
}
112121
}
113122
var forceNativeSlidingSyncMigration by remember { mutableStateOf(false) }
@@ -181,7 +190,7 @@ class LoggedInPresenter(
181190
}
182191

183192
return LoggedInState(
184-
showSyncSpinner = showSyncSpinner,
193+
syncIndicatorState = syncIndicatorState,
185194
pusherRegistrationState = pusherRegistrationState.value,
186195
ignoreRegistrationError = ignoreRegistrationError,
187196
forceNativeSlidingSyncMigration = forceNativeSlidingSyncMigration,

appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInState.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,14 @@ package io.element.android.appnav.loggedin
1111
import io.element.android.libraries.architecture.AsyncData
1212
import io.element.android.libraries.permissions.api.localnetwork.LocalNetworkPermissionDialog
1313

14+
enum class SyncIndicatorState {
15+
Hidden,
16+
Syncing,
17+
ServerUnreachable,
18+
}
19+
1420
data class LoggedInState(
15-
val showSyncSpinner: Boolean,
21+
val syncIndicatorState: SyncIndicatorState,
1622
val pusherRegistrationState: AsyncData<Unit>,
1723
val ignoreRegistrationError: Boolean,
1824
val forceNativeSlidingSyncMigration: Boolean,

appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInStatePreviewParam.kt

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ open class LoggedInStatePreviewParam : PreviewParameterProvider<LoggedInState> {
1717
override val values: Sequence<LoggedInState>
1818
get() = sequenceOf(
1919
aLoggedInState(),
20-
aLoggedInState(showSyncSpinner = true),
20+
aLoggedInState(syncIndicatorState = SyncIndicatorState.Syncing),
21+
aLoggedInState(syncIndicatorState = SyncIndicatorState.ServerUnreachable),
2122
aLoggedInState(pusherRegistrationState = AsyncData.Failure(PusherRegistrationFailure.NoDistributorsAvailable())),
2223
aLoggedInState(forceNativeSlidingSyncMigration = true),
2324
aLoggedInState(localNetworkPermissionDialog = LocalNetworkPermissionDialog.Rationale),
@@ -26,13 +27,13 @@ open class LoggedInStatePreviewParam : PreviewParameterProvider<LoggedInState> {
2627
}
2728

2829
fun aLoggedInState(
29-
showSyncSpinner: Boolean = false,
30+
syncIndicatorState: SyncIndicatorState = SyncIndicatorState.Hidden,
3031
pusherRegistrationState: AsyncData<Unit> = AsyncData.Uninitialized,
3132
forceNativeSlidingSyncMigration: Boolean = false,
3233
appName: String = "Element X",
3334
localNetworkPermissionDialog: LocalNetworkPermissionDialog = LocalNetworkPermissionDialog.None,
3435
) = LoggedInState(
35-
showSyncSpinner = showSyncSpinner,
36+
syncIndicatorState = syncIndicatorState,
3637
pusherRegistrationState = pusherRegistrationState,
3738
ignoreRegistrationError = false,
3839
forceNativeSlidingSyncMigration = forceNativeSlidingSyncMigration,

appnav/src/main/kotlin/io/element/android/appnav/loggedin/LoggedInView.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ fun LoggedInView(
4747
) {
4848
SyncStateView(
4949
modifier = Modifier.align(Alignment.TopCenter),
50-
isVisible = state.showSyncSpinner,
50+
state = state.syncIndicatorState,
5151
)
5252
}
5353
when (state.pusherRegistrationState) {

appnav/src/main/kotlin/io/element/android/appnav/loggedin/SyncStateView.kt

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,23 @@ import io.element.android.libraries.ui.strings.CommonStrings
2525

2626
@Composable
2727
fun SyncStateView(
28-
isVisible: Boolean,
28+
state: SyncIndicatorState,
2929
modifier: Modifier = Modifier
3030
) {
3131
AnimatedVisibility(
32-
visible = isVisible,
32+
visible = state != SyncIndicatorState.Hidden,
3333
modifier = modifier,
3434
enter = fadeIn(spring(stiffness = 500F)),
3535
exit = fadeOut(spring(stiffness = 500F)),
3636
) {
37-
AsyncIndicator.Loading(
38-
text = stringResource(id = CommonStrings.common_syncing),
39-
)
37+
when (state) {
38+
SyncIndicatorState.ServerUnreachable -> AsyncIndicator.Failure(
39+
text = stringResource(id = CommonStrings.common_server_unreachable),
40+
)
41+
else -> AsyncIndicator.Loading(
42+
text = stringResource(id = CommonStrings.common_syncing),
43+
)
44+
}
4045
}
4146
}
4247

@@ -46,7 +51,18 @@ internal fun SyncStateViewPreview() = ElementPreview {
4651
// Add a box to see the shadow
4752
Box(modifier = Modifier.padding(24.dp)) {
4853
SyncStateView(
49-
isVisible = true
54+
state = SyncIndicatorState.Syncing
55+
)
56+
}
57+
}
58+
59+
@PreviewsDayNight
60+
@Composable
61+
internal fun SyncStateViewServerUnreachablePreview() = ElementPreview {
62+
// Add a box to see the shadow
63+
Box(modifier = Modifier.padding(24.dp)) {
64+
SyncStateView(
65+
state = SyncIndicatorState.ServerUnreachable
5066
)
5167
}
5268
}

appnav/src/test/kotlin/io/element/android/appnav/loggedin/LoggedInPresenterTest.kt

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ class LoggedInPresenterTest {
6767
fun `present - initial state`() = runTest {
6868
createLoggedInPresenter().test {
6969
val initialState = awaitItem()
70-
assertThat(initialState.showSyncSpinner).isFalse()
70+
assertThat(initialState.syncIndicatorState).isEqualTo(SyncIndicatorState.Hidden)
7171
assertThat(initialState.pusherRegistrationState.isUninitialized()).isTrue()
7272
assertThat(initialState.ignoreRegistrationError).isFalse()
7373
}
@@ -97,11 +97,33 @@ class LoggedInPresenterTest {
9797
matrixClient = FakeMatrixClient(roomListService = roomListService),
9898
).test {
9999
val initialState = awaitItem()
100-
assertThat(initialState.showSyncSpinner).isFalse()
100+
assertThat(initialState.syncIndicatorState).isEqualTo(SyncIndicatorState.Hidden)
101101
roomListService.postSyncIndicator(RoomListService.SyncIndicator.Show)
102-
consumeItemsUntilPredicate { it.showSyncSpinner }
102+
consumeItemsUntilPredicate { it.syncIndicatorState == SyncIndicatorState.Syncing }
103103
roomListService.postSyncIndicator(RoomListService.SyncIndicator.Hide)
104-
consumeItemsUntilPredicate { !it.showSyncSpinner }
104+
consumeItemsUntilPredicate { it.syncIndicatorState != SyncIndicatorState.Syncing }
105+
}
106+
}
107+
108+
@Test
109+
fun `present - say the server is unreachable when the device has network but the sync is offline`() = runTest {
110+
createLoggedInPresenter(
111+
syncState = SyncState.Offline,
112+
networkMonitor = FakeNetworkMonitor(initialStatus = NetworkStatus.Connected),
113+
).test {
114+
consumeItemsUntilPredicate { it.syncIndicatorState == SyncIndicatorState.ServerUnreachable }
115+
cancelAndConsumeRemainingEvents()
116+
}
117+
}
118+
119+
@Test
120+
fun `present - say nothing when the device itself has no network`() = runTest {
121+
createLoggedInPresenter(
122+
syncState = SyncState.Offline,
123+
networkMonitor = FakeNetworkMonitor(initialStatus = NetworkStatus.Disconnected),
124+
).test {
125+
consumeItemsUntilPredicate { it.syncIndicatorState == SyncIndicatorState.Hidden }
126+
cancelAndConsumeRemainingEvents()
105127
}
106128
}
107129

tests/konsist/src/test/kotlin/io/element/android/tests/konsist/KonsistPreviewTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ class KonsistPreviewTest {
133133
"SecureBackupSetupViewChangePreview",
134134
"SelectedUserCannotRemovePreview",
135135
"SpaceMembersViewNoHeroesPreview",
136+
"SyncStateViewServerUnreachablePreview",
136137
"TextComposerAddCaptionPreview",
137138
"TextComposerCaptionPreview",
138139
"TextComposerEditCaptionPreview",
Lines changed: 2 additions & 2 deletions
Loading
Lines changed: 2 additions & 2 deletions
Loading
Lines changed: 2 additions & 2 deletions
Loading

0 commit comments

Comments
 (0)