about summary refs log tree commit diff
path: root/modules/expo-bluesky-gif-view/src/GifView.web.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'modules/expo-bluesky-gif-view/src/GifView.web.tsx')
-rw-r--r--modules/expo-bluesky-gif-view/src/GifView.web.tsx82
1 files changed, 82 insertions, 0 deletions
diff --git a/modules/expo-bluesky-gif-view/src/GifView.web.tsx b/modules/expo-bluesky-gif-view/src/GifView.web.tsx
new file mode 100644
index 000000000..c197e01a1
--- /dev/null
+++ b/modules/expo-bluesky-gif-view/src/GifView.web.tsx
@@ -0,0 +1,82 @@
+import * as React from 'react'
+import {StyleSheet} from 'react-native'
+
+import {GifViewProps} from './GifView.types'
+
+export class GifView extends React.PureComponent<GifViewProps> {
+  private readonly videoPlayerRef: React.RefObject<HTMLMediaElement> =
+    React.createRef()
+  private isLoaded = false
+
+  constructor(props: GifViewProps | Readonly<GifViewProps>) {
+    super(props)
+  }
+
+  componentDidUpdate(prevProps: Readonly<GifViewProps>) {
+    if (prevProps.autoplay !== this.props.autoplay) {
+      if (this.props.autoplay) {
+        this.playAsync()
+      } else {
+        this.pauseAsync()
+      }
+    }
+  }
+
+  static async prefetchAsync(_: string[]): Promise<void> {
+    console.warn('prefetchAsync is not supported on web')
+  }
+
+  private firePlayerStateChangeEvent = () => {
+    this.props.onPlayerStateChange?.({
+      nativeEvent: {
+        isPlaying: !this.videoPlayerRef.current?.paused,
+        isLoaded: this.isLoaded,
+      },
+    })
+  }
+
+  private onLoad = () => {
+    // Prevent multiple calls to onLoad because onCanPlay will fire after each loop
+    if (this.isLoaded) {
+      return
+    }
+
+    this.isLoaded = true
+    this.firePlayerStateChangeEvent()
+  }
+
+  async playAsync(): Promise<void> {
+    this.videoPlayerRef.current?.play()
+  }
+
+  async pauseAsync(): Promise<void> {
+    this.videoPlayerRef.current?.pause()
+  }
+
+  async toggleAsync(): Promise<void> {
+    if (this.videoPlayerRef.current?.paused) {
+      await this.playAsync()
+    } else {
+      await this.pauseAsync()
+    }
+  }
+
+  render() {
+    return (
+      <video
+        src={this.props.source}
+        autoPlay={this.props.autoplay ? 'autoplay' : undefined}
+        preload={this.props.autoplay ? 'auto' : undefined}
+        playsInline={true}
+        loop="loop"
+        muted="muted"
+        style={StyleSheet.flatten(this.props.style)}
+        onCanPlay={this.onLoad}
+        onPlay={this.firePlayerStateChangeEvent}
+        onPause={this.firePlayerStateChangeEvent}
+        aria-label={this.props.accessibilityLabel}
+        ref={this.videoPlayerRef}
+      />
+    )
+  }
+}