owenclave / app/src/main/java/io/nekohasekai/sagernet/ui/compose/components/CommonComponents.kt

github - dev - back to tree - upstream
package io.nekohasekai.sagernet.ui.compose.components import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.IconButtonDefaults import androidx.compose.material3.LargeFlexibleTopAppBar import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarScrollBehavior import androidx.compose.material3.LoadingIndicator import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.unit.dp @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun OwenclaveTopAppBar( title: String, modifier: Modifier = Modifier, navigationIcon: ImageVector? = null, onNavigationClick: (() -> Unit)? = null, actions: @Composable RowScope.() -> Unit = {}, scrollBehavior: TopAppBarScrollBehavior? = null, ) { // Fade the nav-icon container out as the bar collapses so it doesn't look // "stuck" against the scrolled background. val collapsedFraction = scrollBehavior?.state?.collapsedFraction ?: 0f val navContainer = MaterialTheme.colorScheme.surfaceBright.copy( alpha = 1f - collapsedFraction, ) LargeFlexibleTopAppBar( title = { Text( title, style = MaterialTheme.typography.headlineSmall, maxLines = 1, softWrap = false, modifier = Modifier.padding(vertical = 4.dp), ) }, modifier = modifier, navigationIcon = { if (navigationIcon != null && onNavigationClick != null) { IconButton( onClick = onNavigationClick, modifier = Modifier.size(48.dp), colors = IconButtonDefaults.iconButtonColors( containerColor = navContainer, ), ) { Icon( imageVector = navigationIcon, contentDescription = "Navigate back", modifier = Modifier.size(24.dp) ) } } }, actions = actions, colors = TopAppBarDefaults.topAppBarColors( containerColor = MaterialTheme.colorScheme.surface, scrolledContainerColor = MaterialTheme.colorScheme.surfaceContainerHigh, titleContentColor = MaterialTheme.colorScheme.onSurface, navigationIconContentColor = MaterialTheme.colorScheme.onSurface, actionIconContentColor = MaterialTheme.colorScheme.onSurface, ), scrollBehavior = scrollBehavior, ) } @OptIn(ExperimentalMaterial3ExpressiveApi::class) @Composable fun LoadingState( modifier: Modifier = Modifier, message: String? = null, ) { Box( modifier = modifier.fillMaxSize(), contentAlignment = Alignment.Center, ) { if (message != null) { androidx.compose.foundation.layout.Column( horizontalAlignment = Alignment.CenterHorizontally, ) { LoadingIndicator( modifier = Modifier.size(48.dp), color = MaterialTheme.colorScheme.primary, ) Text( text = message, style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(top = 16.dp), ) } } else { LoadingIndicator( modifier = Modifier.size(48.dp), color = MaterialTheme.colorScheme.primary, ) } } } @Composable fun EmptyState( message: String, modifier: Modifier = Modifier, icon: ImageVector? = null, ) { Box( modifier = modifier.fillMaxSize().padding(32.dp), contentAlignment = Alignment.Center, ) { androidx.compose.foundation.layout.Column( horizontalAlignment = Alignment.CenterHorizontally, ) { if (icon != null) { ShapedIconStatic( icon = icon, containerColor = MaterialTheme.colorScheme.secondaryContainer, contentColor = MaterialTheme.colorScheme.onSecondaryContainer, size = 96.dp, ) } Text( text = message, style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(top = 20.dp), ) } } }