import Button from '@components/Button' import GracefullyImage from '@components/GracefullyImage' import { Slider } from '@sharcoux/slider' import { StyleConstants } from '@utils/styles/constants' import { useTheme } from '@utils/styles/ThemeManager' import { Audio } from 'expo-av' import React, { useCallback, useEffect, useRef, useState } from 'react' import { AppState, AppStateStatus, StyleSheet, View } from 'react-native' import { Blurhash } from 'react-native-blurhash' import AttachmentAltText from './AltText' import attachmentAspectRatio from './aspectRatio' export interface Props { total: number index: number sensitiveShown: boolean audio: Mastodon.AttachmentAudio } const AttachmentAudio: React.FC = ({ total, index, sensitiveShown, audio }) => { const { colors } = useTheme() const [audioPlayer, setAudioPlayer] = useState() const [audioPlaying, setAudioPlaying] = useState(false) const [audioPosition, setAudioPosition] = useState(0) const playAudio = useCallback(async () => { if (!audioPlayer) { const { sound } = await Audio.Sound.createAsync( { uri: audio.url }, {}, // @ts-ignore props => setAudioPosition(props.positionMillis) ) setAudioPlayer(sound) } else { await audioPlayer.setPositionAsync(audioPosition) audioPlayer.playAsync() setAudioPlaying(true) } }, [audioPlayer, audioPosition]) const pauseAudio = useCallback(async () => { audioPlayer!.pauseAsync() setAudioPlaying(false) }, [audioPlayer]) const appState = useRef(AppState.currentState) useEffect(() => { const appState = AppState.addEventListener('change', _handleAppStateChange) return () => appState.remove() }, []) const _handleAppStateChange = async (nextAppState: AppStateStatus) => { if (appState.current.match(/active/) && nextAppState.match(/inactive/)) { await audioPlayer?.stopAsync() } appState.current = nextAppState } return ( {sensitiveShown ? ( audio.blurhash ? ( ) : null ) : ( <> {audio.preview_url ? ( ) : null}