Audio playing working

This commit is contained in:
Zhiyuan Zheng 2020-12-25 21:09:43 +01:00
parent 6eeb86921c
commit b5b9c0669c
No known key found for this signature in database
GPG Key ID: 078A93AB607D85E0
6 changed files with 194 additions and 37 deletions

View File

@ -11,6 +11,7 @@
"@expo/vector-icons": "^12.0.0",
"@react-native-community/masked-view": "0.1.10",
"@react-native-community/segmented-control": "2.2.1",
"@react-native-community/slider": "3.0.3",
"@react-navigation/bottom-tabs": "^5.11.2",
"@react-navigation/native": "^5.8.10",
"@reduxjs/toolkit": "^1.5.0",
@ -19,6 +20,7 @@
"expo": "^40.0.0",
"expo-auth-session": "~3.0.0",
"expo-av": "~8.7.0",
"expo-blur": "~8.2.2",
"expo-crypto": "~8.4.0",
"expo-gl": "~9.2.0",
"expo-image-picker": "~9.2.0",
@ -78,4 +80,4 @@
"typescript": "~4.0.0"
},
"private": true
}
}

View File

@ -82,7 +82,7 @@ declare namespace Mastodon {
| AttachmentVideo
| AttachmentGifv
| AttachmentAudio
// | AttachmentUnknown
| AttachmentUnknown
type AttachmentImage = {
// Base
@ -187,8 +187,9 @@ declare namespace Mastodon {
// Others
remote_url?: string
preview_remote_url?: string // undocumented
text_url?: string
meta?: {
meta: {
length: string
duration: number
audio_encode: string
@ -203,20 +204,20 @@ declare namespace Mastodon {
blurhash?: string
}
// type AttachmentUnknown = {
// // Base
// id: string
// type: 'unknown'
// url: string
// preview_url: string
type AttachmentUnknown = {
// Base
id: string
type: 'unknown'
url: string
preview_url: string
// // Others
// remote_url?: string
// text_url?: string
// meta?: any
// description?: string
// blurhash?: string
// }
// Others
remote_url?: string
text_url?: string
meta?: any
description?: string
blurhash?: string
}
type Card = {
// Base

View File

@ -1,4 +1,4 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import React, { useCallback, useMemo, useState } from 'react'
import { Pressable, StyleSheet, Text, View } from 'react-native'
import { StyleConstants } from '@utils/styles/constants'
import { useTheme } from '@utils/styles/ThemeManager'
@ -8,6 +8,8 @@ import AttachmentVideo from '@root/components/Timelines/Timeline/Shared/Attachme
import { IImageInfo } from 'react-native-image-zoom-viewer/built/image-viewer.type'
import { useNavigation } from '@react-navigation/native'
import AttachmentUnsupported from './Attachment/Unsupported'
import AttachmentAudio from './Attachment/Audio'
import { Feather } from '@expo/vector-icons'
export interface Props {
status: Pick<Mastodon.Status, 'media_attachments' | 'sensitive'>
@ -21,13 +23,6 @@ const TimelineAttachment: React.FC<Props> = ({ status, contentWidth }) => {
const onPressBlurView = useCallback(() => {
setSensitiveShown(false)
}, [])
useEffect(() => {
if (status.sensitive && sensitiveShown === false) {
setTimeout(() => {
setSensitiveShown(true)
}, 10000)
}
}, [sensitiveShown])
let imageUrls: (IImageInfo & {
preview_url: Mastodon.AttachmentImage['preview_url']
@ -83,7 +78,13 @@ const TimelineAttachment: React.FC<Props> = ({ status, contentWidth }) => {
/>
)
case 'audio':
return <Text key={index}></Text>
return (
<AttachmentAudio
key={index}
sensitiveShown={sensitiveShown}
audio={attachment}
/>
)
default:
return <AttachmentUnsupported key={index} attachment={attachment} />
}
@ -100,23 +101,43 @@ const TimelineAttachment: React.FC<Props> = ({ status, contentWidth }) => {
>
{attachments}
{status.sensitive && sensitiveShown && (
<Pressable style={styles.sensitiveBlur}>
{status.sensitive &&
(sensitiveShown ? (
<Pressable style={styles.sensitiveBlur}>
<Pressable
onPress={onPressBlurView}
style={[
styles.sensitiveBlurButton,
{ backgroundColor: theme.backgroundOverlay }
]}
>
<Text
style={[styles.sensitiveText, { color: theme.primaryOverlay }]}
>
</Text>
</Pressable>
</Pressable>
) : (
<Pressable
onPress={onPressBlurView}
style={[
styles.sensitiveBlurButton,
{ backgroundColor: theme.backgroundOverlay }
{
backgroundColor: theme.backgroundOverlay,
position: 'absolute',
top: StyleConstants.Spacing.S,
left: StyleConstants.Spacing.S
}
]}
onPress={() => setSensitiveShown(!sensitiveShown)}
>
<Text
style={[styles.sensitiveText, { color: theme.primaryOverlay }]}
>
</Text>
<Feather
name='eye-off'
size={StyleConstants.Font.Size.L}
color={theme.primaryOverlay}
/>
</Pressable>
</Pressable>
)}
))}
</View>
)
}

View File

@ -0,0 +1,123 @@
import React, { useCallback, useState } from 'react'
import { Image, Pressable, StyleSheet, View } from 'react-native'
import { Audio } from 'expo-av'
import { ButtonRow } from '@components/Button'
import layoutAnimation from '@root/utils/styles/layoutAnimation'
import { Surface } from 'gl-react-expo'
import { Blurhash } from 'gl-react-blurhash'
import Slider from '@react-native-community/slider'
import { StyleConstants } from '@root/utils/styles/constants'
import { useTheme } from '@root/utils/styles/ThemeManager'
export interface Props {
sensitiveShown: boolean
audio: Mastodon.AttachmentAudio
}
const AttachmentAudio: React.FC<Props> = ({ sensitiveShown, audio }) => {
layoutAnimation()
const { theme } = useTheme()
const [audioPlayer, setAudioPlayer] = useState<Audio.Sound>()
const [audioPlaying, setAudioPlaying] = useState(false)
const [audioPosition, setAudioPosition] = useState(0)
const playAudio = useCallback(async () => {
if (!audioPlayer) {
await Audio.setAudioModeAsync({ interruptionModeIOS: 1 })
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])
return (
<>
<Pressable style={styles.overlay}>
{sensitiveShown ? (
audio.blurhash && (
<Surface
style={{
width: '100%',
height: '100%'
}}
>
<Blurhash hash={audio.blurhash} />
</Surface>
)
) : (
<>
{(audio.preview_url || audio.preview_remote_url) && (
<Image
style={styles.background}
source={{ uri: audio.preview_url || audio.preview_remote_url }}
/>
)}
<ButtonRow
icon={audioPlaying ? 'pause' : 'play'}
size='L'
{...(audioPlaying
? { onPress: pauseAudio }
: { onPress: playAudio })}
/>
</>
)}
</Pressable>
<View
style={{
flex: 1,
alignSelf: 'flex-end',
backgroundColor: theme.backgroundOverlay,
paddingHorizontal: StyleConstants.Spacing.Global.PagePadding,
paddingVertical: StyleConstants.Spacing.XS,
borderRadius: 6,
opacity: sensitiveShown ? 0.35 : undefined
}}
>
<Slider
style={{
width: '100%'
}}
minimumValue={0}
maximumValue={audio.meta.original.duration * 1000}
value={audioPosition}
minimumTrackTintColor={theme.secondary}
maximumTrackTintColor={theme.disabled}
onSlidingStart={() => {
audioPlayer?.pauseAsync()
setAudioPlaying(false)
}}
onSlidingComplete={value => {
setAudioPosition(value)
}}
/>
</View>
</>
)
}
const styles = StyleSheet.create({
background: { position: 'absolute', width: '100%', height: '100%' },
overlay: {
position: 'absolute',
width: '100%',
height: '100%',
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}
})
export default AttachmentAudio

View File

@ -6,7 +6,7 @@ import { StyleConstants } from '@root/utils/styles/constants'
import openLink from '@root/utils/openLink'
export interface Props {
attachment: Mastodon.Attachment
attachment: Mastodon.AttachmentUnknown
}
const AttachmentUnsupported: React.FC<Props> = ({ attachment }) => {

View File

@ -1339,6 +1339,11 @@
resolved "https://registry.yarnpkg.com/@react-native-community/segmented-control/-/segmented-control-2.2.1.tgz#5ca418d78c5f6051353c9586918458713b88a83c"
integrity sha512-BzxFbI9Iqv+31yVqEvCTzJYmwb8jOMTf/UPuC4Hj176tmEPqBpuDaGH+rkAFg1miOco3/43RQxiAZO+mkY40Fg==
"@react-native-community/slider@3.0.3":
version "3.0.3"
resolved "https://registry.yarnpkg.com/@react-native-community/slider/-/slider-3.0.3.tgz#830167fd757ba70ac638747ba3169b2dbae60330"
integrity sha512-8IeHfDwJ9/CTUwFs6x90VlobV3BfuPgNLjTgC6dRZovfCWigaZwVNIFFJnHBakK3pW2xErAPwhdvNR4JeNoYbw==
"@react-navigation/bottom-tabs@^5.11.2":
version "5.11.2"
resolved "https://registry.yarnpkg.com/@react-navigation/bottom-tabs/-/bottom-tabs-5.11.2.tgz#5b541612fcecdea2a5024a4028da35e4a727bde6"
@ -2860,6 +2865,11 @@ expo-av@~8.7.0:
lodash "^4.17.15"
nullthrows "^1.1.0"
expo-blur@~8.2.2:
version "8.2.2"
resolved "https://registry.yarnpkg.com/expo-blur/-/expo-blur-8.2.2.tgz#a7643d893afb7aed5512b25d5df22ee6083832c1"
integrity sha512-Xiklw60RUPIchHKzfvLTIuccVDTIQEAIPv02yJY2xFDujQKjE0NU0/Z5Z+zsEI9QOi82jX9NbR8gQ+8Mm3hDhA==
expo-constants@^9.3.3, expo-constants@~9.3.3:
version "9.3.5"
resolved "https://registry.yarnpkg.com/expo-constants/-/expo-constants-9.3.5.tgz#78085763e8ed100a5f2df7c682fd99631aa03d5e"