feat: bump up fabric example react-native iOS (#3951)

* feat: 🔥 version bump react native for ios FabricExample
* feat:  copied newly created basic example TS files
This commit is contained in:
yungblud
2024-07-01 00:20:28 +09:00
committed by GitHub
parent 322d7e993d
commit e5a2ee3bd3
27 changed files with 2733 additions and 1473 deletions

View File

@@ -0,0 +1,75 @@
import React, {FunctionComponent} from 'react';
import {
StyleSheet,
Text,
TextStyle,
TouchableOpacity,
View,
} from 'react-native';
import {ResizeMode} from 'react-native-video';
export type MultiValueControlPropType = number | string | ResizeMode;
/*
* MultiValueControl displays a list clickable text view
*/
interface MultiValueControlType<T> {
// a list a string or number to be displayed
values: Array<T>;
// The selected value in values
selected?: T;
// callback to press onPress
onPress: (arg: MultiValueControlPropType) => void;
}
const MultiValueControl: FunctionComponent<
MultiValueControlType<MultiValueControlPropType>
> = ({values, selected, onPress}) => {
const selectedStyle: TextStyle = StyleSheet.flatten([
styles.option,
{fontWeight: 'bold'},
]);
const unselectedStyle: TextStyle = StyleSheet.flatten([
styles.option,
{fontWeight: 'normal'},
]);
return (
<View style={styles.container}>
{values.map((value: MultiValueControlPropType) => {
const _style = value === selected ? selectedStyle : unselectedStyle;
return (
<TouchableOpacity
key={value}
onPress={() => {
onPress?.(value);
}}>
<Text style={_style}>{value}</Text>
</TouchableOpacity>
);
})}
</View>
);
};
const styles = StyleSheet.create({
option: {
alignSelf: 'center',
fontSize: 11,
color: 'white',
paddingLeft: 2,
paddingRight: 2,
lineHeight: 12,
},
container: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
});
export default MultiValueControl;

View File

@@ -0,0 +1,73 @@
import React from 'react';
import {
StyleSheet,
Text,
TextStyle,
TouchableOpacity,
View,
} from 'react-native';
/*
* ToggleControl displays a 2 states clickable text
*/
interface ToggleControlType {
// boolean indicating if text is selected state
isSelected?: boolean;
// value of text when selected
selectedText?: string;
// value of text when NOT selected
unselectedText?: string;
// default text if no only one text field is needed
text?: string;
// callback called when pressing the component
onPress: () => void;
}
const ToggleControl = ({
isSelected,
selectedText,
unselectedText,
text,
onPress,
}: ToggleControlType) => {
const selectedStyle: TextStyle = StyleSheet.flatten([
styles.controlOption,
{fontWeight: 'bold'},
]);
const unselectedStyle: TextStyle = StyleSheet.flatten([
styles.controlOption,
{fontWeight: 'normal'},
]);
const style = isSelected ? selectedStyle : unselectedStyle;
const _text = text ? text : isSelected ? selectedText : unselectedText;
return (
<View style={styles.resizeModeControl}>
<TouchableOpacity onPress={onPress}>
<Text style={style}>{_text}</Text>
</TouchableOpacity>
</View>
);
};
const styles = StyleSheet.create({
controlOption: {
alignSelf: 'center',
fontSize: 11,
color: 'white',
paddingLeft: 2,
paddingRight: 2,
lineHeight: 12,
},
resizeModeControl: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
});
export default ToggleControl;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,53 @@
import {Picker} from '@react-native-picker/picker';
import {Text} from 'react-native';
import {AudioTrack, SelectedTrack} from 'react-native-video';
import styles from '../styles';
import React from 'react';
export interface AudioTrackSelectorType {
audioTracks: Array<AudioTrack>;
selectedAudioTrack: SelectedTrack | undefined;
onValueChange: (arg0: string) => void;
}
const AudioTrackSelector = ({
audioTracks,
selectedAudioTrack,
onValueChange,
}: AudioTrackSelectorType) => {
return (
<>
<Text style={styles.controlOption}>AudioTrack</Text>
<Picker
style={styles.picker}
itemStyle={styles.pickerItem}
selectedValue={selectedAudioTrack?.value}
onValueChange={itemValue => {
if (itemValue !== 'empty') {
console.log('on audio value change ' + itemValue);
onValueChange(`${itemValue}`);
}
}}>
{audioTracks?.length <= 0 ? (
<Picker.Item label={'empty'} value={'empty'} key={'empty'} />
) : (
<Picker.Item label={'none'} value={'none'} key={'none'} />
)}
{audioTracks.map(track => {
if (!track) {
return;
}
return (
<Picker.Item
label={`${track.language} - ${track.title} - ${track.selected}`}
value={`${track.index}`}
key={`${track.index}`}
/>
);
})}
</Picker>
</>
);
};
export default AudioTrackSelector;

View File

@@ -0,0 +1,154 @@
import React, {useCallback, useEffect, useState} from 'react';
import {PanResponder, View} from 'react-native';
import styles from '../styles';
interface SeekerProps {
currentTime: number;
duration: number;
isLoading: boolean;
isUISeeking: boolean;
videoSeek: (arg0: number) => void;
}
const Seeker = ({
currentTime,
duration,
isLoading,
isUISeeking,
videoSeek,
}: SeekerProps) => {
const [seeking, setSeeking] = useState(false);
const [seekerPosition, setSeekerPosition] = useState(0);
const [seekerWidth, setSeekerWidth] = useState(0);
/**
* Set the position of the seekbar's components
* (both fill and handle) according to the
* position supplied.
*
* @param {float} position position in px of seeker handle}
*/
const updateSeekerPosition = useCallback(
(position = 0) => {
if (position <= 0) {
position = 0;
} else if (position >= seekerWidth) {
position = seekerWidth;
}
setSeekerPosition(position);
},
[seekerWidth],
);
/**
* Return the time that the video should be at
* based on where the seeker handle is.
*
* @return {float} time in ms based on seekerPosition.
*/
const calculateTimeFromSeekerPosition = () => {
const percent = seekerPosition / seekerWidth;
return duration * percent;
};
/**
* Get our seekbar responder going
*/
const seekPanResponder = PanResponder.create({
// Ask to be the responder.
onStartShouldSetPanResponder: (_evt, _gestureState) => true,
onMoveShouldSetPanResponder: (_evt, _gestureState) => true,
/**
* When we start the pan tell the machine that we're
* seeking. This stops it from updating the seekbar
* position in the onProgress listener.
*/
onPanResponderGrant: (evt, _gestureState) => {
const position = evt.nativeEvent.locationX;
updateSeekerPosition(position);
setSeeking(true);
},
/**
* When panning, update the seekbar position, duh.
*/
onPanResponderMove: (evt, _gestureState) => {
const position = evt.nativeEvent.locationX;
updateSeekerPosition(position);
},
/**
* On release we update the time and seek to it in the video.
* If you seek to the end of the video we fire the
* onEnd callback
*/
onPanResponderRelease: (_evt, _gestureState) => {
const time = calculateTimeFromSeekerPosition();
if (time >= duration && !isLoading) {
// FIXME ...
// state.paused = true;
// this.onEnd();
} else {
videoSeek(time);
setSeeking(false);
}
},
});
useEffect(() => {
if (!isLoading && !seeking && !isUISeeking) {
const percent = currentTime / duration;
const position = seekerWidth * percent;
updateSeekerPosition(position);
}
}, [
currentTime,
duration,
isLoading,
seekerWidth,
seeking,
isUISeeking,
updateSeekerPosition,
]);
if (!seekPanResponder) {
return null;
}
const seekerStyle = [
styles.seekbarFill,
{
width: seekerPosition > 0 ? seekerPosition : 0,
backgroundColor: '#FFF',
},
];
const seekerPositionStyle = [
styles.seekbarHandle,
{
left: seekerPosition > 0 ? seekerPosition : 0,
},
];
const seekerPointerStyle = [styles.seekbarCircle, {backgroundColor: '#FFF'}];
return (
<View
style={styles.seekbarContainer}
{...seekPanResponder.panHandlers}
{...styles.generalControls}>
<View
style={styles.seekbarTrack}
onLayout={event => setSeekerWidth(event.nativeEvent.layout.width)}
pointerEvents={'none'}>
<View style={seekerStyle} pointerEvents={'none'} />
</View>
<View style={seekerPositionStyle} pointerEvents={'none'}>
<View style={seekerPointerStyle} pointerEvents={'none'} />
</View>
</View>
);
};
export default Seeker;

View File

@@ -0,0 +1,64 @@
import {Picker} from '@react-native-picker/picker';
import {Text} from 'react-native';
import {TextTrack, SelectedTrack} from 'react-native-video';
import styles from '../styles';
import React from 'react';
export interface TextTrackSelectorType {
textTracks: Array<TextTrack>;
selectedTextTrack: SelectedTrack | undefined;
onValueChange: (arg0: string) => void;
textTracksSelectionBy: string;
}
const TextTrackSelector = ({
textTracks,
selectedTextTrack,
onValueChange,
textTracksSelectionBy,
}: TextTrackSelectorType) => {
return (
<>
<Text style={styles.controlOption}>TextTrack</Text>
<Picker
style={styles.picker}
itemStyle={styles.pickerItem}
selectedValue={`${selectedTextTrack?.value}`}
onValueChange={itemValue => {
if (itemValue !== 'empty') {
onValueChange(itemValue);
}
}}>
{textTracks?.length <= 0 ? (
<Picker.Item label={'empty'} value={'empty'} key={'empty'} />
) : (
<Picker.Item label={'none'} value={'none'} key={'none'} />
)}
{textTracks.map(track => {
if (!track) {
return;
}
if (textTracksSelectionBy === 'index') {
return (
<Picker.Item
label={`${track.index}`}
value={track.index}
key={track.index}
/>
);
} else {
return (
<Picker.Item
label={track.language}
value={track.language}
key={track.language}
/>
);
}
})}
</Picker>
</>
);
};
export default TextTrackSelector;

View File

@@ -0,0 +1,64 @@
import {Picker} from '@react-native-picker/picker';
import {Text} from 'react-native';
import {
SelectedVideoTrack,
SelectedVideoTrackType,
VideoTrack,
} from 'react-native-video';
import styles from '../styles';
import React from 'react';
export interface VideoTrackSelectorType {
videoTracks: Array<VideoTrack>;
selectedVideoTrack: SelectedVideoTrack | undefined;
onValueChange: (arg0: string) => void;
}
const VideoTrackSelector = ({
videoTracks,
selectedVideoTrack,
onValueChange,
}: VideoTrackSelectorType) => {
return (
<>
<Text style={styles.controlOption}>VideoTrack</Text>
<Picker
style={styles.picker}
itemStyle={styles.pickerItem}
selectedValue={
selectedVideoTrack === undefined ||
selectedVideoTrack?.type === SelectedVideoTrackType.AUTO
? 'auto'
: `${selectedVideoTrack?.value}`
}
onValueChange={itemValue => {
if (itemValue !== 'empty') {
onValueChange(itemValue);
}
}}>
<Picker.Item label={'auto'} value={'auto'} key={'auto'} />
{videoTracks?.length <= 0 || videoTracks?.length <= 0 ? (
<Picker.Item label={'empty'} value={'empty'} key={'empty'} />
) : (
<Picker.Item label={'none'} value={'none'} key={'none'} />
)}
{videoTracks?.map(track => {
if (!track) {
return;
}
return (
<Picker.Item
label={`${track.width}x${track.height} ${Math.floor(
(track.bitrate || 0) / 8 / 1024,
)} Kbps`}
value={`${track.index}`}
key={track.index}
/>
);
})}
</Picker>
</>
);
};
export default VideoTrackSelector;

Binary file not shown.

View File

@@ -0,0 +1,167 @@
import {StyleSheet} from 'react-native';
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'black',
},
halfScreen: {
position: 'absolute',
top: 50,
left: 50,
bottom: 100,
right: 100,
},
fullScreen: {
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
},
bottomControls: {
backgroundColor: 'transparent',
borderRadius: 5,
position: 'absolute',
bottom: 20,
left: 20,
right: 20,
},
leftControls: {
backgroundColor: 'transparent',
borderRadius: 5,
position: 'absolute',
top: 20,
bottom: 20,
left: 20,
},
rightControls: {
backgroundColor: 'transparent',
borderRadius: 5,
position: 'absolute',
top: 20,
bottom: 20,
right: 20,
},
topControls: {
backgroundColor: 'transparent',
borderRadius: 4,
position: 'absolute',
top: 20,
left: 20,
right: 20,
flex: 1,
flexDirection: 'row',
overflow: 'hidden',
paddingBottom: 10,
},
generalControls: {
flex: 1,
flexDirection: 'row',
borderRadius: 4,
overflow: 'hidden',
paddingBottom: 10,
},
rateControl: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
},
volumeControl: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
},
resizeModeControl: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
leftRightControlOption: {
alignSelf: 'center',
fontSize: 11,
color: 'white',
padding: 10,
lineHeight: 12,
},
controlOption: {
alignSelf: 'center',
fontSize: 11,
color: 'white',
paddingLeft: 2,
paddingRight: 2,
lineHeight: 12,
},
pickerContainer: {
width: 100,
alignSelf: 'center',
color: 'white',
borderWidth: 1,
borderColor: 'red',
},
IndicatorStyle: {
flex: 1,
justifyContent: 'center',
},
seekbarContainer: {
flex: 1,
flexDirection: 'row',
borderRadius: 4,
height: 30,
},
seekbarTrack: {
backgroundColor: '#333',
height: 1,
position: 'relative',
top: 14,
width: '100%',
},
seekbarFill: {
backgroundColor: '#FFF',
height: 1,
width: '100%',
},
seekbarHandle: {
position: 'absolute',
marginLeft: -7,
height: 28,
width: 28,
},
seekbarCircle: {
borderRadius: 12,
position: 'relative',
top: 8,
left: 8,
height: 12,
width: 12,
},
picker: {
flex: 1,
color: 'white',
flexDirection: 'row',
justifyContent: 'center',
width: 100,
height: 40,
},
pickerItem: {
color: 'white',
width: 100,
height: 40,
},
emptyPickerItem: {
color: 'white',
marginTop: 20,
marginLeft: 20,
flex: 1,
width: 100,
height: 40,
},
topControlsContainer: {
paddingTop: 30,
},
});
export default styles;