-
Notifications
You must be signed in to change notification settings - Fork 0
Created a UI component for the core DownloadingProgressDialog #112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
c04b89e
9a62df3
3fcd3f5
a653a96
9f47069
929c642
e5016a2
da2ab2a
50e4689
20117f0
68f42f2
8f64b96
1c5f6aa
d4e930e
aae7391
7befd71
88ba4c6
5fd736f
76e7a25
3530b74
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| package com.urlaunched.android.design.ui.downloadingprogressdialog | ||
|
|
||
| import androidx.compose.animation.core.Animatable | ||
| import androidx.compose.animation.core.tween | ||
| import androidx.compose.runtime.Composable | ||
| import androidx.compose.runtime.LaunchedEffect | ||
| import androidx.compose.runtime.State | ||
| import androidx.compose.runtime.getValue | ||
| import androidx.compose.runtime.mutableLongStateOf | ||
| import androidx.compose.runtime.remember | ||
| import androidx.compose.runtime.rememberCoroutineScope | ||
| import androidx.compose.runtime.setValue | ||
| import kotlinx.coroutines.launch | ||
|
|
||
| private const val MIN_ANIM_DURATION = 1 | ||
| private const val MAX_ANIM_DURATION = 700 | ||
|
|
||
| @Composable | ||
| internal fun animateProgressAsState(progress: Float): State<Float> { | ||
| val coroutineScope = rememberCoroutineScope() | ||
| val animatedProgress = remember { Animatable(progress) } | ||
| var lastTimestamp by remember { mutableLongStateOf(System.currentTimeMillis()) } | ||
|
|
||
| LaunchedEffect(progress) { | ||
| val now = System.currentTimeMillis() | ||
| val deltaT = (now - lastTimestamp).coerceAtLeast(MIN_ANIM_DURATION.toLong()) | ||
|
|
||
| coroutineScope.launch { | ||
| animatedProgress.animateTo( | ||
| targetValue = progress, | ||
| animationSpec = tween( | ||
| durationMillis = deltaT.toInt().coerceIn( | ||
| minimumValue = MIN_ANIM_DURATION, | ||
| maximumValue = MAX_ANIM_DURATION | ||
| ) | ||
| ) | ||
| ) | ||
| } | ||
|
|
||
| lastTimestamp = now | ||
| } | ||
| return animatedProgress.asState() | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,281 @@ | ||
| package com.urlaunched.android.design.ui.downloadingprogressdialog | ||
|
|
||
| import androidx.annotation.FloatRange | ||
| import androidx.compose.foundation.Canvas | ||
| import androidx.compose.foundation.layout.Arrangement | ||
| import androidx.compose.foundation.layout.Box | ||
| import androidx.compose.foundation.layout.BoxScope | ||
| import androidx.compose.foundation.layout.Column | ||
| import androidx.compose.foundation.layout.Row | ||
| import androidx.compose.foundation.layout.fillMaxWidth | ||
| import androidx.compose.foundation.layout.height | ||
| import androidx.compose.foundation.layout.padding | ||
| import androidx.compose.foundation.shape.CircleShape | ||
| import androidx.compose.material3.MaterialTheme | ||
| import androidx.compose.material3.Text | ||
| import androidx.compose.runtime.Composable | ||
| import androidx.compose.runtime.LaunchedEffect | ||
| import androidx.compose.runtime.getValue | ||
| import androidx.compose.runtime.mutableFloatStateOf | ||
| import androidx.compose.runtime.remember | ||
| import androidx.compose.runtime.setValue | ||
| import androidx.compose.ui.Alignment | ||
| import androidx.compose.ui.Modifier | ||
| import androidx.compose.ui.graphics.Brush | ||
| import androidx.compose.ui.graphics.Color | ||
| import androidx.compose.ui.graphics.Path | ||
| import androidx.compose.ui.graphics.Shape | ||
| import androidx.compose.ui.graphics.SolidColor | ||
| import androidx.compose.ui.graphics.addOutline | ||
| import androidx.compose.ui.graphics.drawOutline | ||
| import androidx.compose.ui.graphics.drawscope.clipPath | ||
| import androidx.compose.ui.text.style.TextAlign | ||
| import androidx.compose.ui.tooling.preview.Preview | ||
| import androidx.compose.ui.unit.Dp | ||
| import androidx.compose.ui.unit.dp | ||
| import com.urlaunched.android.design.resources.dimens.Dimens | ||
| import com.urlaunched.android.design.ui.downloadingprogressdialog.models.ProgressTextStyle | ||
| import kotlinx.coroutines.delay | ||
| import kotlinx.coroutines.isActive | ||
|
|
||
| @Composable | ||
| fun AnimatedDownloadingProgressBar( | ||
| modifier: Modifier = Modifier, | ||
| @FloatRange(0.0, 1.0) | ||
| progress: Float, | ||
| trackColor: Color, | ||
| progressColor: Color, | ||
| progressBarHeight: Dp = Dimens.spacingLarge, | ||
| trackShape: Shape = CircleShape, | ||
| progressShape: Shape = trackShape, | ||
| progressText: ((animatedProgress: Float) -> String)? = null, | ||
| progressTextStyle: ProgressTextStyle = ProgressTextStyle(), | ||
| supportingText: (@Composable BoxScope.() -> Unit)? = null | ||
| ) { | ||
| AnimatedDownloadingProgressBar( | ||
| progress = progress, | ||
| trackBrush = SolidColor(trackColor), | ||
| progressBrush = SolidColor(progressColor), | ||
| modifier = modifier, | ||
| progressBarHeight = progressBarHeight, | ||
| trackShape = trackShape, | ||
| progressShape = progressShape, | ||
| progressText = progressText, | ||
| progressTextStyle = progressTextStyle, | ||
| supportingText = supportingText | ||
| ) | ||
| } | ||
|
|
||
| @Composable | ||
| fun AnimatedDownloadingProgressBar( | ||
| modifier: Modifier = Modifier, | ||
| @FloatRange(0.0, 1.0) | ||
| progress: Float, | ||
| trackBrush: Brush, | ||
| progressBrush: Brush, | ||
| progressBarHeight: Dp = Dimens.spacingLarge, | ||
| trackShape: Shape = CircleShape, | ||
| progressShape: Shape = trackShape, | ||
| progressText: ((animatedProgress: Float) -> String)? = null, | ||
| progressTextStyle: ProgressTextStyle = ProgressTextStyle(), | ||
| supportingText: (@Composable BoxScope.() -> Unit)? = null | ||
| ) { | ||
| val animatedProgress by animateProgressAsState(progress = progress) | ||
|
|
||
| DownloadingProgressBar( | ||
| progress = animatedProgress, | ||
| trackBrush = trackBrush, | ||
| progressBrush = progressBrush, | ||
| modifier = modifier, | ||
| progressBarHeight = progressBarHeight, | ||
| trackShape = trackShape, | ||
| progressShape = progressShape, | ||
| supportingText = supportingText, | ||
| progressText = progressText?.invoke(animatedProgress), | ||
| progressTextStyle = progressTextStyle | ||
| ) | ||
| } | ||
|
|
||
| @Composable | ||
| fun DownloadingProgressBar( | ||
| modifier: Modifier = Modifier, | ||
| @FloatRange(0.0, 1.0) | ||
| progress: Float, | ||
| trackColor: Color, | ||
| progressColor: Color, | ||
| progressText: String? = null, | ||
| progressTextStyle: ProgressTextStyle = ProgressTextStyle(), | ||
| progressBarHeight: Dp = Dimens.spacingLarge, | ||
| trackShape: Shape = CircleShape, | ||
| progressShape: Shape = trackShape, | ||
| supportingText: (@Composable BoxScope.() -> Unit)? = null | ||
| ) { | ||
| DownloadingProgressBar( | ||
| progress = progress, | ||
| trackBrush = SolidColor(trackColor), | ||
| progressBrush = SolidColor(progressColor), | ||
| modifier = modifier, | ||
| progressBarHeight = progressBarHeight, | ||
| trackShape = trackShape, | ||
| progressShape = progressShape, | ||
| progressText = progressText, | ||
| progressTextStyle = progressTextStyle, | ||
| supportingText = supportingText | ||
| ) | ||
| } | ||
|
|
||
| @Composable | ||
| fun DownloadingProgressBar( | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Опять много контейнеров наружу смотрит. Разработчик должен сесть за задачу и заиспользовать контейнер, чтобы его не конфузило, какой использовать
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Це варіація з |
||
| modifier: Modifier = Modifier, | ||
| @FloatRange(0.0, 1.0) | ||
| progress: Float, | ||
VMihalatiuk marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| trackBrush: Brush, | ||
| progressBrush: Brush, | ||
| progressText: String? = null, | ||
| progressTextStyle: ProgressTextStyle = ProgressTextStyle(), | ||
| progressBarHeight: Dp = Dimens.spacingLarge, | ||
| trackShape: Shape = CircleShape, | ||
| progressShape: Shape = trackShape, | ||
| supportingText: (@Composable BoxScope.() -> Unit)? = null | ||
| ) { | ||
| Column(modifier = modifier) { | ||
VMihalatiuk marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Box( | ||
| contentAlignment = Alignment.Center | ||
| ) { | ||
| ProgressBar( | ||
| modifier = Modifier | ||
| .fillMaxWidth() | ||
| .height(progressBarHeight), | ||
| progress = progress, | ||
| trackBrush = trackBrush, | ||
| progressBrush = progressBrush, | ||
| trackShape = trackShape, | ||
| progressShape = progressShape | ||
| ) | ||
|
|
||
| if (progressText != null) { | ||
| ProgressText( | ||
| text = progressText, | ||
| progress = progress, | ||
| startColor = progressTextStyle.startColor, | ||
| endColor = progressTextStyle.endColor, | ||
| textAlign = TextAlign.Center, | ||
| modifier = Modifier | ||
| .fillMaxWidth() | ||
| .align(Alignment.Center) | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| supportingText?.let { textContent -> | ||
| Box( | ||
| modifier = Modifier.fillMaxWidth(), | ||
| content = textContent | ||
| ) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| @Composable | ||
| private fun ProgressBar( | ||
| progress: Float, | ||
| modifier: Modifier, | ||
| trackBrush: Brush, | ||
| progressBrush: Brush, | ||
| trackShape: Shape, | ||
| progressShape: Shape | ||
| ) { | ||
| Canvas(modifier = modifier) { | ||
| val trackOutline = trackShape.createOutline(size, layoutDirection, this) | ||
|
|
||
| drawOutline( | ||
| brush = trackBrush, | ||
| outline = trackOutline | ||
| ) | ||
|
|
||
| val progressWidth = size.width * progress | ||
| val progressSize = size.copy(width = progressWidth) | ||
| val progressOutline = progressShape.createOutline(progressSize, layoutDirection, this) | ||
|
|
||
| clipPath( | ||
| path = Path().apply { addOutline(trackOutline) } | ||
| ) { | ||
| drawOutline( | ||
| brush = progressBrush, | ||
| outline = progressOutline | ||
| ) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| @Preview | ||
| @Composable | ||
| private fun GradientProgressBarPreview() { | ||
| val progress = remember { 0.6f } | ||
|
|
||
| DownloadingProgressBar( | ||
| progress = progress, | ||
| progressBarHeight = 50.dp, | ||
| progressBrush = Brush.horizontalGradient( | ||
| 0f to Color.Cyan, | ||
| progress to Color.Magenta | ||
| ), | ||
| trackBrush = SolidColor(Color.LightGray), | ||
| supportingText = { | ||
| Row( | ||
| modifier = Modifier.fillMaxWidth(), | ||
| horizontalArrangement = Arrangement.SpaceBetween | ||
| ) { | ||
| listOf(progress * 100f, 100f).forEach { value -> | ||
| Text( | ||
| text = "${"%.1f".format(value)} MB", | ||
| color = Color.Gray, | ||
| style = MaterialTheme.typography.bodySmall, | ||
| modifier = Modifier.padding( | ||
| horizontal = Dimens.spacingSmall, | ||
| vertical = Dimens.spacingTinyHalf | ||
| ) | ||
| ) | ||
| } | ||
| } | ||
| } | ||
| ) | ||
| } | ||
|
|
||
| @Preview | ||
| @Composable | ||
| private fun SolidProgressBarPreview() { | ||
| DownloadingProgressBar( | ||
| progress = 0.75f, | ||
| progressBarHeight = 50.dp, | ||
| progressColor = Color.Yellow, | ||
| trackColor = Color.LightGray | ||
| ) | ||
| } | ||
|
|
||
| @Preview | ||
| @Composable | ||
| private fun AnimatedProgressBarPreview() { | ||
| var progress by remember { mutableFloatStateOf(0.49f) } | ||
|
|
||
| LaunchedEffect(Unit) { | ||
| while (isActive) { | ||
| delay(500) | ||
| if (progress < 1f) { | ||
| progress += 0.1f | ||
| } else { | ||
| progress = 0f | ||
| } | ||
| } | ||
| } | ||
|
|
||
| AnimatedDownloadingProgressBar( | ||
| progress = progress, | ||
| progressBarHeight = 50.dp, | ||
| progressColor = Color.Red, | ||
| trackColor = Color.LightGray, | ||
| progressText = { animatedProgress -> | ||
| "${"%.1f".format(animatedProgress * 100f)} %" | ||
| } | ||
| ) | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Brush, а той, що нижче, загальний, приймаєBrushнапряму