Feat(ToolsScreen and ToolStarScreen): Show skeleton when loading tool

This commit is contained in:
2024-08-27 17:24:27 +08:00
parent c9363ee34b
commit 93b22ea14b
5 changed files with 184 additions and 2 deletions

View File

@@ -1,5 +1,8 @@
package top.fatweb.oxygen.toolbox.ui.component
import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
@@ -15,6 +18,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
@@ -30,6 +34,11 @@ import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.valentinilk.shimmer.LocalShimmerTheme
import com.valentinilk.shimmer.ShimmerBounds
import com.valentinilk.shimmer.rememberShimmer
import com.valentinilk.shimmer.shimmer
import com.valentinilk.shimmer.shimmerSpec
import top.fatweb.oxygen.toolbox.R
import top.fatweb.oxygen.toolbox.icon.OxygenIcons
import top.fatweb.oxygen.toolbox.model.tool.ToolEntity
@@ -244,3 +253,131 @@ private fun AuthorInfo(
)
}
}
@Composable
fun ToolCardSkeleton(
modifier: Modifier = Modifier
) {
val shimmer = rememberShimmer(
shimmerBounds = ShimmerBounds.Window,
theme = LocalShimmerTheme.current.copy(
animationSpec = infiniteRepeatable(
animation = shimmerSpec(
durationMillis = 1_500,
easing = LinearEasing,
delayMillis = 200
),
repeatMode = RepeatMode.Restart
)
)
)
Card(
modifier = modifier
.clip(RoundedCornerShape(8.dp)),
shape = RoundedCornerShape(8.dp),
colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surface)
) {
Column(
modifier = Modifier.padding(16.dp)
) {
Row(
modifier = Modifier
.height(28.dp)
) {
Surface(
modifier = modifier
.fillMaxHeight()
.width(64.dp)
.shimmer(shimmer),
shape = RoundedCornerShape(8.dp),
color = MaterialTheme.colorScheme.surfaceContainer
) {}
}
Spacer(Modifier.height(16.dp))
Box(
modifier = Modifier
.fillMaxWidth(),
contentAlignment = Alignment.Center
) {
Surface(
modifier = Modifier
.size(80.dp)
.shimmer(shimmer),
shape = RoundedCornerShape(8.dp),
color = MaterialTheme.colorScheme.surfaceContainer
) {}
}
Spacer(Modifier.height(16.dp))
Column(
modifier = modifier.fillMaxWidth(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(6.dp)
) {
Surface(
modifier = Modifier
.size(width = 40.dp, height = 22.dp)
.shimmer(shimmer),
shape = RoundedCornerShape(4.dp),
color = MaterialTheme.colorScheme.surfaceContainer
) {}
Surface(
modifier = Modifier
.size(width = 60.dp, height = 20.dp)
.shimmer(shimmer),
shape = RoundedCornerShape(4.dp),
color = MaterialTheme.colorScheme.surfaceContainer
) {}
Column(
verticalArrangement = Arrangement.spacedBy(2.dp)
) {
Surface(
modifier = Modifier
.size(width = 120.dp, height = 12.dp)
.shimmer(shimmer),
shape = RoundedCornerShape(4.dp),
color = MaterialTheme.colorScheme.surfaceContainer
) {}
Surface(
modifier = Modifier
.size(width = 120.dp, height = 12.dp)
.shimmer(shimmer),
shape = RoundedCornerShape(4.dp),
color = MaterialTheme.colorScheme.surfaceContainer
) {}
Surface(
modifier = Modifier
.size(width = 80.dp, height = 12.dp)
.shimmer(shimmer),
shape = RoundedCornerShape(4.dp),
color = MaterialTheme.colorScheme.surfaceContainer
) {}
}
}
Spacer(Modifier.height(16.dp))
Row(
modifier = Modifier
.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterHorizontally)
) {
Surface(
modifier = Modifier
.size(24.dp)
.shimmer(shimmer),
shape = RoundedCornerShape(12.dp),
color = MaterialTheme.colorScheme.surfaceContainer
) {}
Surface(
modifier = Modifier
.size(width = 120.dp, height = 12.dp)
.shimmer(shimmer),
shape = RoundedCornerShape(4.dp),
color = MaterialTheme.colorScheme.surfaceContainer
) {}
}
}
}
}
const val DEFAULT_TOOL_CARD_SKELETON_COUNT = 8

View File

@@ -43,11 +43,13 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
import top.fatweb.oxygen.toolbox.R
import top.fatweb.oxygen.toolbox.icon.OxygenIcons
import top.fatweb.oxygen.toolbox.model.tool.ToolEntity
import top.fatweb.oxygen.toolbox.ui.component.DEFAULT_TOOL_CARD_SKELETON_COUNT
import top.fatweb.oxygen.toolbox.ui.component.DialogClickerRow
import top.fatweb.oxygen.toolbox.ui.component.DialogSectionGroup
import top.fatweb.oxygen.toolbox.ui.component.DialogTitle
import top.fatweb.oxygen.toolbox.ui.component.Indicator
import top.fatweb.oxygen.toolbox.ui.component.ToolCard
import top.fatweb.oxygen.toolbox.ui.component.ToolCardSkeleton
import top.fatweb.oxygen.toolbox.ui.component.scrollbar.DraggableScrollbar
import top.fatweb.oxygen.toolbox.ui.component.scrollbar.rememberDraggableScroller
import top.fatweb.oxygen.toolbox.ui.component.scrollbar.scrollbarState
@@ -96,6 +98,24 @@ internal fun StarScreen(
when (starScreenUiState) {
StarScreenUiState.Loading -> {
Indicator()
LazyVerticalStaggeredGrid(
modifier = Modifier
.fillMaxSize(),
columns = StaggeredGridCells.Adaptive(160.dp),
contentPadding = PaddingValues(16.dp),
horizontalArrangement = Arrangement.spacedBy(16.dp),
verticalItemSpacing = 24.dp,
state = state
) {
items(count = DEFAULT_TOOL_CARD_SKELETON_COUNT) {
ToolCardSkeleton()
}
item(span = StaggeredGridItemSpan.FullLine) {
Spacer(Modifier.height(8.dp))
Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.safeDrawing))
}
}
}
StarScreenUiState.Nothing -> {
@@ -210,6 +230,7 @@ private fun ToolMenu(
@Composable
private fun howManyTools(starScreenUiState: StarScreenUiState) =
when (starScreenUiState) {
StarScreenUiState.Loading, StarScreenUiState.Nothing -> 0
StarScreenUiState.Loading -> DEFAULT_TOOL_CARD_SKELETON_COUNT
StarScreenUiState.Nothing -> 0
is StarScreenUiState.Success -> starScreenUiState.tools.size
}

View File

@@ -47,11 +47,13 @@ import kotlinx.coroutines.launch
import top.fatweb.oxygen.toolbox.R
import top.fatweb.oxygen.toolbox.icon.OxygenIcons
import top.fatweb.oxygen.toolbox.model.tool.ToolEntity
import top.fatweb.oxygen.toolbox.ui.component.DEFAULT_TOOL_CARD_SKELETON_COUNT
import top.fatweb.oxygen.toolbox.ui.component.DialogClickerRow
import top.fatweb.oxygen.toolbox.ui.component.DialogSectionGroup
import top.fatweb.oxygen.toolbox.ui.component.DialogTitle
import top.fatweb.oxygen.toolbox.ui.component.Indicator
import top.fatweb.oxygen.toolbox.ui.component.ToolCard
import top.fatweb.oxygen.toolbox.ui.component.ToolCardSkeleton
import top.fatweb.oxygen.toolbox.ui.component.scrollbar.DraggableScrollbar
import top.fatweb.oxygen.toolbox.ui.component.scrollbar.rememberDraggableScroller
import top.fatweb.oxygen.toolbox.ui.component.scrollbar.scrollbarState
@@ -116,6 +118,24 @@ internal fun ToolsScreen(
when (toolsScreenUiState) {
ToolsScreenUiState.Loading -> {
Indicator()
LazyVerticalStaggeredGrid(
modifier = Modifier
.fillMaxSize(),
columns = StaggeredGridCells.Adaptive(160.dp),
contentPadding = PaddingValues(16.dp),
horizontalArrangement = Arrangement.spacedBy(16.dp),
verticalItemSpacing = 24.dp,
state = state
) {
items(count = DEFAULT_TOOL_CARD_SKELETON_COUNT) {
ToolCardSkeleton()
}
item(span = StaggeredGridItemSpan.FullLine) {
Spacer(Modifier.height(8.dp))
Spacer(Modifier.windowInsetsBottomHeight(WindowInsets.safeDrawing))
}
}
}
ToolsScreenUiState.Nothing -> {
@@ -254,6 +274,7 @@ private fun ToolMenu(
@Composable
private fun howManyTools(toolsScreenUiState: ToolsScreenUiState) =
when (toolsScreenUiState) {
ToolsScreenUiState.Loading, ToolsScreenUiState.Nothing -> 0
ToolsScreenUiState.Loading -> DEFAULT_TOOL_CARD_SKELETON_COUNT
ToolsScreenUiState.Nothing -> 0
is ToolsScreenUiState.Success -> toolsScreenUiState.tools.size
}