Skip to content

Commit b69c40d

Browse files
authored
add indicator of time remaining (#5000)
1 parent 9b534b9 commit b69c40d

File tree

3 files changed

+58
-35
lines changed

3 files changed

+58
-35
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import React from 'react'
2+
import Animated, {FadeInDown, FadeOutDown} from 'react-native-reanimated'
3+
4+
import {atoms as a, native, useTheme} from '#/alf'
5+
import {Text} from '#/components/Typography'
6+
7+
/**
8+
* Absolutely positioned time indicator showing how many seconds are remaining
9+
* Time is in seconds
10+
*/
11+
export function TimeIndicator({time}: {time: number}) {
12+
const t = useTheme()
13+
14+
if (isNaN(time)) {
15+
return null
16+
}
17+
18+
const minutes = Math.floor(time / 60)
19+
const seconds = String(time % 60).padStart(2, '0')
20+
21+
return (
22+
<Animated.View
23+
entering={native(FadeInDown.duration(300))}
24+
exiting={native(FadeOutDown.duration(500))}
25+
style={[
26+
{
27+
backgroundColor: 'rgba(0, 0, 0, 0.5)',
28+
borderRadius: 6,
29+
paddingHorizontal: 6,
30+
paddingVertical: 3,
31+
position: 'absolute',
32+
left: 5,
33+
bottom: 5,
34+
minHeight: 20,
35+
justifyContent: 'center',
36+
},
37+
]}>
38+
<Text
39+
style={[
40+
{color: t.palette.white, fontSize: 12},
41+
a.font_bold,
42+
{lineHeight: 1.25},
43+
]}>
44+
{minutes}:{seconds}
45+
</Text>
46+
</Animated.View>
47+
)
48+
}

src/view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative.tsx

Lines changed: 6 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React, {useCallback, useEffect, useRef, useState} from 'react'
22
import {Pressable, View} from 'react-native'
3-
import Animated, {FadeInDown, FadeOutDown} from 'react-native-reanimated'
3+
import Animated, {FadeInDown} from 'react-native-reanimated'
44
import {VideoPlayer, VideoView} from 'expo-video'
55
import {msg} from '@lingui/macro'
66
import {useLingui} from '@lingui/react'
@@ -10,14 +10,14 @@ import {HITSLOP_30} from '#/lib/constants'
1010
import {useAppState} from '#/lib/hooks/useAppState'
1111
import {logger} from '#/logger'
1212
import {useVideoPlayer} from '#/view/com/util/post-embeds/VideoPlayerContext'
13-
import {android, atoms as a, useTheme} from '#/alf'
13+
import {atoms as a, useTheme} from '#/alf'
1414
import {Mute_Stroke2_Corner0_Rounded as MuteIcon} from '#/components/icons/Mute'
1515
import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as UnmuteIcon} from '#/components/icons/Speaker'
16-
import {Text} from '#/components/Typography'
1716
import {
1817
AudioCategory,
1918
PlatformInfo,
2019
} from '../../../../../../modules/expo-bluesky-swiss-army'
20+
import {TimeIndicator} from './TimeIndicator'
2121

2222
export function VideoEmbedInnerNative() {
2323
const player = useVideoPlayer()
@@ -86,10 +86,6 @@ function Controls({
8686
Math.floor(player.currentTime),
8787
)
8888

89-
const timeRemaining = duration - currentTime
90-
const minutes = Math.floor(timeRemaining / 60)
91-
const seconds = String(timeRemaining % 60).padStart(2, '0')
92-
9389
useEffect(() => {
9490
const interval = setInterval(() => {
9591
// duration gets reset to 0 on loop
@@ -143,37 +139,12 @@ function Controls({
143139
// 1. timeRemaining is a number - was seeing NaNs
144140
// 2. duration is greater than 0 - means metadata has loaded
145141
// 3. we're less than 5 second into the video
142+
const timeRemaining = duration - currentTime
146143
const showTime = !isNaN(timeRemaining) && duration > 0 && currentTime <= 5
147144

148145
return (
149146
<View style={[a.absolute, a.inset_0]}>
150-
{showTime && (
151-
<Animated.View
152-
entering={FadeInDown.duration(300)}
153-
exiting={FadeOutDown.duration(500)}
154-
style={[
155-
{
156-
backgroundColor: 'rgba(0, 0, 0, 0.75)',
157-
borderRadius: 6,
158-
paddingHorizontal: 6,
159-
paddingVertical: 3,
160-
position: 'absolute',
161-
left: 5,
162-
bottom: 5,
163-
minHeight: 20,
164-
justifyContent: 'center',
165-
},
166-
]}>
167-
<Text
168-
style={[
169-
{color: t.palette.white, fontSize: 12},
170-
a.font_bold,
171-
android({lineHeight: 1.25}),
172-
]}>
173-
{minutes}:{seconds}
174-
</Text>
175-
</Animated.View>
176-
)}
147+
{showTime && <TimeIndicator time={timeRemaining} />}
177148
<Pressable
178149
onPress={onPressFullscreen}
179150
style={a.flex_1}
@@ -185,7 +156,7 @@ function Controls({
185156
<Animated.View
186157
entering={FadeInDown.duration(300)}
187158
style={{
188-
backgroundColor: 'rgba(0, 0, 0, 0.75)',
159+
backgroundColor: 'rgba(0, 0, 0, 0.5)',
189160
borderRadius: 6,
190161
paddingHorizontal: 6,
191162
paddingVertical: 3,

src/view/com/util/post-embeds/VideoEmbedInner/VideoWebControls.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import {Play_Filled_Corner0_Rounded as PlayIcon} from '#/components/icons/Play'
3636
import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as UnmuteIcon} from '#/components/icons/Speaker'
3737
import {Loader} from '#/components/Loader'
3838
import {Text} from '#/components/Typography'
39+
import {TimeIndicator} from './TimeIndicator'
3940

4041
export function Controls({
4142
videoRef,
@@ -252,6 +253,9 @@ export function Controls({
252253
style={a.flex_1}
253254
onPress={onPressEmptySpace}
254255
/>
256+
{active && !showControls && !focused && (
257+
<TimeIndicator time={Math.floor(duration - currentTime)} />
258+
)}
255259
<View
256260
style={[
257261
a.flex_shrink_0,

0 commit comments

Comments
 (0)