Skip to content

Commit

Permalink
feat: dotLottie IOS & Android integration (#3)
Browse files Browse the repository at this point in the history
* chore: initial commit

* chore: basic dotlottie configuration for android

* chore: relating branches

* chore: fixed readme

* feat: android functions

* feat: android dotlottie controller functions

* feat: listeners update

* chore: completed android functions and props

* chore: pr fixes

* chore: ci fixes

* chore: ci fixes

* chore: ci fixes

* feat: ios function manually

* feat: ios function manually

* feat: ios functions

* feat: more ios functions

* feat: state machine events

* fix: ci fix

---------

Co-authored-by: Shamsudeen Yusuf <[email protected]>
  • Loading branch information
shamsudeeen-yusuf and elasoshi authored Oct 8, 2024
1 parent 0881399 commit 3e24262
Show file tree
Hide file tree
Showing 24 changed files with 1,369 additions and 1,566 deletions.
48 changes: 44 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,52 @@ npm install dotlottie-react-native

## Usage

```js
import { DotlottieReactNativeView } from 'dotlottie-react-native';
```ts
import { Button, StyleSheet, View } from 'react-native';
import { DotLottie, Mode, type Dotlottie } from 'dotlottie-react-native';
import { useRef } from 'react';

// ...
export default function App() {
const ref = useRef<Dotlottie>(null);

<DotlottieReactNativeView color="tomato" />;
return (
<View style={styles.container}>
<DotLottie
ref={ref}
source={require('../assets/animation.lottie')}
style={styles.box}
loop={false}
autoplay={false}
/>
<Button title="Play" onPress={() => ref.current?.play()} />
<Button title="Pause" onPress={() => ref.current?.pause()} />
<Button title="Stop" onPress={() => ref.current?.stop()} />
<Button title="Loop" onPress={() => ref.current?.setLoop(true)} />
<Button title="Speed" onPress={() => ref.current?.setSpeed(1)} />
<Button
title="FORWARD"
onPress={() => ref.current?.setPlayMode(Mode.FORWARD)}
/>
<Button
title="REVERSE"
onPress={() => ref.current?.setPlayMode(Mode.REVERSE)}
/>
</View>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
box: {
width: 200,
height: 200,
marginVertical: 20,
},
});
```

## Contributing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@ import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.uimanager.ViewManager


class DotlottieReactNativePackage : ReactPackage {
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
return emptyList()
return listOf()
}

override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
package com.dotlottiereactnative

import android.widget.FrameLayout
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.platform.ComposeView
import com.dotlottie.dlplayer.Event
import com.dotlottie.dlplayer.Mode
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.ReactContext
import com.facebook.react.bridge.WritableMap
import com.facebook.react.uimanager.ThemedReactContext
import com.facebook.react.uimanager.events.RCTEventEmitter
import com.lottiefiles.dotlottie.core.compose.runtime.DotLottieController
import com.lottiefiles.dotlottie.core.compose.ui.DotLottieAnimation
import com.lottiefiles.dotlottie.core.util.DotLottieEventListener
import com.lottiefiles.dotlottie.core.util.DotLottieSource
import com.lottiefiles.dotlottie.core.util.StateMachineEventListener

class DotlottieReactNativeView(context: ThemedReactContext) : FrameLayout(context) {

private var reactContext: ReactContext = context.reactApplicationContext
private var animationUrl: String? = null
private var loop: Boolean = false
private var autoplay: Boolean = true
private var speed: Float = 1f
private var useFrameInterpolation: Boolean = false
private var themeId: String? = null
private var marker: String? = null
private var segment: Pair<Float, Float>? = null
private var playMode: Mode = Mode.FORWARD
var dotLottieController: DotLottieController = DotLottieController()

private val composeView: ComposeView =
ComposeView(context).apply {
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
}

init {
addView(composeView)
// Set initial content
composeView.setContent { DotLottieContent() }
}

fun onReceiveNativeEvent(eventName: String, value: WritableMap?) {

reactContext.getJSModule(RCTEventEmitter::class.java).receiveEvent(id, eventName, value)
}

@Composable
fun DotLottieContent() {
dotLottieController = remember { DotLottieController() }

val stateListener = remember {
object : StateMachineEventListener {
override fun onTransition(previousState: String, newState: String) {
val value =
Arguments.createMap().apply {
putString("previousState", previousState)
putString("newState", newState)
}

onReceiveNativeEvent("onTransition", value)
}

override fun onStateExit(leavingState: String) {
val value = Arguments.createMap().apply { putString("leavingState", leavingState) }
onReceiveNativeEvent("onStateExit", value)
}

override fun onStateEntered(enteringState: String) {
val value = Arguments.createMap().apply { putString("enteringState", enteringState) }
println("enteringState")
onReceiveNativeEvent("onStateEntered", value)
}
}
}

LaunchedEffect(UInt) { dotLottieController.addStateMachineEventListener(stateListener) }

animationUrl?.let { url ->
DotLottieAnimation(
source = DotLottieSource.Url(url),
autoplay = autoplay,
loop = loop,
speed = speed,
controller = dotLottieController,
useFrameInterpolation = useFrameInterpolation,
themeId = themeId,
marker = marker,
segment = segment,
playMode = playMode,
eventListeners =
listOf(
object : DotLottieEventListener {
override fun onLoad() {
onReceiveNativeEvent("onLoad", null)
}
override fun onComplete() {

onReceiveNativeEvent("onComplete", null)
}
override fun onLoadError() {

onReceiveNativeEvent("onLoadError", null)
}
override fun onPlay() {
onReceiveNativeEvent("onPlay", null)
}
override fun onStop() {
onReceiveNativeEvent("onRender", null)
}
override fun onPause() {
onReceiveNativeEvent("onPause", null)
}
override fun onFreeze() {
onReceiveNativeEvent("onFreeze", null)
}
override fun onUnFreeze() {
onReceiveNativeEvent("onUnFreeze", null)
}
override fun onDestroy() {
onReceiveNativeEvent("onDestroy", null)
}
}
)
)
}
}

fun setSource(url: String?) {
animationUrl = url
composeView.setContent { DotLottieContent() }
}

fun setLoop(value: Boolean) {
loop = value
composeView.setContent { DotLottieContent() }
}

fun setAutoPlay(value: Boolean) {
autoplay = value
composeView.setContent { DotLottieContent() }
}

fun setSpeed(value: Double) {
speed = value.toFloat()
composeView.setContent { DotLottieContent() }
}

fun setUseFrameInterpolation(value: Boolean) {
useFrameInterpolation = value
composeView.setContent { DotLottieContent() }
}

fun setThemeId(value: String?) {
themeId = value
composeView.setContent { DotLottieContent() }
}

fun setMarker(value: String?) {
marker = value
composeView.setContent { DotLottieContent() }
}

fun setSegment(start: Double, end: Double) {
segment = Pair(start.toFloat(), end.toFloat())
composeView.setContent { DotLottieContent() }
}

fun postEvent(event: String) {
dotLottieController.postEvent(Event.String(event))
}

fun resize(width: UInt, height: UInt) {
dotLottieController.resize(width, height)
}
}
Loading

0 comments on commit 3e24262

Please sign in to comment.