Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions design/api/current.api
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,61 @@ package com.urlaunched.android.design.ui.counter.ui {

}

package com.urlaunched.android.design.ui.downloadingprogressdialog {

public final class DownloadingProgressBarKt {
method @androidx.compose.runtime.Composable public static void AnimatedDownloadingProgressBar(optional androidx.compose.ui.Modifier modifier, @FloatRange(from=0.0, to=1.0) float progress, androidx.compose.ui.graphics.Brush trackBrush, androidx.compose.ui.graphics.Brush progressBrush, optional float progressBarHeight, optional androidx.compose.ui.graphics.Shape trackShape, optional androidx.compose.ui.graphics.Shape progressShape, optional kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.String>? progressText, optional com.urlaunched.android.design.ui.downloadingprogressdialog.models.ProgressTextStyle progressTextStyle, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? supportingText);
method @androidx.compose.runtime.Composable public static void AnimatedDownloadingProgressBar(optional androidx.compose.ui.Modifier modifier, @FloatRange(from=0.0, to=1.0) float progress, long trackColor, long progressColor, optional float progressBarHeight, optional androidx.compose.ui.graphics.Shape trackShape, optional androidx.compose.ui.graphics.Shape progressShape, optional kotlin.jvm.functions.Function1<? super java.lang.Float,java.lang.String>? progressText, optional com.urlaunched.android.design.ui.downloadingprogressdialog.models.ProgressTextStyle progressTextStyle, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? supportingText);
method @androidx.compose.runtime.Composable public static void DownloadingProgressBar(optional androidx.compose.ui.Modifier modifier, @FloatRange(from=0.0, to=1.0) float progress, androidx.compose.ui.graphics.Brush trackBrush, androidx.compose.ui.graphics.Brush progressBrush, optional String? progressText, optional com.urlaunched.android.design.ui.downloadingprogressdialog.models.ProgressTextStyle progressTextStyle, optional float progressBarHeight, optional androidx.compose.ui.graphics.Shape trackShape, optional androidx.compose.ui.graphics.Shape progressShape, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? supportingText);
method @androidx.compose.runtime.Composable public static void DownloadingProgressBar(optional androidx.compose.ui.Modifier modifier, @FloatRange(from=0.0, to=1.0) float progress, long trackColor, long progressColor, optional String? progressText, optional com.urlaunched.android.design.ui.downloadingprogressdialog.models.ProgressTextStyle progressTextStyle, optional float progressBarHeight, optional androidx.compose.ui.graphics.Shape trackShape, optional androidx.compose.ui.graphics.Shape progressShape, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? supportingText);
}

public final class DownloadingProgressDialogKt {
method @androidx.compose.runtime.Composable public static void BaseDownloadingProgressDialog(optional androidx.compose.ui.Modifier modifier, @com.composables.core.androidx.annotation.FloatRange(from=0.0, to=1.0) float progress, optional String? progressText, optional com.urlaunched.android.design.ui.downloadingprogressdialog.models.ProgressTextStyle progressTextStyle, optional com.urlaunched.android.design.ui.downloadingprogressdialog.models.ProgressBarStyle progressBarStyle, optional kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional long dialogContainerColor, optional androidx.compose.ui.graphics.Shape dialogContainerShape, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.ui.window.DialogProperties dialogProperties, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? title, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? description, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? supportingText, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? bottomContent);
method @androidx.compose.runtime.Composable public static void DownloadingProgressDialog(optional androidx.compose.ui.Modifier modifier, @com.composables.core.androidx.annotation.FloatRange(from=0.0, to=1.0) float progress, optional String? progressText, optional com.urlaunched.android.design.ui.downloadingprogressdialog.models.ProgressTextStyle progressTextStyle, optional com.urlaunched.android.design.ui.downloadingprogressdialog.models.ProgressBarStyle progressBarStyle, optional long dialogContainerColor, optional kotlin.jvm.functions.Function0<kotlin.Unit> onDismissRequest, optional androidx.compose.ui.graphics.Shape dialogContainerShape, optional androidx.compose.foundation.layout.PaddingValues contentPadding, optional androidx.compose.ui.window.DialogProperties dialogProperties, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? title, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? description, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.BoxScope,kotlin.Unit>? supportingText, optional kotlin.jvm.functions.Function1<? super androidx.compose.foundation.layout.ColumnScope,kotlin.Unit>? bottomContent);
}

}

package com.urlaunched.android.design.ui.downloadingprogressdialog.models {

public final class ProgressBarStyle {
ctor public ProgressBarStyle(optional float progressBarHeight, androidx.compose.ui.graphics.Brush trackBrush, androidx.compose.ui.graphics.Brush progressBrush, optional androidx.compose.ui.graphics.Shape trackShape, optional androidx.compose.ui.graphics.Shape progressShape);
ctor public ProgressBarStyle(optional float progressBarHeight, optional long trackColor, optional long progressColor, optional androidx.compose.ui.graphics.Shape trackShape, optional androidx.compose.ui.graphics.Shape progressShape);
method public float component1-D9Ej5fM();
method public androidx.compose.ui.graphics.Brush component2();
method public androidx.compose.ui.graphics.Brush component3();
method public androidx.compose.ui.graphics.Shape component4();
method public androidx.compose.ui.graphics.Shape component5();
method public com.urlaunched.android.design.ui.downloadingprogressdialog.models.ProgressBarStyle copy--orJrPs(float progressBarHeight, androidx.compose.ui.graphics.Brush trackBrush, androidx.compose.ui.graphics.Brush progressBrush, androidx.compose.ui.graphics.Shape trackShape, androidx.compose.ui.graphics.Shape progressShape);
method public float getProgressBarHeight();
method public androidx.compose.ui.graphics.Brush getProgressBrush();
method public androidx.compose.ui.graphics.Shape getProgressShape();
method public androidx.compose.ui.graphics.Brush getTrackBrush();
method public androidx.compose.ui.graphics.Shape getTrackShape();
property public final float progressBarHeight;
property public final androidx.compose.ui.graphics.Brush progressBrush;
property public final androidx.compose.ui.graphics.Shape progressShape;
property public final androidx.compose.ui.graphics.Brush trackBrush;
property public final androidx.compose.ui.graphics.Shape trackShape;
}

public final class ProgressTextStyle {
ctor public ProgressTextStyle(optional androidx.compose.ui.text.TextStyle textStyle, optional long startColor, optional long endColor);
method public androidx.compose.ui.text.TextStyle component1();
method public long component2-0d7_KjU();
method public long component3-0d7_KjU();
method public com.urlaunched.android.design.ui.downloadingprogressdialog.models.ProgressTextStyle copy-WkMS-hQ(androidx.compose.ui.text.TextStyle textStyle, long startColor, long endColor);
method public long getEndColor();
method public long getStartColor();
method public androidx.compose.ui.text.TextStyle getTextStyle();
property public final long endColor;
property public final long startColor;
property public final androidx.compose.ui.text.TextStyle textStyle;
}

}

package com.urlaunched.android.design.ui.expandabletext {

public final class ExpandableTextKt {
Expand Down
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(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Зачем нужна дополнительная обертка? Снизу есть тоже AnimatedDownloadingProgressBar
  2. Давай не указывать в названии слово Animated

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Цей приймає колір і перетворює його в Brush, а той, що нижче, загальний, приймає Brush напряму
  2. Як тоді розрізняти той, що з анімацією, і той то, що без?

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(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Опять много контейнеров наружу смотрит. Разработчик должен сесть за задачу и заиспользовать контейнер, чтобы его не конфузило, какой использовать

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Це варіація з Brush і без анімації

modifier: Modifier = Modifier,
@FloatRange(0.0, 1.0)
progress: Float,
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) {
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)} %"
}
)
}
Loading