Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Zhirkevich Alexander Y authored and Zhirkevich Alexander Y committed May 29, 2024
1 parent b9faa62 commit 5b0748f
Show file tree
Hide file tree
Showing 33 changed files with 597 additions and 133 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package io.github.alexzhirkevich.compottie.internal.platform

import android.graphics.BitmapFactory
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.asImageBitmap

internal actual fun ImageBitmap.Companion.fromBytes(bytes: ByteArray) : ImageBitmap {
return BitmapFactory.decodeByteArray(bytes, 0, bytes.size).asImageBitmap()
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import androidx.compose.runtime.Immutable
sealed class LottieCompositionSpec {

@Immutable
class JsonString constructor(
class JsonString(
internal val jsonString: String
) : LottieCompositionSpec() {
override fun equals(other: Any?): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,87 +2,120 @@ package io.github.alexzhirkevich.compottie

import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.produceState
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.geometry.MutableRect
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.Matrix
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.graphics.drawscope.scale
import androidx.compose.ui.graphics.drawscope.translate
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.withSave
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.util.fastForEachReversed
import io.github.alexzhirkevich.compottie.internal.content.Content
import io.github.alexzhirkevich.compottie.internal.content.DrawingContent
import io.github.alexzhirkevich.compottie.internal.utils.preScale
import io.github.alexzhirkevich.compottie.internal.utils.preTranslate
import io.github.alexzhirkevich.compottie.internal.services.LottieImageService
import io.github.alexzhirkevich.compottie.internal.services.LottieServiceLocator
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonClassDiscriminator
import kotlin.math.roundToInt


@Composable
fun rememberLottiePainter(
composition : LottieCompositionResult,
maintainOriginalImageBounds: Boolean = false,
onLoadError : (Throwable) -> Painter = { EmptyPainter },
progress : () -> Float
) : Painter {

val painter by produceState<ProgressPainter>(EmptyPainter){
value = LottiePainter(composition.await())
val painter by produceState<Painter>(EmptyPainter) {
value = try {
LottiePainter(
composition = composition.await(),
maintainOriginalImageBounds = maintainOriginalImageBounds
)
} catch (t : Throwable) {
onLoadError(t)
}
}

LaunchedEffect(painter){
snapshotFlow {
progress()
}.collect {
painter.progress = it
(painter as? LottiePainter)?.progress = it
}
}

return painter
}

private abstract class ProgressPainter : Painter() {

abstract var progress : Float
}

private object EmptyPainter : ProgressPainter() {
private object EmptyPainter : Painter() {

override var progress: Float = 0f

override val intrinsicSize: Size = Size(1f,1f)

override fun DrawScope.onDraw() {
}

}

private class LottiePainter(
private val composition: LottieComposition,
private val clipToCompositionBounds : Boolean = true
) : ProgressPainter() {
private val maintainOriginalImageBounds : Boolean,
) : Painter() {

override val intrinsicSize: Size = Size(
composition.lottieData.width.toFloat(),
composition.lottieData.height.toFloat()
)

override var progress: Float by mutableStateOf(0f)
var progress: Float by mutableStateOf(0f)

private val matrix = Matrix()

private var alpha by mutableStateOf(1f)

private val currentFrame by derivedStateOf {
val p = composition.lottieData.outPoint * progress.coerceIn(0f, 1f) -
composition.lottieData.inPoint
p.coerceAtLeast(0f).roundToInt()
}

private var serviceLocator = LottieServiceLocator(
LottieImageService(
maintainOriginalImageBounds = maintainOriginalImageBounds,
assets = composition.lottieData.assets
)
)

init {
composition.lottieData.layers.forEach {
it.serviceLocator = serviceLocator
}
}

override fun applyAlpha(alpha: Float): Boolean {
if (alpha !in 0f..1f)
return false

this.alpha = alpha
return true
}


override fun DrawScope.onDraw() {

drawIntoCanvas { canvas ->
Expand All @@ -103,22 +136,19 @@ private class LottiePainter(
layoutDirection
)


// matrix.preScale(scale.scaleX, scale.scaleY)
// matrix.preTranslate(offset.x.toFloat(), offset.y.toFloat())

val dat = composition.lottieData

val frame = (dat.outPoint * progress.coerceIn(0f, 1f) - dat.inPoint)
.coerceAtLeast(0f).roundToInt()

scale(scale.scaleX, scale.scaleY) {
translate(offset.x.toFloat(), offset.y.toFloat()) {
dat.layers.fastForEachReversed {
// scale(scale.scaleX, scale.scaleY) {
// translate(offset.x.toFloat(), offset.y.toFloat()) {
composition.lottieData.layers.fastForEachReversed {
if (it is DrawingContent) {
it.draw(canvas, matrix, alpha, frame)
}
}
it.density = density
try {
it.draw(canvas, matrix, alpha, currentFrame)
} catch (t: Throwable) {
println("Lottie crashed in draw :(")
t.printStackTrace()
}
// }
// }
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package io.github.alexzhirkevich.compottie.internal.content


interface Content {

val name: String?

fun setContents(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import androidx.compose.ui.graphics.Canvas
import androidx.compose.ui.graphics.Matrix
import androidx.compose.ui.graphics.Paint
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.util.fastForEachReversed
import io.github.alexzhirkevich.compottie.internal.platform.addPath
import io.github.alexzhirkevich.compottie.internal.schema.helpers.AnimatedTransform
import io.github.alexzhirkevich.compottie.internal.schema.helpers.Transform
import io.github.alexzhirkevich.compottie.internal.schema.shapes.TransformShape
import io.github.alexzhirkevich.compottie.internal.utils.Utils
import io.github.alexzhirkevich.compottie.internal.utils.preConcat
import io.github.alexzhirkevich.compottie.internal.utils.union
Expand All @@ -27,6 +29,7 @@ internal class ContentGroup(
private val path = Path()
private var pathContents: MutableList<PathContent>? = null

private val boundsRect = MutableRect(0f,0f,0f,0f)

override fun draw(canvas: Canvas, parentMatrix: Matrix, parentAlpha: Float, frame: Int) {
if (hidden) {
Expand All @@ -40,7 +43,7 @@ internal class ContentGroup(
if (transform != null) {
matrix.preConcat(transform.matrix(frame))
transform.opacity?.interpolated(frame)?.let {
layerAlpha = (layerAlpha * it/100f).coerceIn(0f,1f)
layerAlpha = (layerAlpha * it / 100f).coerceIn(0f, 1f)
}
}

Expand Down Expand Up @@ -78,12 +81,12 @@ internal class ContentGroup(
if (hidden) {
return path
}
for (i in contents.indices.reversed()) {
val content = contents[i]
if (content is PathContent) {
path.addPath(content.getPath(frame), matrix)
contents.fastForEachReversed {
if (it is PathContent) {
path.addPath(it.getPath(frame), matrix)
}
}

return path
}

Expand All @@ -110,11 +113,11 @@ internal class ContentGroup(
matrix.preConcat(transform.matrix(frame))
}

rect.set(0f,0f,0f,0f)
for (i in contents.indices.reversed()) {
val content = contents[i]
if (content is DrawingContent) {
content.getBounds(rect, matrix, applyParents, frame)
rect.set(0f, 0f, 0f, 0f)

contents.fastForEachReversed {
if (it is DrawingContent) {
it.getBounds(rect, matrix, applyParents, frame)
outBounds.union(rect)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package io.github.alexzhirkevich.compottie.internal.platform

import androidx.compose.ui.graphics.ImageBitmap

internal expect fun ImageBitmap.Companion.fromBytes(bytes: ByteArray) : ImageBitmap
Original file line number Diff line number Diff line change
@@ -1,31 +1,35 @@
package io.github.alexzhirkevich.compottie.internal.schema

import io.github.alexzhirkevich.compottie.internal.schema.layers.Layer
import io.github.alexzhirkevich.compottie.internal.schema.layers.NullLayer
import io.github.alexzhirkevich.compottie.internal.schema.layers.ShapeLayer
import io.github.alexzhirkevich.compottie.internal.schema.properties.AnimatedVector2
import io.github.alexzhirkevich.compottie.internal.schema.properties.AnimatedValue
import io.github.alexzhirkevich.compottie.internal.schema.shapes.Ellipse
import io.github.alexzhirkevich.compottie.internal.schema.shapes.Fill
import io.github.alexzhirkevich.compottie.internal.schema.shapes.EllipseShape
import io.github.alexzhirkevich.compottie.internal.schema.shapes.FillShape
import io.github.alexzhirkevich.compottie.internal.schema.shapes.GradientFill
import io.github.alexzhirkevich.compottie.internal.schema.shapes.GradientStroke
import io.github.alexzhirkevich.compottie.internal.schema.shapes.GroupShape
import io.github.alexzhirkevich.compottie.internal.schema.shapes.Rect
import io.github.alexzhirkevich.compottie.internal.schema.shapes.RectShape
import io.github.alexzhirkevich.compottie.internal.schema.shapes.Shape
import io.github.alexzhirkevich.compottie.internal.schema.shapes.SolidStroke
import io.github.alexzhirkevich.compottie.internal.schema.shapes.SolidStrokeShape
import io.github.alexzhirkevich.compottie.internal.schema.shapes.TransformShape
import io.github.alexzhirkevich.compottie.internal.schema.shapes.TrimPath
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.polymorphic
import kotlinx.serialization.modules.subclass

@OptIn(ExperimentalSerializationApi::class)
val LottieJson = Json {
ignoreUnknownKeys = true
isLenient = true

allowTrailingComma = true
serializersModule = SerializersModule {
polymorphic(Layer::class){
subclass(ShapeLayer::class)
subclass(NullLayer::class)
}

polymorphic(AnimatedValue::class){
Expand All @@ -38,13 +42,13 @@ val LottieJson = Json {
}
polymorphic(Shape::class){
// subclass(Path::class)
subclass(Ellipse::class)
subclass(Fill::class)
subclass(EllipseShape::class)
subclass(FillShape::class)
subclass(GradientFill::class)
subclass(GroupShape::class)
subclass(Rect::class)
subclass(RectShape::class)
// subclass(Round::class)
subclass(SolidStroke::class)
subclass(SolidStrokeShape::class)
subclass(GradientStroke::class)
subclass(TrimPath::class)
subclass(TransformShape::class)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.github.alexzhirkevich.compottie.internal.schema

import io.github.alexzhirkevich.compottie.internal.schema.assets.LottieAsset
import io.github.alexzhirkevich.compottie.internal.schema.layers.Layer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
Expand Down Expand Up @@ -28,7 +29,9 @@ internal class LottieData(
@SerialName("nm")
val name : String,

val layers: List<Layer>
val layers: List<Layer> = emptyList(),

val assets : List<LottieAsset> = emptyList()
)

internal val LottieData.durationMillis
Expand Down
Loading

0 comments on commit 5b0748f

Please sign in to comment.