Skip to content

Commit 6fdb210

Browse files
committed
library: Add InfiniteProgressIndicator Component
1 parent 4e53526 commit 6fdb210

File tree

2 files changed

+74
-1
lines changed

2 files changed

+74
-1
lines changed

composeApp/src/commonMain/kotlin/component/OtherComponent.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import androidx.compose.runtime.getValue
1616
import androidx.compose.runtime.mutableStateOf
1717
import androidx.compose.runtime.remember
1818
import androidx.compose.runtime.setValue
19+
import androidx.compose.ui.Alignment
1920
import androidx.compose.ui.Modifier
2021
import androidx.compose.ui.platform.LocalFocusManager
2122
import androidx.compose.ui.text.font.FontWeight
@@ -27,6 +28,7 @@ import top.yukonga.miuix.kmp.basic.ButtonDefaults
2728
import top.yukonga.miuix.kmp.basic.Card
2829
import top.yukonga.miuix.kmp.basic.CircularProgressIndicator
2930
import top.yukonga.miuix.kmp.basic.Icon
31+
import top.yukonga.miuix.kmp.basic.InfiniteProgressIndicator
3032
import top.yukonga.miuix.kmp.basic.LinearProgressIndicator
3133
import top.yukonga.miuix.kmp.basic.Slider
3234
import top.yukonga.miuix.kmp.basic.SliderDefaults.SliderHapticEffect
@@ -186,7 +188,7 @@ fun OtherComponent(padding: PaddingValues) {
186188
)
187189
}
188190

189-
SmallTitle(text = "LinearProgressIndicator")
191+
SmallTitle(text = "ProgressIndicator")
190192
progressValues.forEach { progressValue ->
191193
LinearProgressIndicator(
192194
progress = progressValue,
@@ -208,6 +210,10 @@ fun OtherComponent(padding: PaddingValues) {
208210
progress = progressValue
209211
)
210212
}
213+
InfiniteProgressIndicator(
214+
modifier = Modifier
215+
.align(alignment = Alignment.CenterVertically)
216+
)
211217
}
212218

213219
SmallTitle(text = "TextField")

miuix/src/commonMain/kotlin/top/yukonga/miuix/kmp/basic/ProgressIndicator.kt

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ import androidx.compose.ui.unit.Dp
2424
import androidx.compose.ui.unit.dp
2525
import top.yukonga.miuix.kmp.basic.ProgressIndicatorDefaults.ProgressIndicatorColors
2626
import top.yukonga.miuix.kmp.theme.MiuixTheme
27+
import kotlin.math.PI
28+
import kotlin.math.cos
29+
import kotlin.math.sin
2730

2831
/**
2932
* A [LinearProgressIndicator] with Miuix style.
@@ -260,6 +263,61 @@ fun CircularProgressIndicator(
260263
}
261264
}
262265

266+
/**
267+
* A [InfiniteProgressIndicator] with Miuix style showing an orbiting dot.
268+
*
269+
* @param modifier The modifier to be applied to the indicator.
270+
* @param color The color of the indicator.
271+
* @param size The size (diameter) of the circular indicator.
272+
* @param strokeWidth The width of the circular stroke.
273+
* @param orbitingDotSize The size of the orbiting dot.
274+
*/
275+
@Composable
276+
fun InfiniteProgressIndicator(
277+
modifier: Modifier = Modifier,
278+
color: Color = Color.Gray,
279+
size: Dp = ProgressIndicatorDefaults.DefaultInfiniteProgressIndicatorSize,
280+
strokeWidth: Dp = ProgressIndicatorDefaults.DefaultInfiniteProgressIndicatorStrokeWidth,
281+
orbitingDotSize: Dp = ProgressIndicatorDefaults.DefaultInfiniteProgressIndicatorOrbitingDotSize
282+
) {
283+
val rotationAnim = remember { Animatable(0f) }
284+
285+
LaunchedEffect(Unit) {
286+
rotationAnim.animateTo(
287+
targetValue = 360f,
288+
animationSpec = infiniteRepeatable(
289+
animation = tween(800, easing = LinearEasing),
290+
repeatMode = RepeatMode.Restart
291+
)
292+
)
293+
}
294+
295+
Canvas(modifier = modifier.size(size)) {
296+
val center = Offset(this.size.width / 2, this.size.height / 2)
297+
val radius = (size.toPx() - strokeWidth.toPx()) / 2
298+
299+
drawCircle(
300+
color = color,
301+
radius = radius,
302+
center = center,
303+
style = Stroke(strokeWidth.toPx(), cap = StrokeCap.Round)
304+
)
305+
306+
val orbitRadius = radius - 2 * orbitingDotSize.toPx()
307+
val angle = rotationAnim.value * PI.toFloat() / 180f
308+
val dotCenter = center + Offset(
309+
x = orbitRadius * cos(angle),
310+
y = orbitRadius * sin(angle)
311+
)
312+
313+
drawCircle(
314+
color = color,
315+
radius = orbitingDotSize.toPx(),
316+
center = dotCenter
317+
)
318+
}
319+
}
320+
263321
object ProgressIndicatorDefaults {
264322
/** The default height of [LinearProgressIndicator]. */
265323
val DefaultLinearProgressIndicatorHeight = 6.dp
@@ -270,6 +328,15 @@ object ProgressIndicatorDefaults {
270328
/** The default size of [CircularProgressIndicator]. */
271329
val DefaultCircularProgressIndicatorSize = 36.dp
272330

331+
/** The default stroke width of [InfiniteProgressIndicator]. */
332+
val DefaultInfiniteProgressIndicatorStrokeWidth = 2.dp
333+
334+
/** The default radius width of the orbiting dot in [InfiniteProgressIndicator]. */
335+
val DefaultInfiniteProgressIndicatorOrbitingDotSize = 2.dp
336+
337+
/** The default size of [InfiniteProgressIndicator]. */
338+
val DefaultInfiniteProgressIndicatorSize = 20.dp
339+
273340
/**
274341
* The default [ProgressIndicatorColors] used in [LinearProgressIndicator].
275342
*/

0 commit comments

Comments
 (0)