reorg, start of custom buttom tabs

now we're cookin with bottom tabs
This commit is contained in:
austinried 2021-06-19 18:38:13 +09:00
parent c9b096d347
commit d82be24992
13 changed files with 310 additions and 214 deletions

View File

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

View File

@ -1,144 +0,0 @@
import React, { ReactComponentElement } from 'react';
import { Text, View, Image, FlatList } from 'react-native';
import { createMaterialTopTabNavigator, MaterialTopTabBarProps } from '@react-navigation/material-top-tabs';
import { NavigationContainer } from '@react-navigation/native';
import { Artist } from '../models/music';
import { useRecoilValue } from 'recoil';
import { artistsState } from '../state/artists';
import LinearGradient from 'react-native-linear-gradient';
import { primary } from '../styles/colors';
import text from '../styles/text';
const TabView: React.FC<{}> = ({ children }) => (
<LinearGradient
colors={['#383838', '#000000']}
// colors={['#395266', '#06172d']}
// start={{x: 0.0, y: 0.25}} end={{x: 0.5, y: 1.0}}
locations={[0.05,0.75]}
style={{
flex: 1,
}}
>
{children}
</LinearGradient>
);
const Albums = () => (
<TabView>
</TabView>
);
const Playlists = () => (
<TabView>
</TabView>
);
const ArtistItem: React.FC<{ item: Artist } > = ({ item }) => (
<View style={{
flexDirection: 'row',
alignItems: 'center',
// height: 56,
marginVertical: 6,
marginLeft: 6,
}}>
<Image
source={item.coverArt ? { uri: 'https://reactnative.dev/img/tiny_logo.png' } : require('../../res/mic_on-fill.png')}
style={{
width: 56,
height: 56,
// tintColor: 'white',
}}
/>
<Text style={{
...text.regular,
marginLeft: 12,
}}>{item.name}</Text>
</View>
);
const Artists = () => {
const artists = useRecoilValue(artistsState);
const renderItem: React.FC<{ item: Artist }> = ({ item }) => (
<ArtistItem item={item} />
);
return (
<TabView>
<FlatList
data={artists}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
</TabView>
);
}
const TabBar: React.FC<MaterialTopTabBarProps> = ({ state, descriptors }) => {
return (
<View style={{
height: 48,
backgroundColor: '#383838',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-around',
}}>
{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 fontFamily = isFocused ? 'Ubuntu-Regular' : 'Ubuntu-Light';
const color = isFocused ? primary.focused : primary.blurred;
const borderBottomColor = isFocused ? primary.focused : '#383838';
return (
<View style={{
borderBottomColor,
borderBottomWidth: 2,
borderBottomLeftRadius: 2,
borderBottomEndRadius: 2,
paddingBottom: 5,
width: 100,
justifyContent: 'center',
flexDirection: 'row',
}}>
<Text style={{
...text.header,
fontFamily, color
}}>{label}</Text>
</View>
);
})}
</View>
);
}
const Tab = createMaterialTopTabNavigator();
const Library = () => (
<View style={{
flex: 1,
}}>
<Tab.Navigator tabBar={TabBar}>
<Tab.Screen
name='Albums'
component={Albums}
/>
<Tab.Screen
name='Artists'
component={Artists}
/>
<Tab.Screen
name='Playlists'
component={Playlists}
/>
</Tab.Navigator>
</View>
);
export default Library;

View File

@ -1,66 +0,0 @@
import React from 'react';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import SettingsView from './Settings';
import NowPlayingLayout from './NowPlayingLayout';
import ArtistsList from './ArtistsList';
import FocusableIcon from './FocusableIcon';
import Library from './Library';
const Tab = createBottomTabNavigator();
const TabNavigator = () => {
return (
<Tab.Navigator
tabBarOptions={{
style: {
backgroundColor: '#383838',
borderTopColor: '#383838',
height: 44,
},
}}
>
<Tab.Screen
name='Home'
component={ArtistsList}
options={{
tabBarIcon: ({ focused }) => FocusableIcon({ focused,
source: require('../../res/home.png'),
focusedSource: require('../../res/home-fill.png'),
}),
}}
/>
<Tab.Screen
name='Library'
component={Library}
options={{
tabBarIcon: ({ focused }) => FocusableIcon({ focused,
source: require('../../res/library.png'),
focusedSource: require('../../res/library-fill.png'),
}),
}}
/>
<Tab.Screen
name='Search'
component={NowPlayingLayout}
options={{
tabBarIcon: ({ focused }) => FocusableIcon({ focused,
source: require('../../res/search.png'),
focusedSource: require('../../res/search-fill.png'),
}),
}}
/>
<Tab.Screen
name='Settings'
component={SettingsView}
options={{
tabBarIcon: ({ focused }) => FocusableIcon({ focused,
source: require('../../res/settings.png'),
focusedSource: require('../../res/settings-fill.png'),
}),
}}
/>
</Tab.Navigator>
);
}
export default TabNavigator;

View File

@ -0,0 +1,90 @@
import React from 'react';
import { Text, View, Image, Pressable } from 'react-native';
import { BottomTabBarProps } from '@react-navigation/bottom-tabs';
import textStyles from '../../styles/text';
const icons: {[key: string]: any} = {
home: {
regular: require('../../../res/home.png'),
fill: require('../../../res/home-fill.png'),
},
library: {
regular: require('../../../res/library.png'),
fill: require('../../../res/library-fill.png'),
},
search: {
regular: require('../../../res/search.png'),
fill: require('../../../res/search-fill.png'),
},
settings: {
regular: require('../../../res/settings.png'),
fill: require('../../../res/settings-fill.png'),
},
}
const BottomTabBar: React.FC<BottomTabBarProps> = ({ state, descriptors, navigation }) => {
return (
<View style={{
height: 54,
backgroundColor: '#383838',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-around',
paddingHorizontal: 12,
}}>
{state.routes.map((route, index) => {
const { options } = descriptors[route.key] as any;
const label =
options.tabBarLabel !== undefined
? options.tabBarLabel as string
: options.title !== undefined
? options.title
: 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: 24,
width: 24,
tintColor: isFocused ? 'white' : '#a0a0a0',
}}
/>
<Text style={{
...textStyles.small,
color: isFocused ? 'white' : '#a0a0a0',
fontFamily: isFocused ? 'Ubuntu-Medium' : 'Ubuntu-Light',
}}>
{label}
</Text>
</Pressable>
);
})}
</View>
);
}
export default BottomTabBar;

View File

@ -0,0 +1,52 @@
import React from 'react';
import { Text, View } from 'react-native';
import { MaterialTopTabBarProps } from '@react-navigation/material-top-tabs';
import { primary } from '../../styles/colors';
import text from '../../styles/text';
const TopTabBar: React.FC<MaterialTopTabBarProps> = ({ state, descriptors }) => {
return (
<View style={{
height: 48,
backgroundColor: '#383838',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-around',
}}>
{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 fontFamily = isFocused ? 'Ubuntu-Regular' : 'Ubuntu-Light';
const color = isFocused ? primary.focused : primary.blurred;
const borderBottomColor = isFocused ? primary.focused : '#383838';
return (
<View style={{
borderBottomColor,
borderBottomWidth: 2,
borderBottomLeftRadius: 2,
borderBottomEndRadius: 2,
paddingBottom: 5,
width: 100,
justifyContent: 'center',
flexDirection: 'row',
}}>
<Text style={{
...text.header,
fontFamily, color
}}>{label}</Text>
</View>
);
})}
</View>
);
}
export default TopTabBar;

View File

@ -0,0 +1,18 @@
import React from 'react';
import LinearGradient from 'react-native-linear-gradient';
const TopTabContainer: React.FC<{}> = ({ children }) => (
<LinearGradient
colors={['#383838', '#000000']}
// colors={['#395266', '#06172d']}
// start={{x: 0.0, y: 0.25}} end={{x: 0.5, y: 1.0}}
locations={[0.05,0.75]}
style={{
flex: 1,
}}
>
{children}
</LinearGradient>
);
export default TopTabContainer;

View File

@ -0,0 +1,9 @@
import React from 'react';
import TopTabContainer from '../common/TopTabContainer';
const AlbumsTab = () => (
<TopTabContainer>
</TopTabContainer>
);
export default AlbumsTab;

View File

@ -0,0 +1,50 @@
import React from 'react';
import { Text, View, Image, FlatList } from 'react-native';
import { Artist } from '../../models/music';
import { useRecoilValue } from 'recoil';
import { artistsState } from '../../state/artists';
import text from '../../styles/text';
import TopTabContainer from '../common/TopTabContainer';
const ArtistItem: React.FC<{ item: Artist } > = ({ item }) => (
<View style={{
flexDirection: 'row',
alignItems: 'center',
// height: 56,
marginVertical: 6,
marginLeft: 6,
}}>
<Image
source={item.coverArt ? { uri: 'https://reactnative.dev/img/tiny_logo.png' } : require('../../../res/mic_on-fill.png')}
style={{
width: 56,
height: 56,
// tintColor: 'white',
}}
/>
<Text style={{
...text.regular,
marginLeft: 12,
}}>{item.name}</Text>
</View>
);
const ArtistsTab = () => {
const artists = useRecoilValue(artistsState);
const renderItem: React.FC<{ item: Artist }> = ({ item }) => (
<ArtistItem item={item} />
);
return (
<TopTabContainer>
<FlatList
data={artists}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
</TopTabContainer>
);
}
export default ArtistsTab;

View File

@ -0,0 +1,9 @@
import React from 'react';
import TopTabContainer from '../common/TopTabContainer';
const PlaylistsTab = () => (
<TopTabContainer>
</TopTabContainer>
);
export default PlaylistsTab;

View File

@ -0,0 +1,40 @@
import React from 'react';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import SettingsView from '../Settings';
import NowPlayingLayout from '../NowPlayingLayout';
import ArtistsList from '../ArtistsList';
import LibraryTopTabNavigator from './LibraryTopTabNavigator';
import BottomTabBar from '../common/BottomTabBar';
const Tab = createBottomTabNavigator();
const BottomTabNavigator = () => {
return (
<Tab.Navigator
tabBar={BottomTabBar}
>
<Tab.Screen
name='Home'
component={ArtistsList}
options={{ icon: 'home' } as any}
/>
<Tab.Screen
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>
);
}
export default BottomTabNavigator;

View File

@ -0,0 +1,32 @@
import React from 'react';
import { View } from 'react-native';
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
import AlbumsTab from '../library/AlbumsTab';
import ArtistsTab from '../library/ArtistsTab';
import PlaylistsTab from '../library/PlaylistsTab';
import TopTabBar from '../common/TopTabBar';
const Tab = createMaterialTopTabNavigator();
const LibraryTopTabNavigator = () => (
<View style={{
flex: 1,
}}>
<Tab.Navigator tabBar={TopTabBar}>
<Tab.Screen
name='Albums'
component={AlbumsTab}
/>
<Tab.Screen
name='Artists'
component={ArtistsTab}
/>
<Tab.Screen
name='Playlists'
component={PlaylistsTab}
/>
</Tab.Navigator>
</View>
);
export default LibraryTopTabNavigator;

View File

@ -1,7 +1,7 @@
import React from 'react';
import { createStackNavigator } from '@react-navigation/stack';
import TabNavigator from './TabNavigator';
import NowPlayingLayout from './NowPlayingLayout';
import NowPlayingLayout from '../NowPlayingLayout';
import BottomTabNavigator from './BottomTabNavigator';
const RootStack = createStackNavigator();
@ -9,7 +9,7 @@ const RootNavigator = () => (
<RootStack.Navigator>
<RootStack.Screen
name='Main'
component={TabNavigator}
component={BottomTabNavigator}
options={{ headerShown: false }}
/>
<RootStack.Screen

View File

@ -11,6 +11,11 @@ const header: TextStyle = {
fontSize: 22,
};
const small: TextStyle = {
...regular,
fontSize: 11,
};
export type TextStyles = {
[key: string]: TextStyle,
}
@ -18,4 +23,5 @@ export type TextStyles = {
export default {
regular,
header,
small,
};