handle notification click link

also correctly handle back on now playing from app open
standardize route names
This commit is contained in:
austinried 2021-07-27 20:38:28 +09:00
parent 25cea64f1d
commit ff0464a156
14 changed files with 120 additions and 87 deletions

View File

@ -1,26 +1,17 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.subsonify">
<uses-permission android:name="android.permission.INTERNET" />
<application
android:name=".MainApplication"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:theme="@style/AppTheme"
android:usesCleartextTraffic="true">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
android:launchMode="singleTask"
android:windowSoftInputMode="adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.subsonify">
<uses-permission android:name="android.permission.INTERNET"/>
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="false" android:theme="@style/AppTheme" android:usesCleartextTraffic="true">
<activity android:name=".MainActivity" android:label="@string/app_name" android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode" android:launchMode="singleTask" android:windowSoftInputMode="adjustPan">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="trackplayer"/>
</intent-filter>
</activity>
</application>
</manifest>

View File

@ -1,5 +1,4 @@
import React from 'react'
import { DarkTheme, NavigationContainer } from '@react-navigation/native'
import SplashPage from '@app/screens/SplashPage'
import RootNavigator from '@app/navigation/RootNavigator'
import { Provider } from 'jotai'
@ -7,18 +6,13 @@ import { StatusBar, View } from 'react-native'
import colors from '@app/styles/colors'
import TrackPlayerState from '@app/components/TrackPlayerState'
const theme = { ...DarkTheme }
theme.colors.background = colors.gradient.high
const App = () => (
<Provider>
<StatusBar animated={true} backgroundColor={'rgba(0, 0, 0, 0.4)'} barStyle={'light-content'} translucent={true} />
<TrackPlayerState />
<View style={{ flex: 1, backgroundColor: colors.gradient.high }}>
<SplashPage>
<NavigationContainer theme={theme}>
<RootNavigator />
</NavigationContainer>
<RootNavigator />
</SplashPage>
</View>
</Provider>

View File

@ -57,13 +57,13 @@ const ListItem: React.FC<{
if (!onPress) {
switch (item.itemType) {
case 'album':
onPress = () => navigation.navigate('AlbumView', { id: item.id, title: item.name })
onPress = () => navigation.navigate('album', { id: item.id, title: item.name })
break
case 'artist':
onPress = () => navigation.navigate('ArtistView', { id: item.id, title: item.name })
onPress = () => navigation.navigate('artist', { id: item.id, title: item.name })
break
case 'playlist':
onPress = () => navigation.navigate('PlaylistView', { id: item.id, title: item.name })
onPress = () => navigation.navigate('playlist', { id: item.id, title: item.name })
break
}
}

View File

@ -64,7 +64,7 @@ const NowPlayingBar = () => {
return (
<Pressable
onPress={() => navigation.navigate('NowPlaying')}
onPress={() => navigation.navigate('now-playing')}
style={{ ...styles.container, display: track ? 'flex' : 'none' }}>
<ProgressBar />
<View style={styles.subContainer}>

View File

@ -15,14 +15,14 @@ import { StyleSheet } from 'react-native'
import { createNativeStackNavigator, NativeStackNavigationProp } from 'react-native-screens/native-stack'
type TabStackParamList = {
TabMain: { toTop?: boolean }
AlbumView: { id: string; title: string }
ArtistView: { id: string; title: string }
PlaylistView: { id: string; title: string }
main: { toTop?: boolean }
album: { id: string; title: string }
artist: { id: string; title: string }
playlist: { id: string; title: string }
}
type AlbumScreenNavigationProp = NativeStackNavigationProp<TabStackParamList, 'AlbumView'>
type AlbumScreenRouteProp = RouteProp<TabStackParamList, 'AlbumView'>
type AlbumScreenNavigationProp = NativeStackNavigationProp<TabStackParamList, 'album'>
type AlbumScreenRouteProp = RouteProp<TabStackParamList, 'album'>
type AlbumScreenProps = {
route: AlbumScreenRouteProp
navigation: AlbumScreenNavigationProp
@ -32,8 +32,8 @@ const AlbumScreen: React.FC<AlbumScreenProps> = ({ route }) => (
<AlbumView id={route.params.id} title={route.params.title} />
)
type ArtistScreenNavigationProp = NativeStackNavigationProp<TabStackParamList, 'ArtistView'>
type ArtistScreenRouteProp = RouteProp<TabStackParamList, 'ArtistView'>
type ArtistScreenNavigationProp = NativeStackNavigationProp<TabStackParamList, 'artist'>
type ArtistScreenRouteProp = RouteProp<TabStackParamList, 'artist'>
type ArtistScreenProps = {
route: ArtistScreenRouteProp
navigation: ArtistScreenNavigationProp
@ -43,8 +43,8 @@ const ArtistScreen: React.FC<ArtistScreenProps> = ({ route }) => (
<ArtistView id={route.params.id} title={route.params.title} />
)
type PlaylistScreenNavigationProp = NativeStackNavigationProp<TabStackParamList, 'PlaylistView'>
type PlaylistScreenRouteProp = RouteProp<TabStackParamList, 'PlaylistView'>
type PlaylistScreenNavigationProp = NativeStackNavigationProp<TabStackParamList, 'playlist'>
type PlaylistScreenRouteProp = RouteProp<TabStackParamList, 'playlist'>
type PlaylistScreenProps = {
route: PlaylistScreenRouteProp
navigation: PlaylistScreenNavigationProp
@ -86,11 +86,11 @@ function createTabStackNavigator(Component: React.ComponentType<any>) {
})
return (
<Stack.Navigator>
<Stack.Screen name="TabMain" component={Component} options={{ headerShown: false }} />
<Stack.Screen name="AlbumView" component={AlbumScreen} options={itemScreenOptions} />
<Stack.Screen name="ArtistView" component={ArtistScreen} options={itemScreenOptions} />
<Stack.Screen name="PlaylistView" component={PlaylistScreen} options={itemScreenOptions} />
<Stack.Navigator initialRouteName="main">
<Stack.Screen name="main" component={Component} options={{ headerShown: false }} />
<Stack.Screen name="album" component={AlbumScreen} options={itemScreenOptions} />
<Stack.Screen name="artist" component={ArtistScreen} options={itemScreenOptions} />
<Stack.Screen name="playlist" component={PlaylistScreen} options={itemScreenOptions} />
</Stack.Navigator>
)
}
@ -106,11 +106,11 @@ const Tab = createBottomTabNavigator()
const BottomTabNavigator = () => {
return (
<Tab.Navigator tabBar={BottomTabBar}>
<Tab.Screen name="Home" component={HomeTab} options={{ icon: 'home' } as any} />
<Tab.Screen name="Library" component={LibraryTab} options={{ icon: 'library' } as any} />
<Tab.Screen name="Search" component={SearchTab} options={{ icon: 'search' } as any} />
<Tab.Screen name="Settings" component={SettingsView} options={{ icon: 'settings' } as any} />
<Tab.Navigator tabBar={BottomTabBar} initialRouteName="home">
<Tab.Screen name="home" component={HomeTab} options={{ icon: 'home' } as any} />
<Tab.Screen name="library" component={LibraryTab} options={{ icon: 'library' } as any} />
<Tab.Screen name="search" component={SearchTab} options={{ icon: 'search' } as any} />
<Tab.Screen name="settings" component={SettingsView} options={{ icon: 'settings' } as any} />
</Tab.Navigator>
)
}

View File

@ -16,10 +16,11 @@ const LibraryTopTabNavigator = () => (
style: styles.tabBar,
labelStyle: styles.tablabelStyle,
indicatorStyle: styles.tabindicatorStyle,
}}>
<Tab.Screen name="Albums" component={AlbumsTab} />
<Tab.Screen name="Artists" component={ArtistsTab} />
<Tab.Screen name="Playlists" component={PlaylistsTab} />
}}
initialRouteName="albums">
<Tab.Screen name="albums" component={AlbumsTab} />
<Tab.Screen name="artists" component={ArtistsTab} />
<Tab.Screen name="playlists" component={PlaylistsTab} />
</Tab.Navigator>
)

View File

@ -1,18 +1,40 @@
import BottomTabNavigator from '@app/navigation/BottomTabNavigator'
import NowPlayingLayout from '@app/screens/NowPlayingLayout'
import colors from '@app/styles/colors'
import { DarkTheme, NavigationContainer } from '@react-navigation/native'
import React from 'react'
import { createNativeStackNavigator } from 'react-native-screens/native-stack'
import NowPlayingLayout from '@app/screens/NowPlayingLayout'
import BottomTabNavigator from '@app/navigation/BottomTabNavigator'
const RootStack = createNativeStackNavigator()
const theme = { ...DarkTheme }
theme.colors.background = colors.gradient.high
const RootNavigator = () => (
<RootStack.Navigator
screenOptions={{
headerShown: false,
<NavigationContainer
theme={theme}
linking={{
prefixes: ['trackplayer'],
config: {
screens: {
main: {
path: ':/main',
},
'now-playing': {
path: ':/notification.click',
},
},
},
}}>
<RootStack.Screen name="Main" component={BottomTabNavigator} />
<RootStack.Screen name="NowPlaying" component={NowPlayingLayout} />
</RootStack.Navigator>
<RootStack.Navigator
screenOptions={{
headerShown: false,
}}
initialRouteName="main">
<RootStack.Screen name="main" component={BottomTabNavigator} />
<RootStack.Screen name="now-playing" component={NowPlayingLayout} />
</RootStack.Navigator>
</NavigationContainer>
)
export default RootNavigator

View File

@ -24,7 +24,7 @@ const AlbumItem = React.memo<{
return (
<PressableOpacity
onPress={() => navigation.navigate('AlbumView', { id: album.id, title: album.name })}
onPress={() => navigation.navigate('album', { id: album.id, title: album.name })}
style={[styles.albumItem, { width }]}>
<CoverArt coverArt={album.coverArt} style={{ height, width }} />
<Text style={styles.albumTitle}>{album.name}</Text>

View File

@ -28,7 +28,7 @@ const AlbumItem = React.memo<{
return (
<PressableOpacity
onPress={() => navigation.navigate('AlbumView', { id: album.id, title: album.name })}
onPress={() => navigation.navigate('album', { id: album.id, title: album.name })}
key={album.id}
style={styles.item}>
<CoverArt coverArt={album.coverArt} style={{ height: styles.item.width, width: styles.item.width }} />

View File

@ -24,7 +24,7 @@ const AlbumItem = React.memo<{
return (
<PressableOpacity
style={[styles.item, { maxWidth: size, height }]}
onPress={() => navigation.navigate('AlbumView', { id, title: name })}>
onPress={() => navigation.navigate('album', { id, title: name })}>
<CoverArt coverArt={coverArt} style={{ height: size, width: size }} />
<View style={styles.itemDetails}>
<Text style={styles.title} numberOfLines={1}>

View File

@ -1,7 +1,6 @@
import { useNavigation } from '@react-navigation/native'
import { useAtomValue } from 'jotai/utils'
import React, { useEffect } from 'react'
import { StatusBar, StyleSheet, Text, View } from 'react-native'
import React, { useCallback, useEffect } from 'react'
import { BackHandler, StatusBar, StyleSheet, Text, View } from 'react-native'
import { State } from 'react-native-track-player'
import IconFA from 'react-native-vector-icons/FontAwesome'
import IconFA5 from 'react-native-vector-icons/FontAwesome5'
@ -28,14 +27,17 @@ import ImageGradientBackground from '@app/components/ImageGradientBackground'
import PressableOpacity from '@app/components/PressableOpacity'
import dimensions from '@app/styles/dimensions'
import { NativeStackScreenProps } from 'react-native-screens/native-stack'
import { useFocusEffect } from '@react-navigation/native'
const NowPlayingHeader = () => {
// eslint-disable-next-line no-spaced-func
const NowPlayingHeader = React.memo<{
backHandler: () => void
}>(({ backHandler }) => {
const queueName = useAtomValue(queueNameAtom)
const navigation = useNavigation()
return (
<View style={headerStyles.container}>
<PressableOpacity onPress={() => navigation.goBack()} style={headerStyles.icons} ripple={true}>
<PressableOpacity onPress={backHandler} style={headerStyles.icons} ripple={true}>
<IconMat name="arrow-back" color="white" size={25} />
</PressableOpacity>
<Text numberOfLines={1} style={headerStyles.queueName}>
@ -46,7 +48,7 @@ const NowPlayingHeader = () => {
</PressableOpacity>
</View>
)
}
})
const headerStyles = StyleSheet.create({
container: {
@ -302,24 +304,41 @@ const controlsStyles = StyleSheet.create({
})
type RootStackParamList = {
Main: undefined
NowPlaying: undefined
main: undefined
'now-playing': undefined
}
type NowPlayingProps = NativeStackScreenProps<RootStackParamList, 'NowPlaying'>
type NowPlayingProps = NativeStackScreenProps<RootStackParamList, 'now-playing'>
const NowPlayingLayout: React.FC<NowPlayingProps> = ({ navigation }) => {
const track = useAtomValue(currentTrackAtom)
useEffect(() => {
if (!track && navigation.canGoBack()) {
const back = useCallback(() => {
if (navigation.canGoBack()) {
navigation.popToTop()
} else {
navigation.navigate('main')
}
return true
}, [navigation])
useEffect(() => {
if (!track) {
back()
}
})
useFocusEffect(
useCallback(() => {
BackHandler.addEventListener('hardwareBackPress', back)
return () => BackHandler.removeEventListener('hardwareBackPress', back)
}, [back]),
)
return (
<View style={styles.container}>
<ImageGradientBackground imageUri={track?.artwork as string} imageKey={`${track?.album}${track?.artist}`} />
<NowPlayingHeader />
<NowPlayingHeader backHandler={back} />
<View style={styles.content}>
<SongCoverArt />
<SongInfo />

View File

@ -18,7 +18,7 @@ const TestControls = () => {
return (
<View>
<Button title="Remove all keys" onPress={removeAllKeys} />
<Button title="Now Playing" onPress={() => navigation.navigate('NowPlaying')} />
<Button title="Now Playing" onPress={() => navigation.navigate('now-playing')} />
</View>
)
}

View File

@ -55,7 +55,8 @@
"jest": "^26.6.3",
"metro-react-native-babel-preset": "^0.64.0",
"react-test-renderer": "17.0.1",
"typescript": "^3.8.3"
"typescript": "^3.8.3",
"uri-scheme": "^1.0.91"
},
"resolutions": {
"@types/react": "^17"

View File

@ -6718,6 +6718,11 @@ uri-js@^4.2.2:
dependencies:
punycode "^2.1.0"
uri-scheme@^1.0.91:
version "1.0.91"
resolved "https://registry.yarnpkg.com/uri-scheme/-/uri-scheme-1.0.91.tgz#9169b7d4ab421f29fc6576885b30a7be4e39780e"
integrity sha512-/vy0dGnTgiojTGiV9QzmTy79HT4Xn2x1ee+rs8Geiav0w16Ayme2aRg5W71GcARB2ck/fYrxDZBIPlntVbwKuQ==
urix@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"