mirror of
https://github.com/austinried/subtracks.git
synced 2025-12-27 00:59:28 +01:00
image optimizations
This commit is contained in:
parent
b1944f7791
commit
c8ed5bf5cb
2441
package-lock.json
generated
2441
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -18,6 +18,7 @@
|
||||
"md5": "^2.3.0",
|
||||
"react": "17.0.1",
|
||||
"react-native": "0.64.1",
|
||||
"react-native-fast-image": "^8.3.4",
|
||||
"react-native-fs": "^2.18.0",
|
||||
"react-native-gesture-handler": "^1.10.3",
|
||||
"react-native-get-random-values": "^1.7.0",
|
||||
|
||||
@ -3,6 +3,7 @@ import { Text, View, Image, Pressable } from 'react-native';
|
||||
import { BottomTabBarProps } from '@react-navigation/bottom-tabs';
|
||||
import textStyles from '../../styles/text';
|
||||
import colors from '../../styles/colors';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
|
||||
const icons: {[key: string]: any} = {
|
||||
home: {
|
||||
@ -66,13 +67,13 @@ const BottomTabBar: React.FC<BottomTabBarProps> = ({ state, descriptors, navigat
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
<FastImage
|
||||
source={isFocused ? img.fill : img.regular}
|
||||
style={{
|
||||
height: 26,
|
||||
width: 26,
|
||||
tintColor: isFocused ? colors.text.primary : colors.text.secondary,
|
||||
}}
|
||||
tintColor={isFocused ? colors.text.primary : colors.text.secondary}
|
||||
/>
|
||||
<Text style={{
|
||||
...textStyles.xsmall,
|
||||
|
||||
@ -1,62 +1,45 @@
|
||||
import React, { memo, useEffect, useState } from 'react';
|
||||
import { View, Image, Text, FlatList, Button, ListRenderItem } from 'react-native';
|
||||
import { useRecoilState, useRecoilValue } from 'recoil';
|
||||
import { Album } from '../../models/music';
|
||||
import { albumsState, albumState, useUpdateAlbums, albumIdsState, useCoverArtUri } from '../../state/albums';
|
||||
import TopTabContainer from '../common/TopTabContainer';
|
||||
import textStyles from '../../styles/text';
|
||||
import { ScrollView } from 'react-native-gesture-handler';
|
||||
import colors from '../../styles/colors';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { FlatList, Text, View } from 'react-native';
|
||||
import FastImage from 'react-native-fast-image';
|
||||
import LinearGradient from 'react-native-linear-gradient';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import { Album } from '../../models/music';
|
||||
import { albumsState, useCoverArtUri, useUpdateAlbums } from '../../state/albums';
|
||||
import colors from '../../styles/colors';
|
||||
import textStyles from '../../styles/text';
|
||||
import TopTabContainer from '../common/TopTabContainer';
|
||||
|
||||
const AlbumArt: React.FC<{ height: number, width: number, id?: string }> = ({ height, width, id }) => {
|
||||
const coverArtSource = useCoverArtUri(id);
|
||||
|
||||
// useEffect(() => {
|
||||
// console.log(id);
|
||||
// });
|
||||
const coverArtUri = useCoverArtUri(id);
|
||||
|
||||
const Placeholder = (
|
||||
<LinearGradient
|
||||
colors={[colors.accent, colors.accentLow]}
|
||||
style={{
|
||||
height, width,
|
||||
}}
|
||||
style={{ height, width }}
|
||||
>
|
||||
<Image
|
||||
<FastImage
|
||||
source={require('../../../res/record-m.png')}
|
||||
style={{
|
||||
height, width,
|
||||
resizeMode: 'contain',
|
||||
}}
|
||||
style={{ height, width }}
|
||||
resizeMode={FastImage.resizeMode.contain}
|
||||
/>
|
||||
</LinearGradient>
|
||||
);
|
||||
|
||||
const CoverArt = (
|
||||
<View style={{
|
||||
height, width,
|
||||
}}>
|
||||
<Image
|
||||
source={{ uri: coverArtSource }}
|
||||
style={{
|
||||
height, width,
|
||||
resizeMode: 'contain',
|
||||
}}
|
||||
<View style={{ height, width }}>
|
||||
<FastImage
|
||||
source={{ uri: coverArtUri }}
|
||||
style={{ height, width }}
|
||||
resizeMode={FastImage.resizeMode.contain}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
|
||||
return coverArtSource ? CoverArt : Placeholder;
|
||||
return coverArtUri ? CoverArt : Placeholder;
|
||||
}
|
||||
const MemoAlbumArt = React.memo(AlbumArt);
|
||||
|
||||
const AlbumItem: React.FC<{ id: string } > = ({ id }) => {
|
||||
const album = useRecoilValue(albumState(id));
|
||||
|
||||
// useEffect(() => {
|
||||
// console.log(album.name);
|
||||
// });
|
||||
|
||||
const AlbumItem: React.FC<{ name: string, coverArt?: string } > = ({ name, coverArt }) => {
|
||||
const size = 125;
|
||||
|
||||
return (
|
||||
@ -68,10 +51,10 @@ const AlbumItem: React.FC<{ id: string } > = ({ id }) => {
|
||||
// width: size,
|
||||
flex: 1/3,
|
||||
}}>
|
||||
<AlbumArt
|
||||
<MemoAlbumArt
|
||||
width={size}
|
||||
height={size}
|
||||
id={album.coverArt}
|
||||
id={coverArt}
|
||||
/>
|
||||
<View style={{
|
||||
flex: 1,
|
||||
@ -85,7 +68,7 @@ const AlbumItem: React.FC<{ id: string } > = ({ id }) => {
|
||||
}}
|
||||
numberOfLines={2}
|
||||
>
|
||||
{album.name}
|
||||
{name}
|
||||
</Text>
|
||||
<Text
|
||||
style={{
|
||||
@ -94,28 +77,24 @@ const AlbumItem: React.FC<{ id: string } > = ({ id }) => {
|
||||
}}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{album.name}
|
||||
{name}
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
const MemoAlbumItem = React.memo(AlbumItem);
|
||||
|
||||
const MemoAlbumItem = memo(AlbumItem, (prev, next) => {
|
||||
// console.log('prev: ' + JSON.stringify(prev) + ' next: ' + JSON.stringify(next))
|
||||
return prev.id == next.id;
|
||||
});
|
||||
const AlbumListRenderItem: React.FC<{ item: Album }> = ({ item }) => (
|
||||
<MemoAlbumItem name={item.name} coverArt={item.coverArt} />
|
||||
);
|
||||
|
||||
const AlbumsList = () => {
|
||||
const albumIds = useRecoilValue(albumIdsState);
|
||||
const albums = useRecoilValue(albumsState);
|
||||
const updateAlbums = useUpdateAlbums();
|
||||
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
|
||||
const renderItem: React.FC<{ item: string }> = ({ item }) => (
|
||||
<MemoAlbumItem id={item} />
|
||||
);
|
||||
|
||||
const refresh = async () => {
|
||||
setRefreshing(true);
|
||||
await updateAlbums();
|
||||
@ -123,7 +102,7 @@ const AlbumsList = () => {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!refreshing && albumIds.length === 0) {
|
||||
if (!refreshing && Object.keys(albums).length === 0) {
|
||||
refresh();
|
||||
}
|
||||
});
|
||||
@ -131,13 +110,13 @@ const AlbumsList = () => {
|
||||
return (
|
||||
<View style={{ flex: 1 }}>
|
||||
<FlatList
|
||||
data={albumIds}
|
||||
renderItem={renderItem}
|
||||
keyExtractor={item => item}
|
||||
data={Object.values(albums)}
|
||||
renderItem={AlbumListRenderItem}
|
||||
keyExtractor={item => item.id}
|
||||
onRefresh={refresh}
|
||||
refreshing={refreshing}
|
||||
numColumns={3}
|
||||
removeClippedSubviews={false}
|
||||
removeClippedSubviews={true}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
@ -151,4 +130,4 @@ const AlbumsTab = () => (
|
||||
</TopTabContainer>
|
||||
);
|
||||
|
||||
export default AlbumsTab;
|
||||
export default React.memo(AlbumsTab);
|
||||
|
||||
@ -10,6 +10,4 @@ export interface Album {
|
||||
name: string;
|
||||
starred?: Date;
|
||||
coverArt?: string;
|
||||
coverArtPath?: string;
|
||||
coverArtModified?: Date;
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { atom, DefaultValue, selector, selectorFamily, useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
import { atom, DefaultValue, selector, selectorFamily, useRecoilValue, useSetRecoilState } from 'recoil';
|
||||
import { SubsonicApiClient } from '../subsonic/api';
|
||||
import { activeServer } from './settings'
|
||||
import { Album } from '../models/music';
|
||||
@ -23,21 +23,11 @@ export const albumsState = atom<{ [id: string]: Album }>({
|
||||
],
|
||||
});
|
||||
|
||||
export const albumIdsState = selector<string[]>({
|
||||
key: 'albumIdsState',
|
||||
get: ({get}) => Object.keys(get(albumsState)),
|
||||
});
|
||||
|
||||
export const albumState = selectorFamily<Album, string>({
|
||||
key: 'albumState',
|
||||
get: id => ({ get }) => {
|
||||
return get(albumsState)[id];
|
||||
},
|
||||
// set: id => ({ set, get }, newValue) => {
|
||||
// if (!(newValue instanceof DefaultValue)) {
|
||||
// set(albumsState, prevState => ({ ...prevState, [id]: newValue }));
|
||||
// }
|
||||
// }
|
||||
});
|
||||
|
||||
export const useUpdateAlbums = () => {
|
||||
@ -49,7 +39,7 @@ export const useUpdateAlbums = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
const client = new SubsonicApiClient(server.address, server.username, server.token, server.salt);
|
||||
const client = new SubsonicApiClient(server);
|
||||
const response = await client.getAlbumList2({ type: 'alphabeticalByArtist', size: 50 });
|
||||
|
||||
const albums = response.data.albums.reduce((acc, x) => {
|
||||
@ -65,7 +55,7 @@ export const useUpdateAlbums = () => {
|
||||
};
|
||||
};
|
||||
|
||||
export function useCoverArtUri(id: string | undefined): string | undefined {
|
||||
export function useCoverArtUri(id?: string): string | undefined {
|
||||
if (!id) {
|
||||
return undefined;
|
||||
}
|
||||
@ -100,7 +90,7 @@ export function useCoverArtUri(id: string | undefined): string | undefined {
|
||||
return;
|
||||
}
|
||||
|
||||
const client = new SubsonicApiClient(server.address, server.username, server.token, server.salt);
|
||||
const client = new SubsonicApiClient(server);
|
||||
await client.getCoverArt({ id });
|
||||
|
||||
setCoverArtSource(fileUri);
|
||||
|
||||
@ -30,7 +30,7 @@ export const useUpdateArtists = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
const client = new SubsonicApiClient(server.address, server.username, server.token, server.salt);
|
||||
const client = new SubsonicApiClient(server);
|
||||
const response = await client.getArtists();
|
||||
|
||||
setArtists(response.data.artists.map(x => ({
|
||||
|
||||
@ -2,6 +2,7 @@ import { DOMParser } from 'xmldom';
|
||||
import RNFS from 'react-native-fs';
|
||||
import { GetAlbumList2Params, GetAlbumListParams, GetArtistInfo2Params, GetArtistInfoParams, GetCoverArtParams, GetIndexesParams } from './params';
|
||||
import { GetAlbumList2Response, GetAlbumListResponse, GetArtistInfo2Response, GetArtistInfoResponse, GetArtistsResponse, GetIndexesResponse, SubsonicResponse } from './responses';
|
||||
import { ServerSettings } from '../models/settings';
|
||||
|
||||
export class SubsonicApiError extends Error {
|
||||
method: string;
|
||||
@ -56,14 +57,14 @@ export class SubsonicApiClient {
|
||||
|
||||
private params: URLSearchParams
|
||||
|
||||
constructor(address: string, username: string, token: string, salt: string) {
|
||||
this.address = address;
|
||||
this.username = username;
|
||||
constructor(server: ServerSettings) {
|
||||
this.address = server.address;
|
||||
this.username = server.username;
|
||||
|
||||
this.params = new URLSearchParams();
|
||||
this.params.append('u', username);
|
||||
this.params.append('t', token);
|
||||
this.params.append('s', salt);
|
||||
this.params.append('u', server.username);
|
||||
this.params.append('t', server.token);
|
||||
this.params.append('s', server.salt);
|
||||
this.params.append('v', '1.15.0');
|
||||
this.params.append('c', 'subsonify-cool-unique-app-string')
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user