feat: Tweak progress bar gestures

This commit is contained in:
Lei Nelissen
2022-05-05 22:54:37 +02:00
parent e135b23565
commit b0961d3263
7 changed files with 68 additions and 68 deletions

View File

@@ -41,7 +41,7 @@
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = JellyfinAudioPlayer/main.m; sourceTree = "<group>"; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = JellyfinAudioPlayer/main.m; sourceTree = "<group>"; };
2710519FCC41B05FDE6738DF /* Pods-JellyfinAudioPlayer.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JellyfinAudioPlayer.release.xcconfig"; path = "Target Support Files/Pods-JellyfinAudioPlayer/Pods-JellyfinAudioPlayer.release.xcconfig"; sourceTree = "<group>"; }; 2710519FCC41B05FDE6738DF /* Pods-JellyfinAudioPlayer.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JellyfinAudioPlayer.release.xcconfig"; path = "Target Support Files/Pods-JellyfinAudioPlayer/Pods-JellyfinAudioPlayer.release.xcconfig"; sourceTree = "<group>"; };
39572B38534BBDBB596C8C95 /* Pods-JellyfinAudioPlayer-JellyfinAudioPlayerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JellyfinAudioPlayer-JellyfinAudioPlayerTests.release.xcconfig"; path = "Target Support Files/Pods-JellyfinAudioPlayer-JellyfinAudioPlayerTests/Pods-JellyfinAudioPlayer-JellyfinAudioPlayerTests.release.xcconfig"; sourceTree = "<group>"; }; 39572B38534BBDBB596C8C95 /* Pods-JellyfinAudioPlayer-JellyfinAudioPlayerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JellyfinAudioPlayer-JellyfinAudioPlayerTests.release.xcconfig"; path = "Target Support Files/Pods-JellyfinAudioPlayer-JellyfinAudioPlayerTests/Pods-JellyfinAudioPlayer-JellyfinAudioPlayerTests.release.xcconfig"; sourceTree = "<group>"; };
4B4A0465FF364579B28CF5D7 /* Inter-VariableFont_slnt,wght.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = undefined; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-VariableFont_slnt,wght.ttf"; path = "../src/assets/fonts/Inter-VariableFont_slnt,wght.ttf"; sourceTree = "<group>"; }; 4B4A0465FF364579B28CF5D7 /* Inter-VariableFont_slnt,wght.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Inter-VariableFont_slnt,wght.ttf"; path = "../src/assets/fonts/Inter-VariableFont_slnt,wght.ttf"; sourceTree = "<group>"; };
4FA1B23B2550A94B007A035E /* JellyfinAudioPlayer-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JellyfinAudioPlayer-Bridging-Header.h"; sourceTree = "<group>"; }; 4FA1B23B2550A94B007A035E /* JellyfinAudioPlayer-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JellyfinAudioPlayer-Bridging-Header.h"; sourceTree = "<group>"; };
4FA1B23C2550A94C007A035E /* File.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = File.swift; sourceTree = "<group>"; }; 4FA1B23C2550A94C007A035E /* File.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = File.swift; sourceTree = "<group>"; };
590BEA7DE65819C5B5FDAD06 /* Pods-JellyfinAudioPlayer-tvOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JellyfinAudioPlayer-tvOSTests.release.xcconfig"; path = "Target Support Files/Pods-JellyfinAudioPlayer-tvOSTests/Pods-JellyfinAudioPlayer-tvOSTests.release.xcconfig"; sourceTree = "<group>"; }; 590BEA7DE65819C5B5FDAD06 /* Pods-JellyfinAudioPlayer-tvOSTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-JellyfinAudioPlayer-tvOSTests.release.xcconfig"; path = "Target Support Files/Pods-JellyfinAudioPlayer-tvOSTests/Pods-JellyfinAudioPlayer-tvOSTests.release.xcconfig"; sourceTree = "<group>"; };
@@ -176,7 +176,6 @@
4B4A0465FF364579B28CF5D7 /* Inter-VariableFont_slnt,wght.ttf */, 4B4A0465FF364579B28CF5D7 /* Inter-VariableFont_slnt,wght.ttf */,
); );
name = Resources; name = Resources;
path = "";
sourceTree = "<group>"; sourceTree = "<group>";
}; };
/* End PBXGroup section */ /* End PBXGroup section */
@@ -214,7 +213,6 @@
13B07F8E1A680F5B00A75B9A /* Resources */, 13B07F8E1A680F5B00A75B9A /* Resources */,
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
B9FB8FC65CEFF9AFAC71127E /* [CP] Copy Pods Resources */, B9FB8FC65CEFF9AFAC71127E /* [CP] Copy Pods Resources */,
1DC46C84C90B4D84A18AC142 /* Upload Debug Symbols to Sentry */,
2917566AA57EE087FC9FCCE9 /* [CP] Embed Pods Frameworks */, 2917566AA57EE087FC9FCCE9 /* [CP] Embed Pods Frameworks */,
); );
buildRules = ( buildRules = (
@@ -302,21 +300,7 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "export SENTRY_PROPERTIES=sentry.properties\nexport EXTRA_PACKAGER_ARGS=\"--sourcemap-output $DERIVED_FILE_DIR/main.jsbundle.map\"\nexport NODE_BINARY=$(which node)\n../node_modules/@sentry/cli/bin/sentry-cli react-native xcode ../node_modules/react-native/scripts/react-native-xcode.sh\n"; shellScript = "set -e\n\nexport NODE_BINARY=node\n../node_modules/react-native/scripts/react-native-xcode.sh\n";
};
1DC46C84C90B4D84A18AC142 /* Upload Debug Symbols to Sentry */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Upload Debug Symbols to Sentry";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "export SENTRY_PROPERTIES=sentry.properties\n../node_modules/@sentry/cli/bin/sentry-cli upload-dsym";
}; };
2917566AA57EE087FC9FCCE9 /* [CP] Embed Pods Frameworks */ = { 2917566AA57EE087FC9FCCE9 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;

14
package-lock.json generated
View File

@@ -45,7 +45,7 @@
"react-native-shadow-2": "^6.0.5", "react-native-shadow-2": "^6.0.5",
"react-native-svg": "^12.3.0", "react-native-svg": "^12.3.0",
"react-native-svg-transformer": "^1.0.0", "react-native-svg-transformer": "^1.0.0",
"react-native-track-player": "^2.2.0-rc3", "react-native-track-player": "^2.1.3",
"react-native-webview": "^11.18.2", "react-native-webview": "^11.18.2",
"react-redux": "^7.2.6", "react-redux": "^7.2.6",
"redux": "^4.2.0", "redux": "^4.2.0",
@@ -14509,9 +14509,9 @@
} }
}, },
"node_modules/react-native-track-player": { "node_modules/react-native-track-player": {
"version": "2.2.0-rc3", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/react-native-track-player/-/react-native-track-player-2.2.0-rc3.tgz", "resolved": "https://registry.npmjs.org/react-native-track-player/-/react-native-track-player-2.1.3.tgz",
"integrity": "sha512-Pvmum3MQ5PE8/yOIIPsk00zZk3EzdocUuVUwuBKSCmdKK/3O9YhnZRC3EuT59XCDm23pZZJZDSR44VeXN6Gamg==", "integrity": "sha512-JWKFRu+hr1ECN339RH+c+XDM7HfwvdvS4H1p4cJbhg/9b1CQGPJSrYXEhYkngN0msoxBxAjFyFIhjT2fWDCltA==",
"peerDependencies": { "peerDependencies": {
"react": ">=16.8.6", "react": ">=16.8.6",
"react-native": ">=0.60.0-rc.2", "react-native": ">=0.60.0-rc.2",
@@ -28865,9 +28865,9 @@
} }
}, },
"react-native-track-player": { "react-native-track-player": {
"version": "2.2.0-rc3", "version": "2.1.3",
"resolved": "https://registry.npmjs.org/react-native-track-player/-/react-native-track-player-2.2.0-rc3.tgz", "resolved": "https://registry.npmjs.org/react-native-track-player/-/react-native-track-player-2.1.3.tgz",
"integrity": "sha512-Pvmum3MQ5PE8/yOIIPsk00zZk3EzdocUuVUwuBKSCmdKK/3O9YhnZRC3EuT59XCDm23pZZJZDSR44VeXN6Gamg==", "integrity": "sha512-JWKFRu+hr1ECN339RH+c+XDM7HfwvdvS4H1p4cJbhg/9b1CQGPJSrYXEhYkngN0msoxBxAjFyFIhjT2fWDCltA==",
"requires": {} "requires": {}
}, },
"react-native-webview": { "react-native-webview": {

View File

@@ -49,7 +49,7 @@
"react-native-shadow-2": "^6.0.5", "react-native-shadow-2": "^6.0.5",
"react-native-svg": "^12.3.0", "react-native-svg": "^12.3.0",
"react-native-svg-transformer": "^1.0.0", "react-native-svg-transformer": "^1.0.0",
"react-native-track-player": "^2.2.0-rc3", "react-native-track-player": "^2.1.3",
"react-native-webview": "^11.18.2", "react-native-webview": "^11.18.2",
"react-redux": "^7.2.6", "react-redux": "^7.2.6",
"redux": "^4.2.0", "redux": "^4.2.0",

View File

@@ -12,7 +12,6 @@ import {
import { useColorScheme } from 'react-native'; import { useColorScheme } from 'react-native';
import { ColorSchemeContext, themes } from './Colors'; import { ColorSchemeContext, themes } from './Colors';
import DownloadManager from './DownloadManager'; import DownloadManager from './DownloadManager';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
// import ErrorReportingAlert from 'utility/ErrorReportingAlert'; // import ErrorReportingAlert from 'utility/ErrorReportingAlert';
export default function App(): JSX.Element { export default function App(): JSX.Element {
@@ -43,10 +42,8 @@ export default function App(): JSX.Element {
<PersistGate loading={null} persistor={persistedStore}> <PersistGate loading={null} persistor={persistedStore}>
<ColorSchemeContext.Provider value={theme}> <ColorSchemeContext.Provider value={theme}>
<NavigationContainer theme={colorScheme === 'dark' ? DarkTheme : DefaultTheme}> <NavigationContainer theme={colorScheme === 'dark' ? DarkTheme : DefaultTheme}>
<GestureHandlerRootView style={{ flex: 1 }}> <Routes />
<Routes /> <DownloadManager />
<DownloadManager />
</GestureHandlerRootView>
</NavigationContainer> </NavigationContainer>
</ColorSchemeContext.Provider> </ColorSchemeContext.Provider>
</PersistGate> </PersistGate>

View File

@@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import { createStackNavigator } from '@react-navigation/stack'; import { createStackNavigator } from '@react-navigation/stack';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { MusicStackParams } from './types'; import { MusicStackParams } from './types';
import Albums from './stacks/Albums'; import Albums from './stacks/Albums';
import Album from './stacks/Album'; import Album from './stacks/Album';
@@ -17,7 +18,7 @@ function MusicStack() {
const defaultStyles = useDefaultStyles(); const defaultStyles = useDefaultStyles();
return ( return (
<> <GestureHandlerRootView>
<Stack.Navigator initialRouteName="RecentAlbums" screenOptions={{ <Stack.Navigator initialRouteName="RecentAlbums" screenOptions={{
headerTintColor: THEME_COLOR, headerTintColor: THEME_COLOR,
headerTitleStyle: defaultStyles.stackHeader, headerTitleStyle: defaultStyles.stackHeader,
@@ -30,7 +31,7 @@ function MusicStack() {
<Stack.Screen name="Playlist" component={Playlist} options={{ headerTitle: t('playlist') }} /> <Stack.Screen name="Playlist" component={Playlist} options={{ headerTitle: t('playlist') }} />
</Stack.Navigator> </Stack.Navigator>
<NowPlaying /> <NowPlaying />
</> </GestureHandlerRootView>
); );
} }

View File

@@ -20,9 +20,11 @@ import Reanimated, {
import ReText from 'components/ReText'; import ReText from 'components/ReText';
const DRAG_HANDLE_SIZE = 20; const DRAG_HANDLE_SIZE = 20;
const PADDING_TOP = 14;
const Container = styled.View` const Container = styled.View`
margin-top: 28px; padding-top: ${PADDING_TOP}px;
margin-top: ${PADDING_TOP}px;
`; `;
const NumberBar = styled.View` const NumberBar = styled.View`
@@ -43,7 +45,7 @@ const DragHandle = styled(Reanimated.View)`
background-color: ${THEME_COLOR}; background-color: ${THEME_COLOR};
position: absolute; position: absolute;
left: -${DRAG_HANDLE_SIZE / 2}px; left: -${DRAG_HANDLE_SIZE / 2}px;
top: -${DRAG_HANDLE_SIZE / 2 - 2.5}px; top: ${PADDING_TOP - DRAG_HANDLE_SIZE / 2 + 2.5}px;
z-index: 14; z-index: 14;
`; `;
@@ -90,9 +92,13 @@ function ProgressBar() {
} }
}, [pos, dur]); }, [pos, dur]);
const gesture = Gesture.Pan() const pan = Gesture.Pan()
.onBegin(() => { .minDistance(1)
.activeOffsetX(1)
.activeOffsetY(1)
.onBegin((e) => {
isDragging.value = true; isDragging.value = true;
offset.value = Math.min(Math.max(DRAG_HANDLE_SIZE / 2, e.x), width.value - DRAG_HANDLE_SIZE / 2);
}).onUpdate((e) => { }).onUpdate((e) => {
offset.value = Math.min(Math.max(DRAG_HANDLE_SIZE / 2, e.x), width.value - DRAG_HANDLE_SIZE / 2); offset.value = Math.min(Math.max(DRAG_HANDLE_SIZE / 2, e.x), width.value - DRAG_HANDLE_SIZE / 2);
}).onFinalize(() => { }).onFinalize(() => {
@@ -100,11 +106,22 @@ function ProgressBar() {
isDragging.value = false; isDragging.value = false;
runOnJS(TrackPlayer.seekTo)(pos.value); runOnJS(TrackPlayer.seekTo)(pos.value);
}); });
const tap = Gesture.Tap()
.onBegin((e) => {
isDragging.value = true;
offset.value = Math.min(Math.max(DRAG_HANDLE_SIZE / 2, e.x), width.value - DRAG_HANDLE_SIZE / 2);
}).onFinalize(() => {
pos.value = (offset.value - DRAG_HANDLE_SIZE / 2) / (width.value - DRAG_HANDLE_SIZE) * dur.value;
isDragging.value = false;
runOnJS(TrackPlayer.seekTo)(pos.value);
});
const gesture = Gesture.Exclusive(tap, pan);
useEffect(() => { useEffect(() => {
pos.value = position; pos.value = position;
buf.value = buffered; buf.value = buffered;
dur.value = duration; dur.value = duration;
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [position, buffered, duration]); }, [position, buffered, duration]);
const dragHandleStyles = useAnimatedStyle(() => { const dragHandleStyles = useAnimatedStyle(() => {
@@ -112,7 +129,7 @@ function ProgressBar() {
transform: [ transform: [
{ translateX: offset.value }, { translateX: offset.value },
{ {
scale: withTiming(isDragging.value ? 1 : 0.05, { scale: withTiming(isDragging.value ? 1 : 0, {
duration: 100, duration: 100,
easing: Easing.out(Easing.ease), easing: Easing.out(Easing.ease),
}) })
@@ -158,29 +175,27 @@ function ProgressBar() {
}); });
return ( return (
<Container onLayout={(e) => { width.value = e.nativeEvent.layout.width; }}> <GestureDetector gesture={gesture}>
<GestureDetector gesture={gesture}> <Container onLayout={(e) => { width.value = e.nativeEvent.layout.width; }}>
<> <ProgressTrackContainer>
<ProgressTrackContainer> <ProgressTrack
<ProgressTrack opacity={0.15}
opacity={0.15} />
/> <ProgressTrack
<ProgressTrack style={bufferStyles}
style={bufferStyles} opacity={0.15}
opacity={0.15} />
/> <ProgressTrack
<ProgressTrack style={progressStyles}
style={progressStyles} />
/> </ProgressTrackContainer>
</ProgressTrackContainer> <DragHandle style={dragHandleStyles} />
<DragHandle style={dragHandleStyles} /> <NumberBar style={{ flex: 1 }}>
<NumberBar style={{ flex: 1 }}> <Number text={timePassed} style={timePassedStyles} />
<Number text={timePassed} style={timePassedStyles} /> <Number text={timeRemaining} style={timeRemainingStyles} />
<Number text={timeRemaining} style={timeRemainingStyles} /> </NumberBar>
</NumberBar> </Container>
</> </GestureDetector>
</GestureDetector>
</Container>
); );
} }

View File

@@ -7,6 +7,7 @@ import Queue from './components/Queue';
import useDefaultStyles from 'components/Colors'; import useDefaultStyles from 'components/Colors';
import ConnectionNotice from './components/ConnectionNotice'; import ConnectionNotice from './components/ConnectionNotice';
import { ScrollView } from 'react-native-gesture-handler'; import { ScrollView } from 'react-native-gesture-handler';
import { GestureHandlerRootView } from 'react-native-gesture-handler';
const styles = StyleSheet.create({ const styles = StyleSheet.create({
inner: { inner: {
@@ -18,12 +19,14 @@ export default function Player() {
const defaultStyles = useDefaultStyles(); const defaultStyles = useDefaultStyles();
return ( return (
<ScrollView contentContainerStyle={styles.inner} style={defaultStyles.view}> <GestureHandlerRootView>
<NowPlaying /> <ScrollView contentContainerStyle={styles.inner} style={defaultStyles.view}>
<ConnectionNotice /> <NowPlaying />
<ProgressBar /> <ConnectionNotice />
<MediaControls /> <ProgressBar />
<Queue /> <MediaControls />
</ScrollView> <Queue />
</ScrollView>
</GestureHandlerRootView>
); );
} }