Feat(ToolStore): Support pull down to refresh
This commit is contained in:
@@ -1,114 +0,0 @@
|
|||||||
package top.fatweb.oxygen.toolbox.icon
|
|
||||||
|
|
||||||
import androidx.compose.foundation.Image
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.graphics.Color
|
|
||||||
import androidx.compose.ui.graphics.PathFillType
|
|
||||||
import androidx.compose.ui.graphics.SolidColor
|
|
||||||
import androidx.compose.ui.graphics.StrokeCap
|
|
||||||
import androidx.compose.ui.graphics.StrokeJoin
|
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
|
||||||
import androidx.compose.ui.graphics.vector.path
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
|
|
||||||
|
|
||||||
@Preview
|
|
||||||
@Composable
|
|
||||||
private fun VectorPreview() {
|
|
||||||
Image(Loading, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
val Loading: ImageVector
|
|
||||||
get() = ImageVector.Builder(
|
|
||||||
name = "Loading",
|
|
||||||
defaultWidth = 1024.dp,
|
|
||||||
defaultHeight = 1024.dp,
|
|
||||||
viewportWidth = 1024f,
|
|
||||||
viewportHeight = 1024f
|
|
||||||
).apply {
|
|
||||||
path(
|
|
||||||
fill = SolidColor(Color.Black),
|
|
||||||
fillAlpha = 1.0f,
|
|
||||||
stroke = null,
|
|
||||||
strokeAlpha = 1.0f,
|
|
||||||
strokeLineWidth = 1.0f,
|
|
||||||
strokeLineCap = StrokeCap.Butt,
|
|
||||||
strokeLineJoin = StrokeJoin.Miter,
|
|
||||||
strokeLineMiter = 1.0f,
|
|
||||||
pathFillType = PathFillType.NonZero
|
|
||||||
) {
|
|
||||||
moveTo(x = 988f, y = 548f)
|
|
||||||
curveToRelative(
|
|
||||||
dx1 = -19.9f,
|
|
||||||
dy1 = 0f,
|
|
||||||
dx2 = -36f,
|
|
||||||
dy2 = -16.1f,
|
|
||||||
dx3 = -36f,
|
|
||||||
dy3 = -36f
|
|
||||||
)
|
|
||||||
curveToRelative(
|
|
||||||
dx1 = 0f,
|
|
||||||
dy1 = -59.4f,
|
|
||||||
dx2 = -11.6f,
|
|
||||||
dy2 = -117f,
|
|
||||||
dx3 = -34.6f,
|
|
||||||
dy3 = -171.3f
|
|
||||||
)
|
|
||||||
arcToRelative(
|
|
||||||
a = 440.45f,
|
|
||||||
b = 440.45f,
|
|
||||||
theta = 0f,
|
|
||||||
isMoreThanHalf = false,
|
|
||||||
isPositiveArc = false,
|
|
||||||
dx1 = -94.3f,
|
|
||||||
dy1 = -139.9f
|
|
||||||
)
|
|
||||||
arcToRelative(
|
|
||||||
a = 437.71f,
|
|
||||||
b = 437.71f,
|
|
||||||
theta = 0f,
|
|
||||||
isMoreThanHalf = false,
|
|
||||||
isPositiveArc = false,
|
|
||||||
dx1 = -139.9f,
|
|
||||||
dy1 = -94.3f
|
|
||||||
)
|
|
||||||
curveTo(x1 = 629f, y1 = 83.6f, x2 = 571.4f, y2 = 72f, x3 = 512f, y3 = 72f)
|
|
||||||
curveToRelative(
|
|
||||||
dx1 = -19.9f,
|
|
||||||
dy1 = 0f,
|
|
||||||
dx2 = -36f,
|
|
||||||
dy2 = -16.1f,
|
|
||||||
dx3 = -36f,
|
|
||||||
dy3 = -36f
|
|
||||||
)
|
|
||||||
reflectiveCurveToRelative(dx1 = 16.1f, dy1 = -36f, dx2 = 36f, dy2 = -36f)
|
|
||||||
curveToRelative(
|
|
||||||
dx1 = 69.1f,
|
|
||||||
dy1 = 0f,
|
|
||||||
dx2 = 136.2f,
|
|
||||||
dy2 = 13.5f,
|
|
||||||
dx3 = 199.3f,
|
|
||||||
dy3 = 40.3f
|
|
||||||
)
|
|
||||||
curveTo(x1 = 772.3f, y1 = 66f, x2 = 827f, y2 = 103f, x3 = 874f, y3 = 150f)
|
|
||||||
curveToRelative(
|
|
||||||
dx1 = 47f,
|
|
||||||
dy1 = 47f,
|
|
||||||
dx2 = 83.9f,
|
|
||||||
dy2 = 101.8f,
|
|
||||||
dx3 = 109.7f,
|
|
||||||
dy3 = 162.7f
|
|
||||||
)
|
|
||||||
curveToRelative(
|
|
||||||
dx1 = 26.7f,
|
|
||||||
dy1 = 63.1f,
|
|
||||||
dx2 = 40.2f,
|
|
||||||
dy2 = 130.2f,
|
|
||||||
dx3 = 40.2f,
|
|
||||||
dy3 = 199.3f
|
|
||||||
)
|
|
||||||
curveToRelative(dx1 = 0.1f, dy1 = 19.9f, dx2 = -16f, dy2 = 36f, dx3 = -35.9f, dy3 = 36f)
|
|
||||||
close()
|
|
||||||
}
|
|
||||||
}.build()
|
|
||||||
@@ -1,11 +1,6 @@
|
|||||||
package top.fatweb.oxygen.toolbox.ui.store
|
package top.fatweb.oxygen.toolbox.ui.store
|
||||||
|
|
||||||
import androidx.activity.compose.ReportDrawnWhen
|
import androidx.activity.compose.ReportDrawnWhen
|
||||||
import androidx.compose.animation.core.Ease
|
|
||||||
import androidx.compose.animation.core.animateFloat
|
|
||||||
import androidx.compose.animation.core.infiniteRepeatable
|
|
||||||
import androidx.compose.animation.core.rememberInfiniteTransition
|
|
||||||
import androidx.compose.animation.core.tween
|
|
||||||
import androidx.compose.foundation.gestures.Orientation
|
import androidx.compose.foundation.gestures.Orientation
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
@@ -20,7 +15,6 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.safeDrawing
|
import androidx.compose.foundation.layout.safeDrawing
|
||||||
import androidx.compose.foundation.layout.size
|
|
||||||
import androidx.compose.foundation.layout.systemBars
|
import androidx.compose.foundation.layout.systemBars
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.layout.windowInsetsBottomHeight
|
import androidx.compose.foundation.layout.windowInsetsBottomHeight
|
||||||
@@ -31,11 +25,16 @@ import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells
|
|||||||
import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridItemSpan
|
import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridItemSpan
|
||||||
import androidx.compose.foundation.lazy.staggeredgrid.items
|
import androidx.compose.foundation.lazy.staggeredgrid.items
|
||||||
import androidx.compose.foundation.lazy.staggeredgrid.rememberLazyStaggeredGridState
|
import androidx.compose.foundation.lazy.staggeredgrid.rememberLazyStaggeredGridState
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
|
import androidx.compose.material3.pulltorefresh.PullToRefreshContainer
|
||||||
|
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
@@ -45,7 +44,8 @@ import androidx.compose.runtime.remember
|
|||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.graphicsLayer
|
import androidx.compose.ui.draw.clipToBounds
|
||||||
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
@@ -53,7 +53,6 @@ import androidx.paging.LoadState
|
|||||||
import androidx.paging.compose.LazyPagingItems
|
import androidx.paging.compose.LazyPagingItems
|
||||||
import androidx.paging.compose.collectAsLazyPagingItems
|
import androidx.paging.compose.collectAsLazyPagingItems
|
||||||
import top.fatweb.oxygen.toolbox.R
|
import top.fatweb.oxygen.toolbox.R
|
||||||
import top.fatweb.oxygen.toolbox.icon.Loading
|
|
||||||
import top.fatweb.oxygen.toolbox.icon.OxygenIcons
|
import top.fatweb.oxygen.toolbox.icon.OxygenIcons
|
||||||
import top.fatweb.oxygen.toolbox.model.tool.ToolEntity
|
import top.fatweb.oxygen.toolbox.model.tool.ToolEntity
|
||||||
import top.fatweb.oxygen.toolbox.ui.component.ToolCard
|
import top.fatweb.oxygen.toolbox.ui.component.ToolCard
|
||||||
@@ -90,6 +89,7 @@ internal fun ToolStoreRoute(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
internal fun ToolStoreScreen(
|
internal fun ToolStoreScreen(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
@@ -107,13 +107,25 @@ internal fun ToolStoreScreen(
|
|||||||
|
|
||||||
ReportDrawnWhen { !isToolLoading }
|
ReportDrawnWhen { !isToolLoading }
|
||||||
|
|
||||||
|
val pullToRefreshState = rememberPullToRefreshState()
|
||||||
|
LaunchedEffect(pullToRefreshState.isRefreshing) {
|
||||||
|
if (pullToRefreshState.isRefreshing) {
|
||||||
|
toolStorePagingItems.refresh()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LaunchedEffect(toolStorePagingItems.loadState.refresh) {
|
||||||
|
if (toolStorePagingItems.loadState.refresh is LoadState.Loading) {
|
||||||
|
pullToRefreshState.startRefresh()
|
||||||
|
} else {
|
||||||
|
pullToRefreshState.endRefresh()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val itemsAvailable = toolStorePagingItems.itemCount
|
val itemsAvailable = toolStorePagingItems.itemCount
|
||||||
|
|
||||||
val state = rememberLazyStaggeredGridState()
|
val state = rememberLazyStaggeredGridState()
|
||||||
val scrollbarState = state.scrollbarState(itemsAvailable = itemsAvailable)
|
val scrollbarState = state.scrollbarState(itemsAvailable = itemsAvailable)
|
||||||
|
|
||||||
val infiniteTransition = rememberInfiniteTransition(label = "infiniteTransition")
|
|
||||||
|
|
||||||
var installTool by remember {
|
var installTool by remember {
|
||||||
mutableStateOf(
|
mutableStateOf(
|
||||||
ToolEntity(
|
ToolEntity(
|
||||||
@@ -125,7 +137,10 @@ internal fun ToolStoreScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
modifier.fillMaxSize()
|
modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.clipToBounds()
|
||||||
|
.nestedScroll(pullToRefreshState.nestedScrollConnection)
|
||||||
) {
|
) {
|
||||||
LazyVerticalStaggeredGrid(
|
LazyVerticalStaggeredGrid(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -154,28 +169,11 @@ internal fun ToolStoreScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (toolStorePagingItems.loadState.refresh is LoadState.Loading) {
|
PullToRefreshContainer(
|
||||||
Column(
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
verticalArrangement = Arrangement.Center
|
|
||||||
) {
|
|
||||||
val angle by infiniteTransition.animateFloat(
|
|
||||||
initialValue = 0F,
|
|
||||||
targetValue = 360F,
|
|
||||||
animationSpec = infiniteRepeatable(
|
|
||||||
animation = tween(durationMillis = 800, easing = Ease),
|
|
||||||
), label = "angle"
|
|
||||||
)
|
|
||||||
Icon(
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.size(32.dp)
|
.align(Alignment.TopCenter),
|
||||||
.graphicsLayer { rotationZ = angle },
|
state = pullToRefreshState,
|
||||||
imageVector = Loading,
|
|
||||||
contentDescription = ""
|
|
||||||
)
|
)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (itemsAvailable == 0 && !isToolLoading) {
|
if (itemsAvailable == 0 && !isToolLoading) {
|
||||||
Column(
|
Column(
|
||||||
|
|||||||
Reference in New Issue
Block a user