Implement SyncState chip. (#909)

This commit is contained in:
Benoit Marty
2023-07-19 11:45:30 +02:00
parent 6520419c4b
commit f8fd684710
5 changed files with 138 additions and 20 deletions

View File

@@ -20,6 +20,7 @@ import android.Manifest
import android.os.Build
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.permissions.api.PermissionsPresenter
@@ -52,6 +53,7 @@ class LoggedInPresenter @Inject constructor(
pushService.registerWith(matrixClient, pushProvider, distributor)
}
val syncState = matrixClient.syncService().syncState.collectAsState()
val permissionsState = postNotificationPermissionsPresenter.present()
// fun handleEvents(event: LoggedInEvents) {
@@ -60,6 +62,7 @@ class LoggedInPresenter @Inject constructor(
// }
return LoggedInState(
syncState = syncState.value,
permissionsState = permissionsState,
// eventSink = ::handleEvents
)

View File

@@ -16,9 +16,11 @@
package io.element.android.appnav.loggedin
import io.element.android.libraries.matrix.api.sync.SyncState
import io.element.android.libraries.permissions.api.PermissionsState
data class LoggedInState(
val syncState: SyncState,
val permissionsState: PermissionsState,
// val eventSink: (LoggedInEvents) -> Unit
)

View File

@@ -17,17 +17,22 @@
package io.element.android.appnav.loggedin
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import io.element.android.libraries.matrix.api.sync.SyncState
import io.element.android.libraries.permissions.api.createDummyPostNotificationPermissionsState
open class LoggedInStateProvider : PreviewParameterProvider<LoggedInState> {
override val values: Sequence<LoggedInState>
get() = sequenceOf(
aLoggedInState(),
aLoggedInState(syncState = SyncState.Idle),
// Add other state here
)
}
fun aLoggedInState() = LoggedInState(
fun aLoggedInState(
syncState: SyncState = SyncState.Syncing,
) = LoggedInState(
syncState = syncState,
permissionsState = createDummyPostNotificationPermissionsState(),
// eventSink = {}
)

View File

@@ -16,14 +16,19 @@
package io.element.android.appnav.loggedin
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.libraries.androidutils.system.openAppSettingsPage
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.preview.DayNightPreviews
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.permissions.api.PermissionsView
@Composable
@@ -33,25 +38,27 @@ fun LoggedInView(
) {
val context = LocalContext.current
PermissionsView(
state = state.permissionsState,
modifier = modifier,
openSystemSettings = context::openAppSettingsPage
)
Box(
modifier = modifier
.fillMaxSize()
.systemBarsPadding()
) {
SyncStateView(
modifier = Modifier
.padding(top = 8.dp)
.align(Alignment.TopCenter),
syncState = state.syncState,
)
PermissionsView(
state = state.permissionsState,
openSystemSettings = context::openAppSettingsPage
)
}
}
@Preview
@DayNightPreviews
@Composable
fun LoggedInViewLightPreview(@PreviewParameter(LoggedInStateProvider::class) state: LoggedInState) =
ElementPreviewLight { ContentToPreview(state) }
@Preview
@Composable
fun LoggedInViewDarkPreview(@PreviewParameter(LoggedInStateProvider::class) state: LoggedInState) =
ElementPreviewDark { ContentToPreview(state) }
@Composable
private fun ContentToPreview(state: LoggedInState) {
fun LoggedInViewPreview(@PreviewParameter(LoggedInStateProvider::class) state: LoggedInState) = ElementPreview {
LoggedInView(
state = state
)

View File

@@ -0,0 +1,101 @@
/*
* Copyright (c) 2023 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 io.element.android.appnav.loggedin
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.spring
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.progressSemantics
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.preview.DayNightPreviews
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
import io.element.android.libraries.designsystem.theme.components.Surface
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.matrix.api.sync.SyncState
import io.element.android.libraries.theme.ElementTheme
import io.element.android.libraries.ui.strings.CommonStrings
@Composable
fun SyncStateView(
syncState: SyncState,
modifier: Modifier = Modifier
) {
val animationSpec = spring<Float>(stiffness = 500F)
AnimatedVisibility(
modifier = modifier,
visible = syncState.mustBeVisible(),
enter = fadeIn(animationSpec = animationSpec),
exit = fadeOut(animationSpec = animationSpec),
) {
Surface(
shape = RoundedCornerShape(24.dp),
shadowElevation = 8.dp,
) {
Row(
modifier = Modifier
.background(color = ElementTheme.colors.bgSubtleSecondary)
.padding(horizontal = 24.dp, vertical = 10.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(10.dp)
) {
CircularProgressIndicator(
modifier = Modifier
.progressSemantics()
.size(12.dp),
color = ElementTheme.colors.textPrimary,
strokeWidth = 1.5.dp,
)
Text(
text = stringResource(id = CommonStrings.common_syncing),
color = ElementTheme.colors.textPrimary,
style = ElementTheme.typography.fontBodyMdMedium
)
}
}
}
}
private fun SyncState.mustBeVisible() = when (this) {
SyncState.Idle -> true
SyncState.Syncing -> false
SyncState.InError -> false /* In this case, the network error banner can be displayed */
SyncState.Terminated -> false
}
@DayNightPreviews
@Composable
fun SyncStateViewPreview() = ElementPreview {
// Add a box to see the shadow
Box(modifier = Modifier.padding(24.dp)) {
SyncStateView(
syncState = SyncState.Idle
)
}
}