owenclave / app/src/main/java/io/nekohasekai/sagernet/ui/compose/screens/AssetsScreen.kt

github - dev - back to tree - upstream
package io.nekohasekai.sagernet.ui.compose.screens import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material.icons.filled.Add import androidx.compose.material.icons.filled.Delete import androidx.compose.material.icons.filled.Edit import androidx.compose.material3.Card import androidx.compose.material3.CardDefaults import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.LinearWavyProgressIndicator import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.rememberTopAppBarState import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import io.nekohasekai.sagernet.ui.compose.components.EmptyState import io.nekohasekai.sagernet.ui.compose.components.OwenclaveTopAppBar data class AssetItem( val name: String, val status: String, val updating: Boolean = false, ) @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class) @Composable fun AssetsScreen( assets: List, onBack: () -> Unit, onAdd: () -> Unit, onEdit: (AssetItem) -> Unit, onDelete: (AssetItem) -> Unit, onUpdate: (AssetItem) -> Unit = {}, ) { val scrollBehavior = TopAppBarDefaults.enterAlwaysScrollBehavior(rememberTopAppBarState()) Scaffold( modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection), containerColor = MaterialTheme.colorScheme.surfaceContainer, topBar = { OwenclaveTopAppBar( title = "Route Assets", navigationIcon = Icons.AutoMirrored.Filled.ArrowBack, onNavigationClick = onBack, scrollBehavior = scrollBehavior, actions = { IconButton(onClick = onAdd) { Icon(Icons.Filled.Add, contentDescription = "Add") } }, ) }, ) { paddingValues -> Box( modifier = Modifier .fillMaxSize() .padding(paddingValues) ) { if (assets.isEmpty()) { EmptyState( message = "No assets. Tap + to add geosite/geoip data.", icon = Icons.Filled.Add, ) } else { LazyColumn( modifier = Modifier.fillMaxSize(), contentPadding = androidx.compose.foundation.layout.PaddingValues(vertical = 8.dp), ) { items(assets, key = { it.name }) { asset -> Card( modifier = Modifier .fillMaxWidth() .padding(horizontal = 16.dp, vertical = 4.dp), shape = MaterialTheme.shapes.large, colors = CardDefaults.cardColors( containerColor = MaterialTheme.colorScheme.surfaceContainerLow ), ) { Column { if (asset.updating) { LinearWavyProgressIndicator( modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.primary, ) } androidx.compose.foundation.layout.Row( modifier = Modifier.padding(16.dp), verticalAlignment = androidx.compose.ui.Alignment.CenterVertically, ) { Column(modifier = Modifier.weight(1f)) { Text( text = asset.name, style = MaterialTheme.typography.titleMedium, maxLines = 1, overflow = TextOverflow.Ellipsis, ) Text( text = asset.status, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant, ) } IconButton(onClick = { onEdit(asset) }) { Icon(Icons.Filled.Edit, contentDescription = "Edit", modifier = Modifier.size(20.dp)) } IconButton(onClick = { onDelete(asset) }) { Icon(Icons.Filled.Delete, contentDescription = "Delete", modifier = Modifier.size(20.dp)) } } } } } } } } } }