Revert "switched to navigation-react-native"

This reverts commit a8d0211ab7739b71fc5e32206ff3e85dbf7f051c.
This commit is contained in:
austinried 2021-06-25 09:23:19 +09:00
parent 17fe1b9850
commit 4152ff6cfb
22 changed files with 3268 additions and 356 deletions

View File

@ -1,13 +1,18 @@
import React from 'react'; import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { RecoilRoot } from 'recoil'; import { RecoilRoot } from 'recoil';
import SplashPage from './src/components/SplashPage'; import SplashPage from './src/components/SplashPage';
import RootNavigator from './src/components/navigation/RootNavigator'; import RootNavigator from './src/components/navigation/RootNavigator';
import BottomTabNavigator from './src/components/navigation/BottomTabNavigator';
import { enableScreens } from 'react-native-screens';
enableScreens();
const App = () => ( const App = () => (
<RecoilRoot> <RecoilRoot>
<SplashPage> <SplashPage>
<BottomTabNavigator /> <NavigationContainer>
<RootNavigator />
</NavigationContainer>
</SplashPage> </SplashPage>
</RecoilRoot> </RecoilRoot>
); );

View File

@ -9,11 +9,4 @@
# Add any project specific keep options here: # Add any project specific keep options here:
-keep public class com.dylanvann.fastimage.* {*;} -keep class com.facebook.react.turbomodule.** { *; }
-keep public class com.dylanvann.fastimage.** {*;}
-keep public class * implements com.bumptech.glide.module.GlideModule
-keep public class * extends com.bumptech.glide.module.AppGlideModule
-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
**[] $VALUES;
public *;
}

View File

@ -1,6 +1,7 @@
package com.subsonify; package com.subsonify;
import com.facebook.react.ReactActivity; import com.facebook.react.ReactActivity;
import android.os.Bundle;
public class MainActivity extends ReactActivity { public class MainActivity extends ReactActivity {
@ -12,4 +13,9 @@ public class MainActivity extends ReactActivity {
protected String getMainComponentName() { protected String getMainComponentName() {
return "SubSonify"; return "SubSonify";
} }
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(null);
}
} }

View File

@ -12,6 +12,10 @@ import com.facebook.soloader.SoLoader;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.util.List; import java.util.List;
// for reanimated
import com.facebook.react.bridge.JSIModulePackage;
import com.swmansion.reanimated.ReanimatedJSIModulePackage;
public class MainApplication extends Application implements ReactApplication { public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = private final ReactNativeHost mReactNativeHost =
@ -34,6 +38,12 @@ public class MainApplication extends Application implements ReactApplication {
protected String getJSMainModuleName() { protected String getJSMainModuleName() {
return "index"; return "index";
} }
// for reanimated
@Override
protected JSIModulePackage getJSIModulePackage() {
return new ReanimatedJSIModulePackage();
}
}; };
@Override @Override

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:duration="300"
android:fromAlpha="0"
android:toAlpha="1" />
</set>

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:duration="300"
android:fromAlpha="1"
android:toAlpha="0" />
</set>

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="300"
android:fromXDelta="100%"
android:toXDelta="0" />
</set>

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="300"
android:fromXDelta="0"
android:toXDelta="100%" />
</set>

View File

@ -1,3 +1,7 @@
module.exports = { module.exports = {
presets: ['module:metro-react-native-babel-preset'], presets: ['module:metro-react-native-babel-preset'],
plugins: [
// reanimated has to be listed last in plugins
'react-native-reanimated/plugin',
],
}; };

View File

@ -1,3 +1,4 @@
import 'react-native-gesture-handler';
import 'react-native-get-random-values'; import 'react-native-get-random-values';
import { AppRegistry, LogBox } from 'react-native'; import { AppRegistry, LogBox } from 'react-native';

3118
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -10,17 +10,23 @@
"lint": "eslint . --ext .js,.jsx,.ts,.tsx" "lint": "eslint . --ext .js,.jsx,.ts,.tsx"
}, },
"dependencies": { "dependencies": {
"@react-native-community/masked-view": "^0.1.11",
"@react-navigation/bottom-tabs": "^5.11.11",
"@react-navigation/material-top-tabs": "^5.3.15",
"@react-navigation/native": "^5.9.4",
"@react-navigation/stack": "^5.14.5",
"md5": "^2.3.0", "md5": "^2.3.0",
"navigation": "^5.5.0",
"navigation-react": "^4.3.0",
"navigation-react-native": "^7.4.2",
"react": "17.0.1", "react": "17.0.1",
"react-native": "0.64.1", "react-native": "0.64.1",
"react-native-fast-image": "^8.3.4",
"react-native-fs": "^2.18.0", "react-native-fs": "^2.18.0",
"react-native-gesture-handler": "^1.10.3",
"react-native-get-random-values": "^1.7.0", "react-native-get-random-values": "^1.7.0",
"react-native-linear-gradient": "^2.5.6", "react-native-linear-gradient": "^2.5.6",
"react-native-reanimated": "^2.0.0",
"react-native-safe-area-context": "^3.2.0",
"react-native-screens": "^3.4.0",
"react-native-sqlite-storage": "^5.0.0", "react-native-sqlite-storage": "^5.0.0",
"react-native-tab-view": "^2.16.0",
"react-native-track-player": "^1.2.7", "react-native-track-player": "^1.2.7",
"recoil": "^0.3.1", "recoil": "^0.3.1",
"uuid": "^8.3.2", "uuid": "^8.3.2",

View File

@ -1,4 +1,4 @@
import React, { useEffect } from 'react'; import React from 'react';
import { Button, FlatList, Text, View } from 'react-native'; import { Button, FlatList, Text, View } from 'react-native';
import { useRecoilValue, useResetRecoilState } from 'recoil'; import { useRecoilValue, useResetRecoilState } from 'recoil';
import { artistsState, useUpdateArtists } from '../state/artists'; import { artistsState, useUpdateArtists } from '../state/artists';
@ -21,12 +21,6 @@ const List = () => {
<ArtistItem item={item} /> <ArtistItem item={item} />
); );
console.log('rendering artists');
useEffect(() => {
console.log('mounting artists');
});
return ( return (
<FlatList <FlatList
data={artists} data={artists}

View File

@ -1,4 +1,4 @@
import React, { useContext, useEffect, useState } from 'react'; import React, { useEffect, useState } from 'react';
import { Button, TextInput, View, Text } from 'react-native'; import { Button, TextInput, View, Text } from 'react-native';
import { useRecoilState } from 'recoil'; import { useRecoilState } from 'recoil';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
@ -6,7 +6,8 @@ import md5 from 'md5';
import { musicDb, settingsDb } from '../clients'; import { musicDb, settingsDb } from '../clients';
import { appSettingsState, serversState } from '../state/settings'; import { appSettingsState, serversState } from '../state/settings';
import { DbStorage } from '../storage/db'; import { DbStorage } from '../storage/db';
import { NavigationContext } from 'navigation-react'; import { StackScreenProps } from '@react-navigation/stack';
import { useNavigation } from '@react-navigation/core';
const RecreateDbButton: React.FC<{ db: DbStorage, title: string }> = ({ db, title }) => { const RecreateDbButton: React.FC<{ db: DbStorage, title: string }> = ({ db, title }) => {
const [inProgress, setInProgress] = useState(false); const [inProgress, setInProgress] = useState(false);
@ -31,14 +32,14 @@ const RecreateDbButton: React.FC<{ db: DbStorage, title: string }> = ({ db, titl
} }
const DbControls = () => { const DbControls = () => {
const { stateNavigator } = useContext(NavigationContext); const navigation = useNavigation();
return ( return (
<View> <View>
<RecreateDbButton db={musicDb} title='Music' /> <RecreateDbButton db={musicDb} title='Music' />
<RecreateDbButton db={settingsDb} title='Settings' /> <RecreateDbButton db={settingsDb} title='Settings' />
<Button <Button
title='Now Playing' title='Now Playing'
onPress={() => stateNavigator.navigate('nowplaying')} onPress={() => navigation.navigate('Now Playing')}
/> />
</View> </View>
); );

View File

@ -1,10 +1,8 @@
import React from 'react'; import React from 'react';
import { Text, View, Image, Pressable } from 'react-native'; import { Text, View, Image, Pressable } from 'react-native';
import { BottomTabBarProps } from '@react-navigation/bottom-tabs';
import textStyles from '../../styles/text'; import textStyles from '../../styles/text';
import colors from '../../styles/colors'; import colors from '../../styles/colors';
import { useContext } from 'react';
import { NavigationContext } from 'navigation-react';
import FastImage from 'react-native-fast-image';
const icons: {[key: string]: any} = { const icons: {[key: string]: any} = {
home: { home: {
@ -25,43 +23,7 @@ const icons: {[key: string]: any} = {
}, },
} }
const BottomTabButton: React.FC<{ const BottomTabBar: React.FC<BottomTabBarProps> = ({ state, descriptors, navigation }) => {
route: string,
title: string,
onPress: () => void,
isFocused: boolean,
}> = ({ route, title, onPress, isFocused }) => {
const img = icons[route];
return (
<Pressable
onPress={onPress}
style={{
alignItems: 'center',
flex: 1,
}}
>
<FastImage
source={isFocused ? img.fill : img.regular}
style={{
height: 26,
width: 26,
}}
tintColor={isFocused ? colors.text.primary : colors.text.secondary}
/>
<Text style={{
...textStyles.xsmall,
color: isFocused ? colors.text.primary : colors.text.secondary,
}}>
{title}
</Text>
</Pressable>
);
}
const BottomTabBar = () => {
const { stateNavigator } = useContext(NavigationContext);
return ( return (
<View style={{ <View style={{
height: 54, height: 54,
@ -71,19 +33,56 @@ const BottomTabBar = () => {
justifyContent: 'space-around', justifyContent: 'space-around',
paddingHorizontal: 28, paddingHorizontal: 28,
}}> }}>
{Object.values(stateNavigator.states).map(state => ( {state.routes.map((route, index) => {
<BottomTabButton const { options } = descriptors[route.key] as any;
key={state.key} const label =
route={state.key} options.tabBarLabel !== undefined
title={state.title} ? options.tabBarLabel as string
onPress={() => { : options.title !== undefined
if (stateNavigator.stateContext.state.key !== state.key) { ? options.title
stateNavigator.navigate(state.key); : route.name;
const isFocused = state.index === index;
const img = icons[options.icon];
const onPress = () => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
canPreventDefault: true,
});
if (!isFocused && !event.defaultPrevented) {
navigation.navigate(route.name);
} }
};
return (
<Pressable
key={route.key}
onPress={onPress}
style={{
alignItems: 'center',
flex: 1,
}}
>
<Image
source={isFocused ? img.fill : img.regular}
style={{
height: 26,
width: 26,
tintColor: isFocused ? colors.text.primary : colors.text.secondary,
}} }}
isFocused={stateNavigator.stateContext.state.key === state.key}
/> />
))} <Text style={{
...textStyles.xsmall,
color: isFocused ? colors.text.primary : colors.text.secondary,
}}>
{label}
</Text>
</Pressable>
);
})}
</View> </View>
); );
} }

View File

@ -1,23 +1,35 @@
import { NavigationContext } from 'navigation-react'; import React from 'react';
import React, { useContext } from 'react'; import { Text, View } from 'react-native';
import { Pressable, Text, View } from 'react-native'; import { MaterialTopTabBarProps } from '@react-navigation/material-top-tabs';
import colors from '../../styles/colors'; import colors from '../../styles/colors';
import textStyles from '../../styles/text'; import textStyles from '../../styles/text';
const TopTabButton: React.FC<{ const TopTabBar: React.FC<MaterialTopTabBarProps> = ({ state, descriptors }) => {
title: string, return (
onPress: () => void, <View style={{
isFocused: boolean, backgroundColor: colors.gradient.high,
}> = ({ title, onPress, isFocused }) => { flexDirection: 'row',
alignItems: 'flex-start',
justifyContent: 'flex-start',
}}>
{state.routes.map((route, index) => {
const { options } = descriptors[route.key];
const label =
options.tabBarLabel !== undefined
? options.tabBarLabel
: options.title !== undefined
? options.title
: route.name;
const isFocused = state.index === index;
const color = isFocused ? colors.text.primary : colors.text.secondary; const color = isFocused ? colors.text.primary : colors.text.secondary;
const borderBottomColor = isFocused ? colors.accent : colors.gradient.high; const borderBottomColor = isFocused ? colors.accent : colors.gradient.high;
return ( return (
<Pressable <View key={route.key} style={{
onPress={onPress}
style={{
borderBottomColor, borderBottomColor,
borderBottomWidth: 1.5, borderBottomWidth: 1.5,
// paddingVertical: 8,
width: 94, width: 94,
height: 44, height: 44,
justifyContent: 'center', justifyContent: 'center',
@ -25,32 +37,10 @@ const TopTabButton: React.FC<{
}}> }}>
<Text style={{ <Text style={{
...textStyles.header, color, ...textStyles.header, color,
}}>{title}</Text> }}>{label}</Text>
</Pressable> </View>
); );
} })}
const TopTabBar = () => {
const { stateNavigator } = useContext(NavigationContext);
return (
<View style={{
backgroundColor: colors.gradient.high,
flexDirection: 'row',
justifyContent: 'space-evenly',
}}>
{Object.values(stateNavigator.states).map(state => (
<TopTabButton
key={state.key}
title={state.title}
onPress={() => {
if (stateNavigator.stateContext.state.key !== state.key) {
stateNavigator.navigate(state.key);
}
}}
isFocused={stateNavigator.stateContext.state.key === state.key}
/>
))}
</View> </View>
); );
} }

View File

@ -1,16 +1,17 @@
import React, { memo, useEffect, useState } from 'react'; import React, { memo, useEffect, useState } from 'react';
import { View, Image, Text, FlatList, Button, ListRenderItem, ScrollView } from 'react-native'; import { View, Image, Text, FlatList, Button, ListRenderItem } from 'react-native';
import { useRecoilState, useRecoilValue } from 'recoil'; import { useRecoilState, useRecoilValue } from 'recoil';
import { Album } from '../../models/music'; import { Album } from '../../models/music';
import { albumsState, albumState, useUpdateAlbums, albumIdsState, useCoverArtUri } from '../../state/albums'; import { albumsState, albumState, useUpdateAlbums, albumIdsState, useCoverArtUri } from '../../state/albums';
import TopTabContainer from '../common/TopTabContainer'; import TopTabContainer from '../common/TopTabContainer';
import textStyles from '../../styles/text'; import textStyles from '../../styles/text';
import { ScrollView } from 'react-native-gesture-handler';
import colors from '../../styles/colors'; import colors from '../../styles/colors';
import LinearGradient from 'react-native-linear-gradient'; import LinearGradient from 'react-native-linear-gradient';
import FastImage from 'react-native-fast-image';
import RNFS from 'react-native-fs';
const AlbumArt: React.FC<{ height: number, width: number, id?: string }> = ({ height, width, id }) => { const AlbumArt: React.FC<{ height: number, width: number, id?: string }> = ({ height, width, id }) => {
const coverArtSource = useCoverArtUri(id);
// useEffect(() => { // useEffect(() => {
// console.log(id); // console.log(id);
// }); // });
@ -18,12 +19,16 @@ const AlbumArt: React.FC<{ height: number, width: number, id?: string }> = ({ he
const Placeholder = ( const Placeholder = (
<LinearGradient <LinearGradient
colors={[colors.accent, colors.accentLow]} colors={[colors.accent, colors.accentLow]}
style={{ height, width }} style={{
height, width,
}}
> >
<FastImage <Image
source={require('../../../res/record-m.png')} source={require('../../../res/record-m.png')}
style={{ height, width }} style={{
resizeMode={FastImage.resizeMode.contain} height, width,
resizeMode: 'contain',
}}
/> />
</LinearGradient> </LinearGradient>
); );
@ -32,23 +37,24 @@ const AlbumArt: React.FC<{ height: number, width: number, id?: string }> = ({ he
<View style={{ <View style={{
height, width, height, width,
}}> }}>
<FastImage <Image
source={{ uri: `file://${RNFS.DocumentDirectoryPath}/image_cache/${id}` }} source={{ uri: coverArtSource }}
style={{ height, width }} style={{
resizeMode={FastImage.resizeMode.contain} height, width,
resizeMode: 'contain',
}}
/> />
</View> </View>
); );
return id ? CoverArt : Placeholder; return coverArtSource ? CoverArt : Placeholder;
} }
const AlbumItem: React.FC<{ const AlbumItem: React.FC<{ id: string } > = ({ id }) => {
name: string, const album = useRecoilValue(albumState(id));
coverArt?: string,
} > = ({ name, coverArt }) => {
// useEffect(() => { // useEffect(() => {
// console.log(name); // console.log(album.name);
// }); // });
const size = 125; const size = 125;
@ -60,13 +66,12 @@ const AlbumItem: React.FC<{
marginVertical: 8, marginVertical: 8,
// marginLeft: 6, // marginLeft: 6,
// width: size, // width: size,
height: 180,
flex: 1/3, flex: 1/3,
}}> }}>
<AlbumArt <AlbumArt
width={size} width={size}
height={size} height={size}
id={coverArt} id={album.coverArt}
/> />
<View style={{ <View style={{
flex: 1, flex: 1,
@ -80,7 +85,7 @@ const AlbumItem: React.FC<{
}} }}
numberOfLines={2} numberOfLines={2}
> >
{name} {album.name}
</Text> </Text>
<Text <Text
style={{ style={{
@ -89,34 +94,36 @@ const AlbumItem: React.FC<{
}} }}
numberOfLines={1} numberOfLines={1}
> >
{name} {album.name}
</Text> </Text>
</View> </View>
</View> </View>
); );
} }
function renderItem(props: { item: Album }) { const MemoAlbumItem = memo(AlbumItem, (prev, next) => {
return <AlbumItem name={props.item.name} coverArt={props.item.coverArt} />; // console.log('prev: ' + JSON.stringify(prev) + ' next: ' + JSON.stringify(next))
} return prev.id == next.id;
});
const AlbumsList = () => { const AlbumsList = () => {
const albums = useRecoilValue(albumsState); const albumIds = useRecoilValue(albumIdsState);
const updateAlbums = useUpdateAlbums(); const updateAlbums = useUpdateAlbums();
const [refreshing, setRefreshing] = useState(false); const [refreshing, setRefreshing] = useState(false);
const renderItem: React.FC<{ item: string }> = ({ item }) => (
<MemoAlbumItem id={item} />
);
const refresh = async () => { const refresh = async () => {
setRefreshing(true); setRefreshing(true);
await updateAlbums(); await updateAlbums();
setRefreshing(false); setRefreshing(false);
} }
console.log('rendering albums');
useEffect(() => { useEffect(() => {
console.log('mounting albums'); if (!refreshing && albumIds.length === 0) {
if (!refreshing && Object.keys(albums).length === 0) {
refresh(); refresh();
} }
}); });
@ -124,37 +131,22 @@ const AlbumsList = () => {
return ( return (
<View style={{ flex: 1 }}> <View style={{ flex: 1 }}>
<FlatList <FlatList
data={Object.values(albums)} data={albumIds}
renderItem={renderItem} renderItem={renderItem}
keyExtractor={item => item.id} keyExtractor={item => item}
onRefresh={refresh} onRefresh={refresh}
refreshing={refreshing} refreshing={refreshing}
numColumns={3} numColumns={3}
removeClippedSubviews={true} removeClippedSubviews={false}
// initialNumToRender={3}
// maxToRenderPerBatch={2}
// updateCellsBatchingPeriod={1000}
getItemLayout={(data, index) => ({
length: 180,
offset: 180 * Math.floor(index / 3),
index
})}
/> />
{/* <ScrollView>
{Object.values(albums).map(album => (
<AlbumItem name={album.name} coverArt={album.coverArt} key={album.id} />
))}
</ScrollView> */}
</View> </View>
); );
} }
const MemoAlbumsList = React.memo(AlbumsList);
const AlbumsTab = () => ( const AlbumsTab = () => (
<TopTabContainer> <TopTabContainer>
<React.Suspense fallback={<Text>Loading...</Text>}> <React.Suspense fallback={<Text>Loading...</Text>}>
<MemoAlbumsList /> <AlbumsList />
</React.Suspense> </React.Suspense>
</TopTabContainer> </TopTabContainer>
); );

View File

@ -1,36 +1,40 @@
import React from 'react'; import React from 'react';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import SettingsView from '../Settings'; import SettingsView from '../Settings';
import NowPlayingLayout from '../NowPlayingLayout'; import NowPlayingLayout from '../NowPlayingLayout';
import ArtistsList from '../ArtistsList'; import ArtistsList from '../ArtistsList';
import LibraryTopTabNavigator from './LibraryTopTabNavigator'; import LibraryTopTabNavigator from './LibraryTopTabNavigator';
import BottomTabBar from '../common/BottomTabBar'; import BottomTabBar from '../common/BottomTabBar';
import { NavigationHandler } from 'navigation-react';
import { NavigationStack } from 'navigation-react-native';
import { StateNavigator } from 'navigation';
const stateNavigator = new StateNavigator([ const Tab = createBottomTabNavigator();
{ key: 'home', title: 'Home' },
{ key: 'library', title: 'Library', trackCrumbTrail: true },
{ key: 'search', title: 'Search', trackCrumbTrail: true },
{ key: 'settings', title: 'Settings', trackCrumbTrail: true },
]);
const { home, library, search, settings } = stateNavigator.states; const BottomTabNavigator = () => {
home.renderScene = ArtistsList; return (
library.renderScene = LibraryTopTabNavigator; <Tab.Navigator
search.renderScene = NowPlayingLayout; tabBar={BottomTabBar}
settings.renderScene = SettingsView; >
<Tab.Screen
const BottomTabNavigator = () => ( name='Home'
<NavigationHandler stateNavigator={stateNavigator}> component={ArtistsList}
<NavigationStack options={{ icon: 'home' } as any}
unmountStyle={from => from ? 'fade_in' : 'fade_out'}
crumbStyle={from => from ? 'fade_in' : 'fade_out'}
/> />
<BottomTabBar /> <Tab.Screen
</NavigationHandler> name='Library'
component={LibraryTopTabNavigator}
options={{ icon: 'library' } as any}
/>
<Tab.Screen
name='Search'
component={NowPlayingLayout}
options={{ icon: 'search' } as any}
/>
<Tab.Screen
name='Settings'
component={SettingsView}
options={{ icon: 'settings' } as any}
/>
</Tab.Navigator>
); );
}
stateNavigator.navigate('home');
export default BottomTabNavigator; export default BottomTabNavigator;

View File

@ -1,34 +1,32 @@
import React from 'react'; import React from 'react';
import { View } from 'react-native'; import { View } from 'react-native';
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
import AlbumsTab from '../library/AlbumsTab'; import AlbumsTab from '../library/AlbumsTab';
import ArtistsTab from '../library/ArtistsTab'; import ArtistsTab from '../library/ArtistsTab';
import PlaylistsTab from '../library/PlaylistsTab'; import PlaylistsTab from '../library/PlaylistsTab';
import TopTabBar from '../common/TopTabBar'; import TopTabBar from '../common/TopTabBar';
import { StateNavigator } from 'navigation';
import { NavigationHandler } from 'navigation-react';
import { NavigationStack } from 'navigation-react-native';
const stateNavigator = new StateNavigator([ const Tab = createMaterialTopTabNavigator();
{ key: 'albums', title: 'Albums' },
{ key: 'artists', title: 'Artists', trackCrumbTrail: true, },
{ key: 'playlists', title: 'Playlists', trackCrumbTrail: true, },
]);
const { albums, artists, playlists } = stateNavigator.states;
albums.renderScene = AlbumsTab;
artists.renderScene = ArtistsTab;
playlists.renderScene = PlaylistsTab;
const LibraryTopTabNavigator = () => ( const LibraryTopTabNavigator = () => (
<NavigationHandler stateNavigator={stateNavigator}> <View style={{
<TopTabBar /> flex: 1,
<NavigationStack }}>
unmountStyle={from => from ? 'slide_in' : 'slide_out'} <Tab.Navigator tabBar={TopTabBar}>
crumbStyle={from => from ? 'slide_in' : 'slide_out'} <Tab.Screen
name='Albums'
component={AlbumsTab}
/> />
</NavigationHandler> <Tab.Screen
name='Artists'
component={ArtistsTab}
/>
<Tab.Screen
name='Playlists'
component={PlaylistsTab}
/>
</Tab.Navigator>
</View>
); );
stateNavigator.navigate('albums');
export default LibraryTopTabNavigator; export default LibraryTopTabNavigator;

View File

@ -1,26 +1,23 @@
import { StateNavigator } from 'navigation';
import { NavigationHandler } from 'navigation-react';
import { NavigationStack } from 'navigation-react-native';
import React from 'react'; import React from 'react';
import { View } from 'react-native'; import { createStackNavigator } from '@react-navigation/stack';
import NowPlayingLayout from '../NowPlayingLayout'; import NowPlayingLayout from '../NowPlayingLayout';
import BottomTabNavigator from './BottomTabNavigator'; import BottomTabNavigator from './BottomTabNavigator';
const stateNavigator = new StateNavigator([ const RootStack = createStackNavigator();
{ key: 'main' },
{ key: 'nowplaying', trackCrumbTrail: true },
]);
const { main, nowplaying } = stateNavigator.states;
main.renderScene = () => <BottomTabNavigator />;
nowplaying.renderScene = () => <NowPlayingLayout />;
const RootNavigator = () => ( const RootNavigator = () => (
<NavigationHandler stateNavigator={stateNavigator}> <RootStack.Navigator>
<NavigationStack /> <RootStack.Screen
</NavigationHandler> name='Main'
component={BottomTabNavigator}
options={{ headerShown: false }}
/>
<RootStack.Screen
name='Now Playing'
component={NowPlayingLayout}
options={{ headerShown: false }}
/>
</RootStack.Navigator>
); );
stateNavigator.navigate('main');
export default RootNavigator; export default RootNavigator;

View File

@ -101,7 +101,7 @@ export function useCoverArtUri(id: string | undefined): string | undefined {
} }
const client = new SubsonicApiClient(server.address, server.username, server.token, server.salt); const client = new SubsonicApiClient(server.address, server.username, server.token, server.salt);
await client.getCoverArt({ id, size: '32' }); await client.getCoverArt({ id });
setCoverArtSource(fileUri); setCoverArtSource(fileUri);
} }

View File

@ -78,7 +78,7 @@ export class SubsonicApiClient {
} }
const url = `${this.address}/rest/${method}?${query}`; const url = `${this.address}/rest/${method}?${query}`;
// console.log(url); console.log(url);
return url; return url;
} }
@ -98,7 +98,7 @@ export class SubsonicApiClient {
const response = await fetch(this.buildUrl(method, params)); const response = await fetch(this.buildUrl(method, params));
const text = await response.text(); const text = await response.text();
// console.log(text); console.log(text);
const xml = new DOMParser().parseFromString(text); const xml = new DOMParser().parseFromString(text);
if (xml.documentElement.getAttribute('status') !== 'ok') { if (xml.documentElement.getAttribute('status') !== 'ok') {