created the slider with text
This commit is contained in:
parent
186ab338e4
commit
f344c9e97f
|
@ -0,0 +1,98 @@
|
|||
import React from 'react';
|
||||
import { LayoutChangeEvent, View, TextInput } from 'react-native';
|
||||
import { PanGestureHandler } from 'react-native-gesture-handler';
|
||||
import Animated, {
|
||||
useAnimatedGestureHandler,
|
||||
useAnimatedProps,
|
||||
useAnimatedStyle,
|
||||
useDerivedValue,
|
||||
useSharedValue
|
||||
} from 'react-native-reanimated';
|
||||
|
||||
import styles from './styles';
|
||||
import { useTheme } from '../../../../theme';
|
||||
|
||||
const AnimatedTextInput = Animated.createAnimatedComponent(TextInput);
|
||||
|
||||
const Slider = ({ currentTime = 0, duration = 120, thumbColor = '' }) => {
|
||||
console.log('🚀 ~ file: Slider.tsx:18 ~ Slider ~ currentTime:', currentTime);
|
||||
const { colors } = useTheme();
|
||||
|
||||
const maxWidth = useSharedValue(1);
|
||||
const x = useSharedValue(currentTime);
|
||||
const current = useSharedValue('00:00');
|
||||
const scale = useSharedValue(1);
|
||||
|
||||
const styleLine = useAnimatedStyle(() => ({
|
||||
width: x.value,
|
||||
zIndex: 2
|
||||
}));
|
||||
|
||||
const styleThumb = useAnimatedStyle(() => ({
|
||||
transform: [{ translateX: x.value }, { scale: scale.value }]
|
||||
}));
|
||||
|
||||
const onLayout = (event: LayoutChangeEvent) => {
|
||||
const { width } = event.nativeEvent.layout;
|
||||
maxWidth.value = width - 12;
|
||||
};
|
||||
|
||||
const gestureHandler = useAnimatedGestureHandler({
|
||||
onStart: (_, ctx: any) => {
|
||||
ctx.startX = x.value;
|
||||
},
|
||||
onActive: (event, ctx: any) => {
|
||||
const moveInX: number = ctx.startX + event.translationX;
|
||||
if (moveInX < 0) {
|
||||
x.value = 0;
|
||||
} else if (moveInX > maxWidth.value) {
|
||||
x.value = maxWidth.value;
|
||||
} else {
|
||||
x.value = moveInX;
|
||||
}
|
||||
|
||||
scale.value = 1.3;
|
||||
},
|
||||
onEnd: () => {
|
||||
scale.value = 1;
|
||||
// SEND A CALLBACK TO CHANGE THE PROGRESS OF THE AUDIO
|
||||
}
|
||||
});
|
||||
|
||||
useDerivedValue(() => {
|
||||
const cTime = (x.value * duration) / maxWidth.value;
|
||||
const minutes = Math.floor(cTime / 60);
|
||||
const remainingSeconds = Math.floor(cTime % 60);
|
||||
const formattedMinutes = String(minutes).padStart(2, '0');
|
||||
const formattedSeconds = String(remainingSeconds).padStart(2, '0');
|
||||
current.value = `${formattedMinutes}:${formattedSeconds}`;
|
||||
}, [x, maxWidth, duration]);
|
||||
|
||||
const getCurrentTime = useAnimatedProps(
|
||||
() =>
|
||||
({
|
||||
text: current.value
|
||||
} as any),
|
||||
[current]
|
||||
);
|
||||
|
||||
return (
|
||||
<View style={styles.sliderContainer}>
|
||||
<AnimatedTextInput
|
||||
defaultValue={'00:00'}
|
||||
editable={false}
|
||||
style={[styles.duration, { color: colors.bodyText }]}
|
||||
animatedProps={getCurrentTime}
|
||||
/>
|
||||
<View style={styles.slider} onLayout={onLayout}>
|
||||
<View style={[styles.line, { backgroundColor: colors.auxiliaryText }]} />
|
||||
<Animated.View style={[styles.line, styleLine, { backgroundColor: colors.tintColor }]} />
|
||||
<PanGestureHandler onGestureEvent={gestureHandler}>
|
||||
<Animated.View style={[styles.thumbSlider, { backgroundColor: thumbColor }, styleThumb]} />
|
||||
</PanGestureHandler>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default Slider;
|
|
@ -1,17 +1,13 @@
|
|||
import React, { useContext, useEffect, useRef, useState } from 'react';
|
||||
import { StyleProp, StyleSheet, Text, TextStyle, View, useWindowDimensions } from 'react-native';
|
||||
import { StyleProp, TextStyle, View } from 'react-native';
|
||||
import { Audio, AVPlaybackStatus, InterruptionModeAndroid, InterruptionModeIOS } from 'expo-av';
|
||||
import Slider from '@react-native-community/slider';
|
||||
import moment from 'moment';
|
||||
import { activateKeepAwakeAsync, deactivateKeepAwake } from 'expo-keep-awake';
|
||||
import { Sound } from 'expo-av/build/Audio/Sound';
|
||||
|
||||
import Touchable from '../../Touchable';
|
||||
import Markdown from '../../../markdown';
|
||||
import { CustomIcon } from '../../../CustomIcon';
|
||||
import sharedStyles from '../../../../views/Styles';
|
||||
import { themes } from '../../../../lib/constants';
|
||||
import { isAndroid, isIOS } from '../../../../lib/methods/helpers';
|
||||
import MessageContext from '../../Context';
|
||||
import ActivityIndicator from '../../../ActivityIndicator';
|
||||
import { TGetCustomEmoji } from '../../../../definitions/IEmoji';
|
||||
|
@ -21,6 +17,8 @@ import { downloadMediaFile, getMediaCache } from '../../../../lib/methods/handle
|
|||
import EventEmitter from '../../../../lib/methods/helpers/events';
|
||||
import { PAUSE_AUDIO } from '../../constants';
|
||||
import { fetchAutoDownloadEnabled } from '../../../../lib/methods/autoDownloadPreference';
|
||||
import styles from './styles';
|
||||
import Slider from './Slider';
|
||||
|
||||
interface IButton {
|
||||
loading: boolean;
|
||||
|
@ -48,36 +46,6 @@ const mode = {
|
|||
interruptionModeAndroid: InterruptionModeAndroid.DoNotMix
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
audioContainer: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
height: 56,
|
||||
borderWidth: 1,
|
||||
borderRadius: 4,
|
||||
marginBottom: 6
|
||||
},
|
||||
playPauseButton: {
|
||||
marginHorizontal: 10,
|
||||
alignItems: 'center',
|
||||
backgroundColor: 'transparent'
|
||||
},
|
||||
audioLoading: {
|
||||
marginHorizontal: 8
|
||||
},
|
||||
slider: {
|
||||
flex: 1
|
||||
},
|
||||
duration: {
|
||||
marginHorizontal: 12,
|
||||
fontSize: 14,
|
||||
...sharedStyles.textRegular
|
||||
}
|
||||
});
|
||||
|
||||
const formatTime = (seconds: number) => moment.utc(seconds * 1000).format('mm:ss');
|
||||
|
||||
const BUTTON_HIT_SLOP = { top: 12, right: 12, bottom: 12, left: 12 };
|
||||
|
||||
const Button = React.memo(({ loading, paused, onPress, disabled, cached }: IButton) => {
|
||||
|
@ -114,7 +82,6 @@ const MessageAudio = ({ file, getCustomEmoji, author, isReply, style }: IMessage
|
|||
const [cached, setCached] = useState(false);
|
||||
|
||||
const { baseUrl, user } = useContext(MessageContext);
|
||||
const { scale } = useWindowDimensions();
|
||||
const { theme } = useTheme();
|
||||
|
||||
const sound = useRef<Sound | null>(null);
|
||||
|
@ -150,6 +117,7 @@ const MessageAudio = ({ file, getCustomEmoji, author, isReply, style }: IMessage
|
|||
const onProgress = (data: AVPlaybackStatus) => {
|
||||
if (data.isLoaded) {
|
||||
const currentTime = data.positionMillis / 1000;
|
||||
console.log('🚀 ~ file: index.tsx:120 ~ onProgress ~ currentTime:', currentTime);
|
||||
if (currentTime <= duration) {
|
||||
setCurrentTime(currentTime);
|
||||
}
|
||||
|
@ -171,8 +139,6 @@ const MessageAudio = ({ file, getCustomEmoji, author, isReply, style }: IMessage
|
|||
}
|
||||
};
|
||||
|
||||
const getDuration = () => formatTime(currentTime || duration);
|
||||
|
||||
const togglePlayPause = () => {
|
||||
setPaused(!paused);
|
||||
playPause(!paused);
|
||||
|
@ -240,15 +206,6 @@ const MessageAudio = ({ file, getCustomEmoji, author, isReply, style }: IMessage
|
|||
handleDownload();
|
||||
};
|
||||
|
||||
const onValueChange = async (value: number) => {
|
||||
try {
|
||||
setCurrentTime(value);
|
||||
await sound.current?.setPositionAsync(value * 1000);
|
||||
} catch {
|
||||
// Do nothing
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
sound.current = new Audio.Sound();
|
||||
sound.current?.setOnPlaybackStatusUpdate(onPlaybackStatusUpdate);
|
||||
|
@ -296,9 +253,9 @@ const MessageAudio = ({ file, getCustomEmoji, author, isReply, style }: IMessage
|
|||
}
|
||||
|
||||
let thumbColor;
|
||||
if (isAndroid && isReply) {
|
||||
if (isReply) {
|
||||
thumbColor = themes[theme].tintDisabled;
|
||||
} else if (isAndroid) {
|
||||
} else {
|
||||
thumbColor = themes[theme].tintColor;
|
||||
}
|
||||
|
||||
|
@ -318,19 +275,8 @@ const MessageAudio = ({ file, getCustomEmoji, author, isReply, style }: IMessage
|
|||
]}
|
||||
>
|
||||
<Button disabled={isReply} loading={loading} paused={paused} cached={cached} onPress={onPress} />
|
||||
<Text style={[styles.duration, { color: themes[theme].auxiliaryText }]}>{getDuration()}</Text>
|
||||
<Slider
|
||||
disabled={isReply}
|
||||
style={styles.slider}
|
||||
value={currentTime}
|
||||
maximumValue={duration}
|
||||
minimumValue={0}
|
||||
thumbTintColor={thumbColor}
|
||||
minimumTrackTintColor={themes[theme].tintColor}
|
||||
maximumTrackTintColor={themes[theme].auxiliaryText}
|
||||
onValueChange={onValueChange}
|
||||
thumbImage={isIOS ? { uri: 'audio_thumb', scale } : undefined}
|
||||
/>
|
||||
<Slider currentTime={currentTime} duration={duration} thumbColor={thumbColor} />
|
||||
<View style={{ width: 36, height: 24, backgroundColor: '#999', borderRadius: 4, marginRight: 16 }} />
|
||||
</View>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
import { StyleSheet } from 'react-native';
|
||||
|
||||
import sharedStyles from '../../../../views/Styles';
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
audioContainer: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
height: 56,
|
||||
borderWidth: 1,
|
||||
borderRadius: 4,
|
||||
marginBottom: 6
|
||||
},
|
||||
playPauseButton: {
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#929',
|
||||
marginLeft: 16,
|
||||
height: 32,
|
||||
width: 32,
|
||||
borderRadius: 4,
|
||||
justifyContent: 'center'
|
||||
},
|
||||
audioLoading: {
|
||||
marginHorizontal: 8
|
||||
},
|
||||
sliderContainer: {
|
||||
flexDirection: 'row',
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
height: '100%'
|
||||
},
|
||||
slider: {
|
||||
marginRight: 12,
|
||||
height: '100%',
|
||||
justifyContent: 'center',
|
||||
flex: 1
|
||||
},
|
||||
line: {
|
||||
height: 4,
|
||||
borderRadius: 2,
|
||||
zIndex: 1,
|
||||
position: 'absolute',
|
||||
width: '100%'
|
||||
},
|
||||
duration: {
|
||||
width: 40,
|
||||
marginHorizontal: 12,
|
||||
fontSize: 14,
|
||||
...sharedStyles.textRegular
|
||||
},
|
||||
thumbSlider: {
|
||||
height: 12,
|
||||
width: 12,
|
||||
borderRadius: 6,
|
||||
zIndex: 3
|
||||
}
|
||||
});
|
||||
|
||||
export default styles;
|
Loading…
Reference in New Issue