diff --git a/appnav/src/main/kotlin/io/element/android/appnav/AwaitRoomNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/AwaitRoomNode.kt index 6b8962e30c..0da87e046a 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/AwaitRoomNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/AwaitRoomNode.kt @@ -14,14 +14,27 @@ * limitations under the License. */ +@file:OptIn(ExperimentalMaterial3Api::class) + package io.element.android.appnav import android.os.Parcelable +import androidx.compose.foundation.background import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.layout.systemBars +import androidx.compose.foundation.layout.width +import androidx.compose.foundation.shape.CircleShape +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.unit.dp import androidx.lifecycle.lifecycleScope import com.bumble.appyx.core.composable.Children import com.bumble.appyx.core.modality.BuildContext @@ -30,6 +43,7 @@ import com.bumble.appyx.core.node.node import com.bumble.appyx.core.plugin.Plugin import com.bumble.appyx.core.plugin.plugins import com.bumble.appyx.navmodel.backstack.BackStack +import com.bumble.appyx.navmodel.backstack.operation.newRoot import dagger.assisted.Assisted import dagger.assisted.AssistedInject import io.element.android.anvilannotations.ContributesNode @@ -37,10 +51,17 @@ import io.element.android.libraries.architecture.BackstackNode import io.element.android.libraries.architecture.NodeInputs import io.element.android.libraries.architecture.createNode import io.element.android.libraries.architecture.inputs +import io.element.android.libraries.designsystem.atomic.atoms.PlaceholderAtom +import io.element.android.libraries.designsystem.components.avatar.AvatarSize +import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator +import io.element.android.libraries.designsystem.theme.components.Scaffold +import io.element.android.libraries.designsystem.theme.components.TopAppBar +import io.element.android.libraries.designsystem.theme.placeholderBackground import io.element.android.libraries.di.SessionScope import io.element.android.libraries.matrix.api.MatrixClient import io.element.android.libraries.matrix.api.core.RoomId +import io.element.android.libraries.theme.ElementTheme import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.asFlow import kotlinx.coroutines.flow.launchIn @@ -86,9 +107,9 @@ class AwaitRoomNode @AssistedInject constructor( init { roomStateFlow.onEach { room -> if (room == null) { - backstack.safeRoot(NavTarget.Loading) + backstack.newRoot(NavTarget.Loading) } else { - backstack.safeRoot(NavTarget.Loaded) + backstack.newRoot(NavTarget.Loaded) } }.launchIn(lifecycleScope) } @@ -100,22 +121,57 @@ class AwaitRoomNode @AssistedInject constructor( val roomFlowNodeCallback = plugins() val room = roomStateFlow.value if (room == null) { - loadingNode(buildContext) + loadingNode(buildContext, this::navigateUp) } else { val inputs = RoomFlowNode.Inputs(room, initialElement = inputs.initialElement) createNode(buildContext, plugins = listOf(inputs) + roomFlowNodeCallback + nodeLifecycleCallbacks) } } NavTarget.Loading -> { - loadingNode(buildContext) + loadingNode(buildContext, this::navigateUp) } } } - private fun loadingNode(buildContext: BuildContext) = node(buildContext) { - Box(modifier = it.fillMaxSize(), contentAlignment = Alignment.Center) { - CircularProgressIndicator() - } + private fun loadingNode(buildContext: BuildContext, onBackPressed: () -> Unit) = node(buildContext) { modifier -> + Scaffold( + modifier = modifier, + contentWindowInsets = WindowInsets.systemBars, + topBar = { + TopAppBar( + modifier = Modifier, + navigationIcon = { + BackButton(onClick = onBackPressed) + }, + title = { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Box( + modifier = Modifier + .size(AvatarSize.TimelineRoom.dp) + .align(Alignment.CenterVertically) + .background(color = ElementTheme.colors.placeholderBackground, shape = CircleShape) + ) + Spacer(modifier = Modifier.width(8.dp)) + PlaceholderAtom(width = 20.dp, height = 7.dp) + Spacer(modifier = Modifier.width(7.dp)) + PlaceholderAtom(width = 45.dp, height = 7.dp) + } + }, + ) + }, + content = { padding -> + Box( + modifier = Modifier + .fillMaxSize() + .padding(padding), contentAlignment = Alignment.Center + ) { + CircularProgressIndicator() + } + }, + ) + } @Composable diff --git a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt index ba3d228566..fb9c5162df 100644 --- a/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt +++ b/appnav/src/main/kotlin/io/element/android/appnav/LoggedInFlowNode.kt @@ -267,14 +267,14 @@ class LoggedInFlowNode @AssistedInject constructor( .build() } is NavTarget.Room -> { - val nodeLifecycleCallbacks = plugins() - val callback = object : RoomFlowNode.Callback { - override fun onForwardedToSingleRoom(roomId: RoomId) { - coroutineScope.launch { attachRoom(roomId) } - } + val nodeLifecycleCallbacks = plugins() + val callback = object : RoomFlowNode.Callback { + override fun onForwardedToSingleRoom(roomId: RoomId) { + coroutineScope.launch { attachRoom(roomId) } } - val inputs = AwaitRoomNode.Inputs(roomId = navTarget.roomId, initialElement = navTarget.initialElement) - createNode(buildContext, plugins = listOf(inputs, callback) + nodeLifecycleCallbacks) + } + val inputs = AwaitRoomNode.Inputs(roomId = navTarget.roomId, initialElement = navTarget.initialElement) + createNode(buildContext, plugins = listOf(inputs, callback) + nodeLifecycleCallbacks) } NavTarget.Settings -> { val callback = object : PreferencesEntryPoint.Callback { diff --git a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryPlaceholderRow.kt b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryPlaceholderRow.kt index 8ce5be0a85..0261f1bc16 100644 --- a/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryPlaceholderRow.kt +++ b/features/roomlist/impl/src/main/kotlin/io/element/android/features/roomlist/impl/components/RoomSummaryPlaceholderRow.kt @@ -36,7 +36,7 @@ import io.element.android.libraries.designsystem.atomic.atoms.PlaceholderAtom import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewLight -import io.element.android.libraries.designsystem.theme.roomListPlaceholder +import io.element.android.libraries.designsystem.theme.placeholderBackground import io.element.android.libraries.theme.ElementTheme /** @@ -56,7 +56,7 @@ internal fun RoomSummaryPlaceholderRow( modifier = Modifier .size(AvatarSize.RoomListItem.dp) .align(Alignment.CenterVertically) - .background(color = ElementTheme.colors.roomListPlaceholder, shape = CircleShape) + .background(color = ElementTheme.colors.placeholderBackground, shape = CircleShape) ) Column( modifier = Modifier diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/PlaceholderAtom.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/PlaceholderAtom.kt index 250177399e..75ed007d97 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/PlaceholderAtom.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/atomic/atoms/PlaceholderAtom.kt @@ -29,7 +29,7 @@ import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewLight -import io.element.android.libraries.designsystem.theme.roomListPlaceholder +import io.element.android.libraries.designsystem.theme.placeholderBackground import io.element.android.libraries.theme.ElementTheme @Composable @@ -37,7 +37,7 @@ fun PlaceholderAtom( width: Dp, height: Dp, modifier: Modifier = Modifier, - color: Color = ElementTheme.colors.roomListPlaceholder, + color: Color = ElementTheme.colors.placeholderBackground, ) { Box( modifier = modifier diff --git a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/ColorAliases.kt b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/ColorAliases.kt index 3514928938..563b9d903a 100644 --- a/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/ColorAliases.kt +++ b/libraries/designsystem/src/main/kotlin/io/element/android/libraries/designsystem/theme/ColorAliases.kt @@ -42,7 +42,7 @@ fun MaterialTheme.roomListRoomMessageDate() = colorScheme.secondary val SemanticColors.unreadIndicator get() = iconAccentTertiary -val SemanticColors.roomListPlaceholder +val SemanticColors.placeholderBackground get() = bgSubtleSecondary // This color is not present in Semantic color, so put hard-coded value for now @@ -83,7 +83,7 @@ private fun ContentToPreview() { "roomListRoomMessage" to MaterialTheme.roomListRoomMessage(), "roomListRoomMessageDate" to MaterialTheme.roomListRoomMessageDate(), "unreadIndicator" to ElementTheme.colors.unreadIndicator, - "roomListPlaceholder" to ElementTheme.colors.roomListPlaceholder, + "placeholderBackground" to ElementTheme.colors.placeholderBackground, "messageFromMeBackground" to ElementTheme.colors.messageFromMeBackground, "messageFromOtherBackground" to ElementTheme.colors.messageFromOtherBackground, ) diff --git a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/MatrixUserHeaderPlaceholder.kt b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/MatrixUserHeaderPlaceholder.kt index b43fc36fa6..57901edc03 100644 --- a/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/MatrixUserHeaderPlaceholder.kt +++ b/libraries/matrixui/src/main/kotlin/io/element/android/libraries/matrix/ui/components/MatrixUserHeaderPlaceholder.kt @@ -36,7 +36,7 @@ import io.element.android.libraries.designsystem.atomic.atoms.PlaceholderAtom import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.preview.ElementPreviewDark import io.element.android.libraries.designsystem.preview.ElementPreviewLight -import io.element.android.libraries.designsystem.theme.roomListPlaceholder +import io.element.android.libraries.designsystem.theme.placeholderBackground import io.element.android.libraries.theme.ElementTheme @Composable @@ -53,7 +53,7 @@ fun MatrixUserHeaderPlaceholder( modifier = Modifier .padding(vertical = 12.dp) .size(AvatarSize.UserPreference.dp) - .background(color = ElementTheme.colors.roomListPlaceholder, shape = CircleShape) + .background(color = ElementTheme.colors.placeholderBackground, shape = CircleShape) ) Spacer(modifier = Modifier.width(16.dp)) Column(