@@ -44,6 +44,7 @@ import androidx.compose.ui.graphics.ImageBitmap
4444import androidx.compose.ui.graphics.asAndroidBitmap
4545import androidx.compose.ui.graphics.asImageBitmap
4646import androidx.compose.ui.graphics.drawscope.DrawScope
47+ import androidx.compose.ui.graphics.drawscope.Stroke
4748import androidx.compose.ui.graphics.drawscope.clipRect
4849import androidx.compose.ui.graphics.nativeCanvas
4950import androidx.compose.ui.graphics.rememberGraphicsLayer
@@ -56,9 +57,10 @@ import androidx.compose.ui.unit.Velocity
5657import androidx.compose.ui.unit.dp
5758import androidx.compose.ui.unit.sp
5859import com.smarttoolfactory.tutorial1_1basics.R
60+ import com.smarttoolfactory.tutorial1_1basics.chapter3_layout.chat.MessageStatus
61+ import com.smarttoolfactory.tutorial1_1basics.chapter3_layout.chat.SentMessageRowAlt
5962import com.smarttoolfactory.tutorial1_1basics.chapter6_graphics.randomInRange
6063import com.smarttoolfactory.tutorial1_1basics.chapter6_graphics.scale
61- import com.smarttoolfactory.tutorial1_1basics.ui.BlueGrey400
6264import com.smarttoolfactory.tutorial1_1basics.ui.Pink400
6365import kotlinx.coroutines.CancellationException
6466import kotlin.math.roundToInt
@@ -96,6 +98,12 @@ fun SingleParticleTrajectorySample() {
9698
9799 LaunchedEffect (trajectoryProgressStart, trajectoryProgressEnd) {
98100 particleState.particleList.clear()
101+
102+ val velocity = Velocity (
103+ x = sizePxHalf,
104+ y = sizePxHalf * 4
105+ )
106+
99107 particleState.addParticle(
100108 Particle (
101109 color = Pink400 ,
@@ -105,10 +113,8 @@ fun SingleParticleTrajectorySample() {
105113 ),
106114 initialSize = Size (particleSize, particleSize),
107115 endSize = Size (sizePx, sizePx),
108- velocity = Velocity (
109- x = sizePxHalf,
110- y = sizePxHalf * 4
111- ),
116+ velocity = velocity,
117+ acceleration = - 2 * velocity.y,
112118 trajectoryProgressRange = trajectoryProgressStart.. trajectoryProgressEnd
113119 )
114120 )
@@ -213,25 +219,48 @@ fun ParticleAnimationSample() {
213219 }
214220
215221 val particleState = rememberParticleState()
222+ val particleState2 = rememberParticleState()
216223
217224 val context = LocalContext .current
218225
219226 var progress by remember {
220227 mutableFloatStateOf(0f )
221228 }
229+
230+
231+ SentMessageRowAlt (
232+ modifier = Modifier .disintegrate(
233+ // progress = progress,
234+ particleState = particleState,
235+ onStart = {
236+ Toast .makeText(context, " Animation started..." , Toast .LENGTH_SHORT ).show()
237+ },
238+ onEnd = {
239+ particleState.animationStatus = AnimationStatus .Idle
240+ Toast .makeText(context, " Animation ended..." , Toast .LENGTH_SHORT ).show()
241+ }
242+ ),
243+ quotedImage = R .drawable.avatar_4_raster,
244+ text = " Some long message" ,
245+ messageTime = " 11.02.2024" ,
246+ messageStatus = MessageStatus .READ
247+ )
248+
249+ Spacer (Modifier .height(16 .dp))
250+
222251 Image (
223252 painter = painterResource(R .drawable.avatar_2_raster),
224253 modifier = Modifier
225254 .border(2 .dp, Color .Red )
226255 .size(widthDp)
227256 .disintegrate(
228- progress = progress,
229- particleState = particleState ,
257+ // progress = progress,
258+ particleState = particleState2 ,
230259 onStart = {
231260 Toast .makeText(context, " Animation started..." , Toast .LENGTH_SHORT ).show()
232261 },
233262 onEnd = {
234- // particleState .animationStatus = AnimationStatus.Idle
263+ particleState2 .animationStatus = AnimationStatus .Idle
235264 Toast .makeText(context, " Animation ended..." , Toast .LENGTH_SHORT ).show()
236265 }
237266 ),
@@ -250,6 +279,7 @@ fun ParticleAnimationSample() {
250279 modifier = Modifier .fillMaxWidth(),
251280 onClick = {
252281 particleState.startAnimation()
282+ particleState2.startAnimation()
253283 }
254284 ) {
255285 Text (" Convert graphicsLayer to particles" )
@@ -264,7 +294,7 @@ data class Particle(
264294 val trajectoryProgressRange : ClosedRange <Float > = 0f ..1f ,
265295 var color : Color ,
266296 var velocity : Velocity = Velocity (0f, 0f),
267- var acceleration : Float = - 2 * velocity.y
297+ var acceleration : Float = 0f
268298) {
269299 var currentPosition: Offset = initialCenter
270300 internal set
@@ -352,7 +382,7 @@ fun Modifier.disintegrate(
352382}
353383
354384@Composable
355- fun rememberParticleState (particleSize : Dp = 2 .dp): ParticleState {
385+ fun rememberParticleState (particleSize : Dp = 1 .dp): ParticleState {
356386 return remember {
357387 ParticleState (particleSize)
358388 }
@@ -393,9 +423,7 @@ class ParticleState internal constructor(particleSize: Dp) {
393423 if (animationStatus != AnimationStatus .Idle ) {
394424
395425 drawWithLayer {
396-
397426 particleList.forEach { particle ->
398-
399427 updateParticle(progress, particle)
400428
401429 val color = particle.color
@@ -423,12 +451,12 @@ class ParticleState internal constructor(particleSize: Dp) {
423451 }
424452
425453 // For debugging
426- // drawRect(
427- // color = Color.Black,
428- // topLeft = Offset(progress * size.width, 0f),
429- // size = Size(size.width - progress * size.width, size.height),
430- // style = Stroke(4.dp.toPx())
431- // )
454+ drawRect(
455+ color = Color .Black ,
456+ topLeft = Offset (progress * size.width, 0f ),
457+ size = Size (size.width - progress * size.width, size.height),
458+ style = Stroke (4 .dp.toPx())
459+ )
432460 }
433461 }
434462 }
@@ -452,7 +480,6 @@ class ParticleState internal constructor(particleSize: Dp) {
452480 for (column in 0 until width step particleSize) {
453481 for (row in 0 until height step particleSize) {
454482
455-
456483 // Get pixel at center of this pixel rectangle
457484 // If last pixel is out of image get it from end of the width or height
458485 // 🔥x must be < bitmap.width() and y must be < bitmap.height()
@@ -464,11 +491,8 @@ class ParticleState internal constructor(particleSize: Dp) {
464491 val color = Color (pixel)
465492
466493 if (color != Color .Unspecified ) {
494+ // Set center
467495 val initialCenter = Offset (pixelCenterX.toFloat(), pixelCenterY.toFloat())
468- val horizontalDisplacement = randomInRange(- 50f , 50f )
469-
470- val verticalDisplacement = randomInRange(- height * .1f , height * .2f )
471- val acceleration = randomInRange(- 2f , 2f )
472496
473497 // If this particle is at 20% of image width in x plane
474498 // it returns 0.2f
@@ -494,18 +518,34 @@ class ParticleState internal constructor(particleSize: Dp) {
494518 trajectoryProgressRange =
495519 trajectoryProgressRange.start + startYOffset.. trajectoryProgressRange.endInclusive
496520
521+ val imageMinDimension = width.coerceAtMost(height) * 1f
522+
523+ val velocityX = randomInRange(
524+ // Particles close to end should have less randomization to start of image
525+ - (particleSize * 30f * (1 - fractionToImageWidth * .7f ))
526+ .coerceAtMost(imageMinDimension),
527+ (particleSize * 30f ).coerceAtMost(imageMinDimension)
528+ )
529+ val velocityY = randomInRange(
530+ - (particleSize * 20f ).coerceAtMost(imageMinDimension),
531+ (particleSize * 30f ).coerceAtMost(imageMinDimension)
532+ )
533+ val acceleration = randomInRange(- 1f , 1f )
534+
535+ // Set initial and final sizes
536+ val initialSize = Size (particleSize.toFloat(), particleSize.toFloat())
497537 val endSize = randomInRange(0f , particleSize.toFloat() * .5f )
498538
499539 particleList.add(
500540 Particle (
501541 initialCenter = initialCenter,
502- initialSize = Size (particleSize.toFloat(), particleSize.toFloat()),
503- trajectoryProgressRange = trajectoryProgressRange,
542+ initialSize = initialSize,
504543 endSize = Size (endSize, endSize),
544+ trajectoryProgressRange = trajectoryProgressRange,
505545 color = color,
506546 velocity = Velocity (
507- x = horizontalDisplacement ,
508- y = verticalDisplacement
547+ x = velocityX ,
548+ y = velocityY
509549 ),
510550 acceleration = acceleration
511551 )
@@ -544,8 +584,8 @@ class ParticleState internal constructor(particleSize: Dp) {
544584 // While trajectory progress is less than 80% have full alpha then slowly
545585 // reduce to zero for particles to disappear
546586 alpha = if (trajectoryProgress == 0f ) 1f
547- else if (trajectoryProgress < .8f ) 1f
548- else scale(.8f , 1f , trajectoryProgress, 1f , 0f )
587+ else if (trajectoryProgress < .5f ) 1f
588+ else scale(.5f , 1f , trajectoryProgress, 1f , 0f )
549589
550590 val horizontalDisplacement = velocity.x * trajectoryProgress
551591 val verticalDisplacement =
0 commit comments