Skip to content
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

Feat/android controller functions #3

Merged
Merged
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
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)
}
}
Comment on lines +96 to +126
Copy link

Choose a reason for hiding this comment

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

Lets create eventListeners same as dotLottieController with remember. I think current approach will create new DotLottieEventListener on every composition.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

no it won't because it's on the class so it is created only once

Copy link

Choose a reason for hiding this comment

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

cool we can resolve this

)
)
}
}

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
Loading