moooore styling

started albums
these commits are messy
This commit is contained in:
austinried 2021-06-19 17:19:49 +09:00
parent f19cbabac4
commit c9b096d347
29 changed files with 312 additions and 55 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -22,6 +22,14 @@
496B4B9B91BC401DB51B3EC8 /* Lato-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = F4F4A1F14BEF4BFAA4E8820C /* Lato-Regular.ttf */; };
65CF38EF987D48FE87417D95 /* Lato-Thin.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 02B784765C954771AFD3D736 /* Lato-Thin.ttf */; };
14DD6760CD4745C5BE5F4BE8 /* Lato-ThinItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 88AF24D136144BE4866DE912 /* Lato-ThinItalic.ttf */; };
FE9FA81B39A64124AED77EA4 /* Ubuntu-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = E4F99098BF914E1A931626C4 /* Ubuntu-Bold.ttf */; };
BD8F136628F04F9DB5C97EAA /* Ubuntu-BoldItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 63EFC089F68F4855AAD51042 /* Ubuntu-BoldItalic.ttf */; };
34B5978651964F458F13B159 /* Ubuntu-Italic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9AB4011E8C8D457C96C60260 /* Ubuntu-Italic.ttf */; };
1FAA1C3FB1E3484A9BC95DEA /* Ubuntu-Light.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 0453473C29104FFE89072356 /* Ubuntu-Light.ttf */; };
D27F67A28A5F4FB49E94D881 /* Ubuntu-LightItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = B95CE032E2AD4CF296A08240 /* Ubuntu-LightItalic.ttf */; };
C775139A328B487880547BF7 /* Ubuntu-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 54F543DA45B14889BB58F889 /* Ubuntu-Medium.ttf */; };
7156B9E946AD49D8A71B576A /* Ubuntu-MediumItalic.ttf in Resources */ = {isa = PBXBuildFile; fileRef = F6F917F33913423F90E92389 /* Ubuntu-MediumItalic.ttf */; };
D26C3BD0DD4A46A19FC194A7 /* Ubuntu-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9C7D70BCA0BC439CAC9BD94B /* Ubuntu-Regular.ttf */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -114,6 +122,14 @@
F4F4A1F14BEF4BFAA4E8820C /* Lato-Regular.ttf */ = {isa = PBXFileReference; name = "Lato-Regular.ttf"; path = "../assets/fonts/Lato-Regular.ttf"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
02B784765C954771AFD3D736 /* Lato-Thin.ttf */ = {isa = PBXFileReference; name = "Lato-Thin.ttf"; path = "../assets/fonts/Lato-Thin.ttf"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
88AF24D136144BE4866DE912 /* Lato-ThinItalic.ttf */ = {isa = PBXFileReference; name = "Lato-ThinItalic.ttf"; path = "../assets/fonts/Lato-ThinItalic.ttf"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
E4F99098BF914E1A931626C4 /* Ubuntu-Bold.ttf */ = {isa = PBXFileReference; name = "Ubuntu-Bold.ttf"; path = "../assets/fonts/Ubuntu-Bold.ttf"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
63EFC089F68F4855AAD51042 /* Ubuntu-BoldItalic.ttf */ = {isa = PBXFileReference; name = "Ubuntu-BoldItalic.ttf"; path = "../assets/fonts/Ubuntu-BoldItalic.ttf"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
9AB4011E8C8D457C96C60260 /* Ubuntu-Italic.ttf */ = {isa = PBXFileReference; name = "Ubuntu-Italic.ttf"; path = "../assets/fonts/Ubuntu-Italic.ttf"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
0453473C29104FFE89072356 /* Ubuntu-Light.ttf */ = {isa = PBXFileReference; name = "Ubuntu-Light.ttf"; path = "../assets/fonts/Ubuntu-Light.ttf"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
B95CE032E2AD4CF296A08240 /* Ubuntu-LightItalic.ttf */ = {isa = PBXFileReference; name = "Ubuntu-LightItalic.ttf"; path = "../assets/fonts/Ubuntu-LightItalic.ttf"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
54F543DA45B14889BB58F889 /* Ubuntu-Medium.ttf */ = {isa = PBXFileReference; name = "Ubuntu-Medium.ttf"; path = "../assets/fonts/Ubuntu-Medium.ttf"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
F6F917F33913423F90E92389 /* Ubuntu-MediumItalic.ttf */ = {isa = PBXFileReference; name = "Ubuntu-MediumItalic.ttf"; path = "../assets/fonts/Ubuntu-MediumItalic.ttf"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
9C7D70BCA0BC439CAC9BD94B /* Ubuntu-Regular.ttf */ = {isa = PBXFileReference; name = "Ubuntu-Regular.ttf"; path = "../assets/fonts/Ubuntu-Regular.ttf"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = unknown; explicitFileType = undefined; includeInIndex = 0; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -274,6 +290,14 @@
F4F4A1F14BEF4BFAA4E8820C /* Lato-Regular.ttf */,
02B784765C954771AFD3D736 /* Lato-Thin.ttf */,
88AF24D136144BE4866DE912 /* Lato-ThinItalic.ttf */,
E4F99098BF914E1A931626C4 /* Ubuntu-Bold.ttf */,
63EFC089F68F4855AAD51042 /* Ubuntu-BoldItalic.ttf */,
9AB4011E8C8D457C96C60260 /* Ubuntu-Italic.ttf */,
0453473C29104FFE89072356 /* Ubuntu-Light.ttf */,
B95CE032E2AD4CF296A08240 /* Ubuntu-LightItalic.ttf */,
54F543DA45B14889BB58F889 /* Ubuntu-Medium.ttf */,
F6F917F33913423F90E92389 /* Ubuntu-MediumItalic.ttf */,
9C7D70BCA0BC439CAC9BD94B /* Ubuntu-Regular.ttf */,
);
name = Resources;
sourceTree = "<group>";
@ -437,6 +461,14 @@
496B4B9B91BC401DB51B3EC8 /* Lato-Regular.ttf in Resources */,
65CF38EF987D48FE87417D95 /* Lato-Thin.ttf in Resources */,
14DD6760CD4745C5BE5F4BE8 /* Lato-ThinItalic.ttf in Resources */,
FE9FA81B39A64124AED77EA4 /* Ubuntu-Bold.ttf in Resources */,
BD8F136628F04F9DB5C97EAA /* Ubuntu-BoldItalic.ttf in Resources */,
34B5978651964F458F13B159 /* Ubuntu-Italic.ttf in Resources */,
1FAA1C3FB1E3484A9BC95DEA /* Ubuntu-Light.ttf in Resources */,
D27F67A28A5F4FB49E94D881 /* Ubuntu-LightItalic.ttf in Resources */,
C775139A328B487880547BF7 /* Ubuntu-Medium.ttf in Resources */,
7156B9E946AD49D8A71B576A /* Ubuntu-MediumItalic.ttf in Resources */,
D26C3BD0DD4A46A19FC194A7 /* Ubuntu-Regular.ttf in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -63,6 +63,14 @@
<string>Lato-Regular.ttf</string>
<string>Lato-Thin.ttf</string>
<string>Lato-ThinItalic.ttf</string>
<string>Ubuntu-Bold.ttf</string>
<string>Ubuntu-BoldItalic.ttf</string>
<string>Ubuntu-Italic.ttf</string>
<string>Ubuntu-Light.ttf</string>
<string>Ubuntu-LightItalic.ttf</string>
<string>Ubuntu-Medium.ttf</string>
<string>Ubuntu-MediumItalic.ttf</string>
<string>Ubuntu-Regular.ttf</string>
</array>
</dict>
</plist>

15
package-lock.json generated
View File

@ -18,6 +18,7 @@
"react-native": "0.64.1",
"react-native-gesture-handler": "^1.10.3",
"react-native-get-random-values": "^1.7.0",
"react-native-linear-gradient": "^2.5.6",
"react-native-reanimated": "^2.2.0",
"react-native-safe-area-context": "^3.2.0",
"react-native-screens": "^3.4.0",
@ -10949,6 +10950,14 @@
"react-native": ">=0.42.0"
}
},
"node_modules/react-native-linear-gradient": {
"version": "2.5.6",
"resolved": "https://registry.npmjs.org/react-native-linear-gradient/-/react-native-linear-gradient-2.5.6.tgz",
"integrity": "sha512-HDwEaXcQIuXXCV70O+bK1rizFong3wj+5Q/jSyifKFLg0VWF95xh8XQgfzXwtq0NggL9vNjPKXa016KuFu+VFg==",
"peerDependencies": {
"react-native": ">=0.55"
}
},
"node_modules/react-native-reanimated": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-2.2.0.tgz",
@ -22076,6 +22085,12 @@
"integrity": "sha512-HOf0jzRnq2/aFUcdCJ9w9JGzN3gdEg0zFE4FyYlp4jtidqU03D5X7ZegGKfT1EWteR0gPBGp9ye5T5FvSWi9Yg==",
"requires": {}
},
"react-native-linear-gradient": {
"version": "2.5.6",
"resolved": "https://registry.npmjs.org/react-native-linear-gradient/-/react-native-linear-gradient-2.5.6.tgz",
"integrity": "sha512-HDwEaXcQIuXXCV70O+bK1rizFong3wj+5Q/jSyifKFLg0VWF95xh8XQgfzXwtq0NggL9vNjPKXa016KuFu+VFg==",
"requires": {}
},
"react-native-reanimated": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-2.2.0.tgz",

View File

@ -20,6 +20,7 @@
"react-native": "0.64.1",
"react-native-gesture-handler": "^1.10.3",
"react-native-get-random-values": "^1.7.0",
"react-native-linear-gradient": "^2.5.6",
"react-native-reanimated": "^2.2.0",
"react-native-safe-area-context": "^3.2.0",
"react-native-screens": "^3.4.0",

View File

@ -1,5 +1,6 @@
import React from 'react';
import { Image, ImageSourcePropType } from 'react-native';
import { primary } from '../styles/colors';
export type FocusableIconProps = {
focused: boolean,
@ -11,12 +12,16 @@ export type FocusableIconProps = {
const FocusableIcon: React.FC<FocusableIconProps> = (props) => {
props.focusedSource = props.focusedSource || props.source;
props.width = props.width || 32;
props.height = props.height || 32;
props.width = props.width || 26;
props.height = props.height || 26;
return (
<Image
style={{ height: props.height, width: props.width }}
style={{
height: props.height,
width: props.width,
tintColor: props.focused ? primary.focused : primary.blurred,
}}
source={props.focused ? props.focusedSource : props.source}
/>
);

View File

@ -1,63 +1,144 @@
import React from 'react';
import { Text, View, Image } from 'react-native';
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
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 SectionHeader: React.FC<{ title: string }> = ({ title }) => {
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: 60,
height: 48,
backgroundColor: '#383838',
flexDirection: 'row',
justifyContent: 'space-between',
// backgroundColor: 'green',
alignItems: 'center',
paddingLeft: 15,
paddingRight: 15,
justifyContent: 'space-around',
}}>
<Text style={{
color: 'white',
fontSize: 22,
fontFamily: 'Lato-Black',
}}>{title}</Text>
<Image
style={{
width: 32,
height: 32,
tintColor: 'white',
}}
source={require('../../res/chevron_right-fill.png')}
/>
{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 Albums = () => (
<SectionHeader title='Albums' />
);
const Artists = () => (
<SectionHeader title='Artists' />
);
const Playlists = () => (
<SectionHeader title='Playlists' />
);
const Library = () => (
<Tab.Navigator>
<Tab.Screen
name='Albums'
component={Albums}
/>
<Tab.Screen
name='Artists'
component={Artists}
/>
<Tab.Screen
name='Playlists'
component={Playlists}
/>
</Tab.Navigator>
<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

@ -10,7 +10,15 @@ const Tab = createBottomTabNavigator();
const TabNavigator = () => {
return (
<Tab.Navigator>
<Tab.Navigator
tabBarOptions={{
style: {
backgroundColor: '#383838',
borderTopColor: '#383838',
height: 44,
},
}}
>
<Tab.Screen
name='Home'
component={ArtistsList}

View File

@ -1,4 +1,10 @@
export interface Artist {
id: string;
name: string;
coverArt?: string;
}
export interface Album {
id: string;
name: string;
}

41
src/state/albums.ts Normal file
View File

@ -0,0 +1,41 @@
import { atom, DefaultValue, selector, useRecoilValue, useSetRecoilState } from 'recoil';
import { SubsonicApiClient } from '../subsonic/api';
import { activeServer } from './settings'
import { Artist } from '../models/music';
import { musicDb } from '../clients';
export const albumsState = atom<Artist[]>({
key: 'albumsState',
default: selector({
key: 'albumsState/default',
get: () => musicDb.getAlbums(),
}),
effects_UNSTABLE: [
({ onSet }) => {
onSet((newValue) => {
if (!(newValue instanceof DefaultValue)) {
musicDb.updateAlbums(newValue);
}
});
}
],
});
// export const useUpdateAlbums = () => {
// const setAlbums = useSetRecoilState(albumsState);
// const server = useRecoilValue(activeServer);
// return async () => {
// if (!server) {
// return;
// }
// const client = new SubsonicApiClient(server.address, server.username, server.token, server.salt);
// const response = await client.getAlbums();
// setAlbums(response.data.albums.map(i => ({
// id: i.id,
// name: i.name,
// })));
// };
// };

View File

@ -33,9 +33,10 @@ export const useUpdateArtists = () => {
const client = new SubsonicApiClient(server.address, server.username, server.token, server.salt);
const response = await client.getArtists();
setArtists(response.data.artists.map(i => ({
id: i.id,
name: i.name,
setArtists(response.data.artists.map(x => ({
id: x.id,
name: x.name,
coverArt: x.coverArt,
})));
};
};

View File

@ -1,4 +1,4 @@
import { Artist } from '../models/music';
import { Album, Artist } from '../models/music';
import { DbStorage } from './db';
export class MusicDb extends DbStorage {
@ -10,6 +10,14 @@ export class MusicDb extends DbStorage {
await this.initDb(tx => {
tx.executeSql(`
CREATE TABLE artists (
id TEXT PRIMARY KEY NOT NULL,
name TEXT NOT NULL,
starred INTEGER NOT NULL,
coverArt TEXT
);
`);
tx.executeSql(`
CREATE TABLE albums (
id TEXT PRIMARY KEY NOT NULL,
name TEXT NOT NULL,
starred INTEGER NOT NULL
@ -24,6 +32,7 @@ export class MusicDb extends DbStorage {
`))[0].rows.raw().map(x => ({
id: x.id,
name: x.name,
coverArt: x.coverArt || undefined,
}));
}
@ -34,7 +43,30 @@ export class MusicDb extends DbStorage {
`);
for (const a of artists) {
tx.executeSql(`
INSERT INTO artists (id, name, starred)
INSERT INTO artists (id, name, starred, coverArt)
VALUES (?, ?, ?, ?);
`, [a.id, a.name, false, a.coverArt || null]);
}
});
}
async getAlbums(): Promise<Album[]> {
return (await this.executeSql(`
SELECT * FROM albums;
`))[0].rows.raw().map(x => ({
id: x.id,
name: x.name,
}));
}
async updateAlbums(albums: Album[]): Promise<void> {
await this.transaction((tx) => {
tx.executeSql(`
DELETE FROM albums
`);
for (const a of albums) {
tx.executeSql(`
INSERT INTO albums (id, name, starred)
VALUES (?, ?, ?);
`, [a.id, a.name, false]);
}

6
src/styles/colors.ts Normal file
View File

@ -0,0 +1,6 @@
import { StyleSheet } from "react-native";
export const primary = {
focused: '#fff',
blurred: '#bababa',
}

21
src/styles/text.ts Normal file
View File

@ -0,0 +1,21 @@
import { StyleSheet, TextStyle } from "react-native";
const regular: TextStyle = {
fontFamily: 'Ubuntu-Light',
fontSize: 18,
color: '#fff',
};
const header: TextStyle = {
...regular,
fontSize: 22,
};
export type TextStyles = {
[key: string]: TextStyle,
}
export default {
regular,
header,
};