From 1b02f81cb85333462e3a9a42accc05d09aca4f2c Mon Sep 17 00:00:00 2001
From: Hailey <me@haileyok.com>
Date: Wed, 7 Aug 2024 14:45:06 -0700
Subject: [Video] Visibility detection view (#4741)

Co-authored-by: Samuel Newman <10959775+mozzius@users.noreply.github.com>
---
 .../VideoEmbedInner/VideoEmbedInnerNative.tsx      | 96 ++++++++++++++++++++++
 1 file changed, 96 insertions(+)
 create mode 100644 src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx

(limited to 'src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx')

diff --git a/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx b/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx
new file mode 100644
index 000000000..cc356fb06
--- /dev/null
+++ b/src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx
@@ -0,0 +1,96 @@
+import React, {useEffect, useRef, useState} from 'react'
+import {Pressable, View} from 'react-native'
+import {VideoPlayer, VideoView} from 'expo-video'
+
+import {useVideoPlayer} from 'view/com/util/post-embeds/VideoPlayerContext'
+import {android, atoms as a} from '#/alf'
+import {Text} from '#/components/Typography'
+
+export function VideoEmbedInnerNative() {
+  const player = useVideoPlayer()
+  const ref = useRef<VideoView>(null)
+
+  return (
+    <View style={[a.flex_1, a.relative]} collapsable={false}>
+      <VideoView
+        ref={ref}
+        player={player}
+        style={a.flex_1}
+        nativeControls={true}
+      />
+      <Controls
+        player={player}
+        enterFullscreen={() => ref.current?.enterFullscreen()}
+      />
+    </View>
+  )
+}
+
+function Controls({
+  player,
+  enterFullscreen,
+}: {
+  player: VideoPlayer
+  enterFullscreen: () => void
+}) {
+  const [duration, setDuration] = useState(() => Math.floor(player.duration))
+  const [currentTime, setCurrentTime] = useState(() =>
+    Math.floor(player.currentTime),
+  )
+
+  const timeRemaining = duration - currentTime
+  const minutes = Math.floor(timeRemaining / 60)
+  const seconds = String(timeRemaining % 60).padStart(2, '0')
+
+  useEffect(() => {
+    const interval = setInterval(() => {
+      // duration gets reset to 0 on loop
+      if (player.duration) setDuration(Math.floor(player.duration))
+      setCurrentTime(Math.floor(player.currentTime))
+      // how often should we update the time?
+      // 1000 gets out of sync with the video time
+    }, 250)
+
+    return () => {
+      clearInterval(interval)
+    }
+  }, [player])
+
+  if (isNaN(timeRemaining)) {
+    return null
+  }
+
+  return (
+    <View style={[a.absolute, a.inset_0]}>
+      <View
+        style={[
+          {
+            backgroundColor: 'rgba(0, 0, 0, 0.75',
+            borderRadius: 6,
+            paddingHorizontal: 6,
+            paddingVertical: 3,
+            position: 'absolute',
+            left: 5,
+            bottom: 5,
+          },
+        ]}
+        pointerEvents="none">
+        <Text
+          style={[
+            {color: 'white', fontSize: 12},
+            a.font_bold,
+            android({lineHeight: 1.25}),
+          ]}>
+          {minutes}:{seconds}
+        </Text>
+      </View>
+      <Pressable
+        onPress={enterFullscreen}
+        style={a.flex_1}
+        accessibilityLabel="Video"
+        accessibilityHint="Tap to enter full screen"
+        accessibilityRole="button"
+      />
+    </View>
+  )
+}
-- 
cgit 1.4.1

