Feat(ToolsScreen and ToolStarScreen): Show skeleton when loading tool
This commit is contained in:
@@ -185,4 +185,5 @@ dependencies {
|
||||
implementation(libs.room.runtime)
|
||||
implementation(libs.room.ktx)
|
||||
implementation(libs.timber)
|
||||
implementation(libs.compose.shimmer)
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -33,6 +33,7 @@ androidsvg = "1.4"
|
||||
webviewCompose = "0.33.6"
|
||||
room = "2.6.1"
|
||||
timber = "5.0.1"
|
||||
composeShimmer = "1.3.1"
|
||||
|
||||
[plugins]
|
||||
androidApplication = { id = "com.android.application", version.ref = "agp" }
|
||||
@@ -102,3 +103,4 @@ room-compiler = { group = "androidx.room", name = "room-compiler", version.ref =
|
||||
room-runtime = { group = "androidx.room", name = "room-runtime", version.ref = "room" }
|
||||
room-ktx = { group = "androidx.room", name = "room-ktx", version.ref = "room" }
|
||||
timber = { group = "com.jakewharton.timber", name = "timber", version.ref = "timber" }
|
||||
compose-shimmer = { group = "com.valentinilk.shimmer", name = "compose-shimmer", version.ref = "composeShimmer" }
|
||||
|
||||
Reference in New Issue
Block a user