Change modal to native stacks
This commit is contained in:
26
package-lock.json
generated
26
package-lock.json
generated
@@ -17,6 +17,7 @@
|
|||||||
"@react-native/normalize-color": "^2.0.0",
|
"@react-native/normalize-color": "^2.0.0",
|
||||||
"@react-navigation/bottom-tabs": "^6.3.1",
|
"@react-navigation/bottom-tabs": "^6.3.1",
|
||||||
"@react-navigation/native": "^6.0.10",
|
"@react-navigation/native": "^6.0.10",
|
||||||
|
"@react-navigation/native-stack": "^6.6.2",
|
||||||
"@react-navigation/stack": "^6.2.1",
|
"@react-navigation/stack": "^6.2.1",
|
||||||
"@reduxjs/toolkit": "^1.8.1",
|
"@reduxjs/toolkit": "^1.8.1",
|
||||||
"@sentry/react-native": "^3.4.2",
|
"@sentry/react-native": "^3.4.2",
|
||||||
@@ -3720,6 +3721,22 @@
|
|||||||
"react-native": "*"
|
"react-native": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@react-navigation/native-stack": {
|
||||||
|
"version": "6.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-6.6.2.tgz",
|
||||||
|
"integrity": "sha512-pFMuzhxbPml5MBvJVAzHWoaUkQaefAOKpuUnAs/AxNQuHQwwnxRmDit1PQLuIPo7g7DlfwFXagDHE1R0tbnS8Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"@react-navigation/elements": "^1.3.3",
|
||||||
|
"warn-once": "^0.1.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@react-navigation/native": "^6.0.0",
|
||||||
|
"react": "*",
|
||||||
|
"react-native": "*",
|
||||||
|
"react-native-safe-area-context": ">= 3.0.0",
|
||||||
|
"react-native-screens": ">= 3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@react-navigation/native/node_modules/escape-string-regexp": {
|
"node_modules/@react-navigation/native/node_modules/escape-string-regexp": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
||||||
@@ -19966,6 +19983,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@react-navigation/native-stack": {
|
||||||
|
"version": "6.6.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-navigation/native-stack/-/native-stack-6.6.2.tgz",
|
||||||
|
"integrity": "sha512-pFMuzhxbPml5MBvJVAzHWoaUkQaefAOKpuUnAs/AxNQuHQwwnxRmDit1PQLuIPo7g7DlfwFXagDHE1R0tbnS8Q==",
|
||||||
|
"requires": {
|
||||||
|
"@react-navigation/elements": "^1.3.3",
|
||||||
|
"warn-once": "^0.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@react-navigation/routers": {
|
"@react-navigation/routers": {
|
||||||
"version": "6.1.0",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-6.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@react-navigation/routers/-/routers-6.1.0.tgz",
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
"@react-native/normalize-color": "^2.0.0",
|
"@react-native/normalize-color": "^2.0.0",
|
||||||
"@react-navigation/bottom-tabs": "^6.3.1",
|
"@react-navigation/bottom-tabs": "^6.3.1",
|
||||||
"@react-navigation/native": "^6.0.10",
|
"@react-navigation/native": "^6.0.10",
|
||||||
|
"@react-navigation/native-stack": "^6.6.2",
|
||||||
"@react-navigation/stack": "^6.2.1",
|
"@react-navigation/stack": "^6.2.1",
|
||||||
"@reduxjs/toolkit": "^1.8.1",
|
"@reduxjs/toolkit": "^1.8.1",
|
||||||
"@sentry/react-native": "^3.4.2",
|
"@sentry/react-native": "^3.4.2",
|
||||||
|
|||||||
26
src/components/DismissableScrollView.tsx
Normal file
26
src/components/DismissableScrollView.tsx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import {GestureHandlerRefContext} from '@react-navigation/stack';
|
||||||
|
import React, {PropsWithChildren, useCallback, useState} from 'react';
|
||||||
|
import {ScrollViewProps} from 'react-native';
|
||||||
|
import {ScrollView} from 'react-native-gesture-handler';
|
||||||
|
|
||||||
|
export const DismissableScrollView = (
|
||||||
|
props: PropsWithChildren<ScrollViewProps>,
|
||||||
|
) => {
|
||||||
|
const [scrolledTop, setScrolledTop] = useState(true);
|
||||||
|
const onScroll = useCallback(({nativeEvent}) => {
|
||||||
|
console.log(nativeEvent.contentOffset);
|
||||||
|
setScrolledTop(nativeEvent.contentOffset.y <= 0);
|
||||||
|
}, []);
|
||||||
|
return (
|
||||||
|
<GestureHandlerRefContext.Consumer>
|
||||||
|
{(ref) => (
|
||||||
|
<ScrollView
|
||||||
|
waitFor={scrolledTop ? ref : undefined}
|
||||||
|
onScroll={onScroll}
|
||||||
|
scrollEventThrottle={16}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</GestureHandlerRefContext.Consumer>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useRef } from 'react';
|
import React, { useCallback, useEffect, useRef } from 'react';
|
||||||
import { ActivityIndicator, Animated, Dimensions, Easing, Pressable, View } from 'react-native';
|
import { ActivityIndicator, Animated, Dimensions, Easing, Pressable, View } from 'react-native';
|
||||||
import FastImage from 'react-native-fast-image';
|
import FastImage from 'react-native-fast-image';
|
||||||
import styled, { css } from 'styled-components/native';
|
import styled, { css } from 'styled-components/native';
|
||||||
@@ -12,6 +12,7 @@ import { Shadow } from 'react-native-shadow-2';
|
|||||||
import usePrevious from 'utility/usePrevious';
|
import usePrevious from 'utility/usePrevious';
|
||||||
import Text from 'components/Text';
|
import Text from 'components/Text';
|
||||||
import { ColoredBlurView } from 'components/Colors';
|
import { ColoredBlurView } from 'components/Colors';
|
||||||
|
import { useNavigation } from '@react-navigation/native';
|
||||||
|
|
||||||
const NOW_PLAYING_POPOVER_MARGIN = 6;
|
const NOW_PLAYING_POPOVER_MARGIN = 6;
|
||||||
const NOW_PLAYING_POPOVER_WIDTH = Dimensions.get('screen').width - 2 * NOW_PLAYING_POPOVER_MARGIN;
|
const NOW_PLAYING_POPOVER_WIDTH = Dimensions.get('screen').width - 2 * NOW_PLAYING_POPOVER_MARGIN;
|
||||||
@@ -115,10 +116,15 @@ function NowPlaying() {
|
|||||||
const { index, track } = useCurrentTrack();
|
const { index, track } = useCurrentTrack();
|
||||||
const { buffered, duration, position } = useProgress();
|
const { buffered, duration, position } = useProgress();
|
||||||
const previousIndex = usePrevious(index);
|
const previousIndex = usePrevious(index);
|
||||||
|
const navigation = useNavigation();
|
||||||
|
|
||||||
const bufferAnimation = useRef(new Animated.Value(0));
|
const bufferAnimation = useRef(new Animated.Value(0));
|
||||||
const progressAnimation = useRef(new Animated.Value(0));
|
const progressAnimation = useRef(new Animated.Value(0));
|
||||||
|
|
||||||
|
const openNowPlayingModal = useCallback(() => {
|
||||||
|
navigation.navigate('Player');
|
||||||
|
}, [navigation]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const hasChangedTrack = previousIndex !== index || duration === 0;
|
const hasChangedTrack = previousIndex !== index || duration === 0;
|
||||||
|
|
||||||
@@ -147,11 +153,13 @@ function NowPlaying() {
|
|||||||
</Shadow>
|
</Shadow>
|
||||||
</ShadowOverlay>
|
</ShadowOverlay>
|
||||||
<ColoredBlurView style={{ borderRadius: 8 }}>
|
<ColoredBlurView style={{ borderRadius: 8 }}>
|
||||||
<InnerContainer>
|
<InnerContainer onPress={openNowPlayingModal}>
|
||||||
<Cover source={{ uri: (track.artwork || '') as string }} />
|
<Cover source={{ uri: (track.artwork || '') as string }} />
|
||||||
<TrackNameContainer>
|
<TrackNameContainer>
|
||||||
<Text>{track.title}</Text>
|
<Text numberOfLines={1}>{track.title}</Text>
|
||||||
<Text style={{ opacity: 0.5 }}>{track.artist}{track.album ? ` — ${track.album}` : ''}</Text>
|
<Text style={{ opacity: 0.5 }} numberOfLines={1}>
|
||||||
|
{track.artist}{track.album ? ` — ${track.album}` : ''}
|
||||||
|
</Text>
|
||||||
</TrackNameContainer>
|
</TrackNameContainer>
|
||||||
<ActionButton>
|
<ActionButton>
|
||||||
<SelectActionButton />
|
<SelectActionButton />
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { createBottomTabNavigator, BottomTabNavigationProp } from '@react-navigation/bottom-tabs';
|
import { createBottomTabNavigator, BottomTabNavigationProp } from '@react-navigation/bottom-tabs';
|
||||||
import { createStackNavigator, StackNavigationProp } from '@react-navigation/stack';
|
import { StackNavigationProp } from '@react-navigation/stack';
|
||||||
|
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
||||||
import { CompositeNavigationProp } from '@react-navigation/native';
|
import { CompositeNavigationProp } from '@react-navigation/native';
|
||||||
import { THEME_COLOR } from 'CONSTANTS';
|
import { THEME_COLOR } from 'CONSTANTS';
|
||||||
|
|
||||||
@@ -21,12 +22,12 @@ import { ModalStackParams } from './types';
|
|||||||
import { t } from '@localisation';
|
import { t } from '@localisation';
|
||||||
import ErrorReportingAlert from 'utility/ErrorReportingAlert';
|
import ErrorReportingAlert from 'utility/ErrorReportingAlert';
|
||||||
import ErrorReportingPopup from './modals/ErrorReportingPopup';
|
import ErrorReportingPopup from './modals/ErrorReportingPopup';
|
||||||
|
import Player from './modals/Player';
|
||||||
|
|
||||||
const Stack = createStackNavigator<ModalStackParams>();
|
const Stack = createNativeStackNavigator<ModalStackParams>();
|
||||||
const Tab = createBottomTabNavigator();
|
const Tab = createBottomTabNavigator();
|
||||||
|
|
||||||
type Screens = {
|
type Screens = {
|
||||||
NowPlaying: undefined;
|
|
||||||
Music: undefined;
|
Music: undefined;
|
||||||
Settings: undefined;
|
Settings: undefined;
|
||||||
}
|
}
|
||||||
@@ -78,20 +79,17 @@ type Routes = {
|
|||||||
SetJellyfinServer: undefined;
|
SetJellyfinServer: undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default function Routes() {
|
export default function Routes() {
|
||||||
return (
|
return (
|
||||||
<Stack.Navigator screenOptions={{
|
<Stack.Navigator screenOptions={{
|
||||||
cardStyle: {
|
|
||||||
backgroundColor: 'transparent'
|
|
||||||
},
|
|
||||||
presentation: 'modal',
|
presentation: 'modal',
|
||||||
headerShown: false,
|
headerShown: false,
|
||||||
}}>
|
}} id="MAIN">
|
||||||
<Stack.Screen name="Screens" component={Screens} />
|
<Stack.Screen name="Screens" component={Screens} />
|
||||||
<Stack.Screen name="SetJellyfinServer" component={SetJellyfinServer} />
|
<Stack.Screen name="SetJellyfinServer" component={SetJellyfinServer} />
|
||||||
<Stack.Screen name="TrackPopupMenu" component={TrackPopupMenu} />
|
<Stack.Screen name="TrackPopupMenu" component={TrackPopupMenu} options={{ presentation: 'formSheet' }} />
|
||||||
<Stack.Screen name="ErrorReporting" component={ErrorReportingPopup} />
|
<Stack.Screen name="ErrorReporting" component={ErrorReportingPopup} />
|
||||||
|
<Stack.Screen name="Player" component={Player} />
|
||||||
</Stack.Navigator>
|
</Stack.Navigator>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { StyleSheet, ScrollView } from 'react-native';
|
import { StyleSheet } from 'react-native';
|
||||||
import MediaControls from './components/MediaControls';
|
import MediaControls from './components/MediaControls';
|
||||||
import ProgressBar from './components/ProgressBar';
|
import ProgressBar from './components/ProgressBar';
|
||||||
import NowPlaying from './components/NowPlaying';
|
import NowPlaying from './components/NowPlaying';
|
||||||
import Queue from './components/Queue';
|
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 { DismissableScrollView } from 'components/DismissableScrollView';
|
||||||
|
import { ScrollView } from 'react-native-gesture-handler';
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
inner: {
|
inner: {
|
||||||
@@ -16,6 +16,7 @@ import { useDispatch } from 'react-redux';
|
|||||||
import { queueTrackForDownload, removeDownloadedTrack } from 'store/downloads/actions';
|
import { queueTrackForDownload, removeDownloadedTrack } from 'store/downloads/actions';
|
||||||
import usePlayTracks from 'utility/usePlayTracks';
|
import usePlayTracks from 'utility/usePlayTracks';
|
||||||
import { selectIsDownloaded } from 'store/downloads/selectors';
|
import { selectIsDownloaded } from 'store/downloads/selectors';
|
||||||
|
import { View } from 'react-native';
|
||||||
|
|
||||||
type Route = RouteProp<ModalStackParams, 'TrackPopupMenu'>;
|
type Route = RouteProp<ModalStackParams, 'TrackPopupMenu'>;
|
||||||
|
|
||||||
@@ -68,7 +69,7 @@ function TrackPopupMenu() {
|
|||||||
}, [trackId, dispatch, closeModal]);
|
}, [trackId, dispatch, closeModal]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal fullSize={false}>
|
<View>
|
||||||
<Container>
|
<Container>
|
||||||
<SubHeader style={{ textAlign: 'center' }}>{track?.Name}</SubHeader>
|
<SubHeader style={{ textAlign: 'center' }}>{track?.Name}</SubHeader>
|
||||||
<Text style={{ marginBottom: 18, textAlign: 'center' }}>{track?.Album} - {track?.AlbumArtist}</Text>
|
<Text style={{ marginBottom: 18, textAlign: 'center' }}>{track?.Album} - {track?.AlbumArtist}</Text>
|
||||||
@@ -82,7 +83,7 @@ function TrackPopupMenu() {
|
|||||||
)}
|
)}
|
||||||
</WrappableButtonRow>
|
</WrappableButtonRow>
|
||||||
</Container>
|
</Container>
|
||||||
</Modal>
|
</View>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user