Skip to content

Instantly share code, notes, and snippets.

@jayesh83
Created December 18, 2022 14:10
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jayesh83/739df59f67ab16876b3df5e6838b04cd to your computer and use it in GitHub Desktop.
Save jayesh83/739df59f67ab16876b3df5e6838b04cd to your computer and use it in GitHub Desktop.
Custom Network Data Usage Indicator UI component with Jetpack Compose
@Composable
fun NetworkUsageIndicator(
modifier: Modifier = Modifier,
indicatorValue: Int = 50,
maxIndicatorValue: Int = 100,
backgroundArcColor: Color = Color.LightGray.copy(alpha = 0.5f),
arcColor: Color = Color.Blue,
radius: Dp = 100.dp,
arcStyle: DrawStyle = Stroke(
width = with(LocalDensity.current) { 32.dp.toPx() },
cap = StrokeCap.Round
),
primaryTextColor: Color = Color.Black,
secondaryTextColor: Color = MaterialTheme.colors.onSurface.copy(alpha = 0.5f)
) {
val localDensity = LocalDensity.current
val startAngle = remember(Unit) { 150f }
val targetAngle = remember(Unit) { 240f }
val radiusPx = remember(radius) {
with(localDensity) { radius.toPx() }
}
val diameterPx = remember(radius) {
with(localDensity) { (radius * 2).toPx() }
}
var currentSweepAngle by remember { mutableStateOf(0f) }
val animatedCurrentSweepAngle by animateFloatAsState(
targetValue = currentSweepAngle,
animationSpec = tween(
durationMillis = 1100,
delayMillis = 200,
easing = FastOutSlowInEasing
)
)
val disabledPrimaryTextColor = remember(primaryTextColor) {
primaryTextColor.copy(alpha = 0.3f)
}
var remainingDataTextColor by remember(disabledPrimaryTextColor) {
mutableStateOf(disabledPrimaryTextColor)
}
val animatedRemainingDataTextColor by animateColorAsState(
targetValue = remainingDataTextColor,
animationSpec = tween(
durationMillis = 1100,
delayMillis = 200,
easing = FastOutSlowInEasing
)
)
val safeIndicatorValue = indicatorValue.coerceAtMost(maxIndicatorValue).coerceAtLeast(0)
val animatedIndicatorValue by animateIntAsState(
targetValue = safeIndicatorValue,
animationSpec = tween(
durationMillis = 1100,
delayMillis = 200,
easing = FastOutSlowInEasing
)
)
LaunchedEffect(keys = arrayOf(safeIndicatorValue, maxIndicatorValue)) {
currentSweepAngle = (targetAngle * safeIndicatorValue) / maxIndicatorValue
remainingDataTextColor = if (safeIndicatorValue == 0) disabledPrimaryTextColor else primaryTextColor
}
Column(
modifier = modifier.drawBehind {
drawArc(
color = backgroundArcColor,
startAngle = startAngle,
sweepAngle = targetAngle,
useCenter = false,
topLeft = Offset(size.width / 2 - radiusPx, size.height / 2 - radiusPx),
size = Size(diameterPx, diameterPx),
style = arcStyle
)
drawArc(
color = arcColor,
startAngle = startAngle,
sweepAngle = animatedCurrentSweepAngle,
useCenter = false,
topLeft = Offset(size.width / 2 - radiusPx, size.height / 2 - radiusPx),
size = Size(diameterPx, diameterPx),
style = arcStyle
)
},
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = stringResource(R.string.remaining),
color = secondaryTextColor
)
Text(
text = "$animatedIndicatorValue GB",
style = TextStyle(fontSize = 40.sp, fontWeight = FontWeight.Bold),
color = animatedRemainingDataTextColor
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment