diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/view/com/util/post-embeds/VideoEmbed.tsx | 71 | ||||
-rw-r--r-- | src/view/com/util/post-embeds/VideoEmbed.web.tsx | 48 | ||||
-rw-r--r-- | src/view/com/util/post-embeds/VideoEmbedInner/VideoFallback.tsx | 61 |
3 files changed, 116 insertions, 64 deletions
diff --git a/src/view/com/util/post-embeds/VideoEmbed.tsx b/src/view/com/util/post-embeds/VideoEmbed.tsx index 887efac1a..4e2909f40 100644 --- a/src/view/com/util/post-embeds/VideoEmbed.tsx +++ b/src/view/com/util/post-embeds/VideoEmbed.tsx @@ -1,6 +1,6 @@ -import React from 'react' +import React, {useCallback, useState} from 'react' import {View} from 'react-native' -import {msg} from '@lingui/macro' +import {msg, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {VideoEmbedInnerNative} from 'view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerNative' @@ -8,13 +8,23 @@ import {atoms as a, useTheme} from '#/alf' import {Button, ButtonIcon} from '#/components/Button' import {Play_Filled_Corner2_Rounded as PlayIcon} from '#/components/icons/Play' import {VisibilityView} from '../../../../../modules/expo-bluesky-swiss-army' +import {ErrorBoundary} from '../ErrorBoundary' import {useActiveVideoView} from './ActiveVideoContext' +import * as VideoFallback from './VideoEmbedInner/VideoFallback' export function VideoEmbed({source}: {source: string}) { const t = useTheme() const {active, setActive} = useActiveVideoView({source}) const {_} = useLingui() + const [key, setKey] = useState(0) + const renderError = useCallback( + (error: unknown) => ( + <VideoError error={error} retry={() => setKey(key + 1)} /> + ), + [key], + ) + return ( <View style={[ @@ -25,27 +35,42 @@ export function VideoEmbed({source}: {source: string}) { t.atoms.bg_contrast_25, a.my_xs, ]}> - <VisibilityView - enabled={true} - onChangeStatus={isActive => { - if (isActive) { - setActive() - } - }}> - {active ? ( - <VideoEmbedInnerNative /> - ) : ( - <Button - style={[a.flex_1, t.atoms.bg_contrast_25]} - onPress={setActive} - label={_(msg`Play video`)} - variant="ghost" - color="secondary" - size="large"> - <ButtonIcon icon={PlayIcon} /> - </Button> - )} - </VisibilityView> + <ErrorBoundary renderError={renderError} key={key}> + <VisibilityView + enabled={true} + onChangeStatus={isActive => { + if (isActive) { + setActive() + } + }}> + {active ? ( + <VideoEmbedInnerNative /> + ) : ( + <Button + style={[a.flex_1, t.atoms.bg_contrast_25]} + onPress={setActive} + label={_(msg`Play video`)} + variant="ghost" + color="secondary" + size="large"> + <ButtonIcon icon={PlayIcon} /> + </Button> + )} + </VisibilityView> + </ErrorBoundary> </View> ) } + +function VideoError({retry}: {error: unknown; retry: () => void}) { + return ( + <VideoFallback.Container> + <VideoFallback.Text> + <Trans> + An error occurred while loading the video. Please try again later. + </Trans> + </VideoFallback.Text> + <VideoFallback.RetryButton onPress={retry} /> + </VideoFallback.Container> + ) +} diff --git a/src/view/com/util/post-embeds/VideoEmbed.web.tsx b/src/view/com/util/post-embeds/VideoEmbed.web.tsx index 70d887283..5803b836d 100644 --- a/src/view/com/util/post-embeds/VideoEmbed.web.tsx +++ b/src/view/com/util/post-embeds/VideoEmbed.web.tsx @@ -1,17 +1,15 @@ import React, {useCallback, useEffect, useRef, useState} from 'react' import {View} from 'react-native' -import {msg, Trans} from '@lingui/macro' -import {useLingui} from '@lingui/react' +import {Trans} from '@lingui/macro' import { HLSUnsupportedError, VideoEmbedInnerWeb, } from 'view/com/util/post-embeds/VideoEmbedInner/VideoEmbedInnerWeb' import {atoms as a, useTheme} from '#/alf' -import {Button, ButtonText} from '#/components/Button' -import {Text} from '#/components/Typography' import {ErrorBoundary} from '../ErrorBoundary' import {useActiveVideoView} from './ActiveVideoContext' +import * as VideoFallback from './VideoEmbedInner/VideoFallback' export function VideoEmbed({source}: {source: string}) { const t = useTheme() @@ -138,32 +136,11 @@ function ViewportObserver({ } function VideoError({error, retry}: {error: unknown; retry: () => void}) { - const t = useTheme() - const {_} = useLingui() - const isHLS = error instanceof HLSUnsupportedError return ( - <View - style={[ - a.flex_1, - t.atoms.bg_contrast_25, - a.justify_center, - a.align_center, - a.px_lg, - a.border, - t.atoms.border_contrast_low, - a.rounded_sm, - a.gap_lg, - ]}> - <Text - style={[ - a.text_center, - t.atoms.text_contrast_high, - a.text_md, - a.leading_snug, - {maxWidth: 300}, - ]}> + <VideoFallback.Container> + <VideoFallback.Text> {isHLS ? ( <Trans> Your browser does not support the video format. Please try a @@ -174,19 +151,8 @@ function VideoError({error, retry}: {error: unknown; retry: () => void}) { An error occurred while loading the video. Please try again later. </Trans> )} - </Text> - {!isHLS && ( - <Button - onPress={retry} - size="small" - color="secondary_inverted" - variant="solid" - label={_(msg`Retry`)}> - <ButtonText> - <Trans>Retry</Trans> - </ButtonText> - </Button> - )} - </View> + </VideoFallback.Text> + {!isHLS && <VideoFallback.RetryButton onPress={retry} />} + </VideoFallback.Container> ) } diff --git a/src/view/com/util/post-embeds/VideoEmbedInner/VideoFallback.tsx b/src/view/com/util/post-embeds/VideoEmbedInner/VideoFallback.tsx new file mode 100644 index 000000000..1b46163cc --- /dev/null +++ b/src/view/com/util/post-embeds/VideoEmbedInner/VideoFallback.tsx @@ -0,0 +1,61 @@ +import React from 'react' +import {View} from 'react-native' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' + +import {atoms as a, useTheme} from '#/alf' +import {Button, ButtonText} from '#/components/Button' +import {Text as TypoText} from '#/components/Typography' + +export function Container({children}: {children: React.ReactNode}) { + const t = useTheme() + return ( + <View + style={[ + a.flex_1, + t.atoms.bg_contrast_25, + a.justify_center, + a.align_center, + a.px_lg, + a.border, + t.atoms.border_contrast_low, + a.rounded_sm, + a.gap_lg, + ]}> + {children} + </View> + ) +} + +export function Text({children}: {children: React.ReactNode}) { + const t = useTheme() + return ( + <TypoText + style={[ + a.text_center, + t.atoms.text_contrast_high, + a.text_md, + a.leading_snug, + {maxWidth: 300}, + ]}> + {children} + </TypoText> + ) +} + +export function RetryButton({onPress}: {onPress: () => void}) { + const {_} = useLingui() + + return ( + <Button + onPress={onPress} + size="small" + color="secondary_inverted" + variant="solid" + label={_(msg`Retry`)}> + <ButtonText> + <Trans>Retry</Trans> + </ButtonText> + </Button> + ) +} |