Implement SyncState chip. (#909)
This commit is contained in:
@@ -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
|
||||
)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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 = {}
|
||||
)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user