diff --git a/app/components/AlbumArt.tsx b/app/components/AlbumArt.tsx deleted file mode 100644 index 90cd225..0000000 --- a/app/components/AlbumArt.tsx +++ /dev/null @@ -1,57 +0,0 @@ -import { useAtomValue } from 'jotai/utils' -import React from 'react' -import { ActivityIndicator, View } from 'react-native' -import FastImage from 'react-native-fast-image' -import LinearGradient from 'react-native-linear-gradient' -import { albumArtAtomFamily } from '@app/state/music' -import colors from '@app/styles/colors' -import CoverArt from '@app/components/CoverArt' - -interface AlbumArtProps { - id: string - height: string | number - width: string | number -} - -const AlbumArt: React.FC = ({ id, height, width }) => { - const albumArt = useAtomValue(albumArtAtomFamily(id)) - - const Placeholder = () => ( - - - - ) - - return ( - 200 ? albumArt?.uri : albumArt?.thumbUri} - /> - ) -} - -const AlbumArtFallback: React.FC = ({ height, width }) => ( - - - -) - -const AlbumArtLoader: React.FC = props => ( - }> - - -) - -export default React.memo(AlbumArtLoader) diff --git a/app/components/CoverArt.tsx b/app/components/CoverArt.tsx index 07c08d4..1066d9d 100644 --- a/app/components/CoverArt.tsx +++ b/app/components/CoverArt.tsx @@ -4,7 +4,7 @@ import FastImage from 'react-native-fast-image' import colors from '@app/styles/colors' const CoverArt: React.FC<{ - PlaceholderComponent: () => JSX.Element + PlaceholderComponent?: () => JSX.Element height?: string | number width?: string | number coverArtUri?: string @@ -25,6 +25,7 @@ const CoverArt: React.FC<{ resizeMode={FastImage.resizeMode.contain} onError={() => { setLoading(false) + console.log('asdfdsaf') setPlaceholderVisible(true) }} onLoadEnd={() => setLoading(false)} @@ -35,7 +36,7 @@ const CoverArt: React.FC<{ {coverArtUri ? : <>} - + {PlaceholderComponent ? : <>} diff --git a/app/components/NowPlayingBar.tsx b/app/components/NowPlayingBar.tsx index 16a91c7..c7b216e 100644 --- a/app/components/NowPlayingBar.tsx +++ b/app/components/NowPlayingBar.tsx @@ -69,7 +69,6 @@ const NowPlayingBar = () => { hi} height={styles.subContainer.height} width={styles.subContainer.height} coverArtUri={track?.artworkThumb} diff --git a/app/models/music.ts b/app/models/music.ts index f7ff3c9..73b624e 100644 --- a/app/models/music.ts +++ b/app/models/music.ts @@ -37,11 +37,6 @@ export interface AlbumListItem { coverArtThumbUri?: string } -export interface AlbumArt { - uri?: string - thumbUri?: string -} - export interface AlbumWithSongs extends Album { songs: Song[] } diff --git a/app/screens/AlbumView.tsx b/app/screens/AlbumView.tsx index 9de4953..f4cf511 100644 --- a/app/screens/AlbumView.tsx +++ b/app/screens/AlbumView.tsx @@ -8,11 +8,11 @@ import { albumAtomFamily } from '@app/state/music' import { currentTrackAtom, useSetQueue } from '@app/state/trackplayer' import colors from '@app/styles/colors' import font from '@app/styles/font' -import AlbumArt from '@app/components/AlbumArt' import Button from '@app/components/Button' import GradientBackground from '@app/components/GradientBackground' import ImageGradientScrollView from '@app/components/ImageGradientScrollView' import PressableOpacity from '@app/components/PressableOpacity' +import CoverArt from '@app/components/CoverArt' const SongItem: React.FC<{ id: string @@ -91,7 +91,7 @@ const AlbumDetails: React.FC<{ style={styles.container}> - + {album.name} diff --git a/app/screens/Home.tsx b/app/screens/Home.tsx index e0665da..444ea81 100644 --- a/app/screens/Home.tsx +++ b/app/screens/Home.tsx @@ -1,6 +1,7 @@ import CoverArt from '@app/components/CoverArt' import GradientScrollView from '@app/components/GradientScrollView' import PressableOpacity from '@app/components/PressableOpacity' +import { AlbumListItem } from '@app/models/music' import { albumLists } from '@app/state/music' import colors from '@app/styles/colors' import font from '@app/styles/font' @@ -9,13 +10,38 @@ import { useAtomValue } from 'jotai/utils' import React from 'react' import { ScrollView, StatusBar, StyleSheet, Text, View } from 'react-native' -const Category: React.FC<{ - name: string - stateKey: string -}> = ({ name, stateKey }) => { +const AlbumItem: React.FC<{ + album: AlbumListItem +}> = ({ album }) => { const navigation = useNavigation() - const state = albumLists[stateKey] + return ( + navigation.navigate('AlbumView', { id: album.id, title: album.name })} + key={album.id} + style={styles.item}> + <>} + coverArtUri={album.coverArtThumbUri} + height={styles.item.width} + width={styles.item.width} + /> + + {album.name} + + + {album.artist} + + + ) +} +const MemoAlbumItem = React.memo(AlbumItem) + +const Category: React.FC<{ + name: string + type: string +}> = ({ name, type }) => { + const state = albumLists[type] const list = useAtomValue(state.listAtom) const updating = useAtomValue(state.updatingAtom) const updateList = state.useUpdateList() @@ -28,40 +54,26 @@ const Category: React.FC<{ {list.map(album => ( - navigation.navigate('AlbumView', { id: album.id, title: album.name })} - key={album.id} - style={styles.item}> - <>} - coverArtUri={album.coverArtThumbUri} - height={styles.item.width} - width={styles.item.width} - /> - - {album.name} - - - {album.artist} - - + ))} ) } +const MemoCategory = React.memo(Category) const Home = () => ( - - - - - + + + + + ) diff --git a/app/screens/LibraryAlbums.tsx b/app/screens/LibraryAlbums.tsx index bdf0492..967c3b7 100644 --- a/app/screens/LibraryAlbums.tsx +++ b/app/screens/LibraryAlbums.tsx @@ -1,14 +1,14 @@ +import CoverArt from '@app/components/CoverArt' +import GradientFlatList from '@app/components/GradientFlatList' +import PressableOpacity from '@app/components/PressableOpacity' +import { Album } from '@app/models/music' +import { albumLists } from '@app/state/music' +import colors from '@app/styles/colors' +import font from '@app/styles/font' import { useNavigation } from '@react-navigation/native' import { useAtomValue } from 'jotai/utils' import React, { useEffect } from 'react' import { StyleSheet, Text, useWindowDimensions, View } from 'react-native' -import { Album } from '@app/models/music' -import { albumsAtom, albumsUpdatingAtom, useUpdateAlbums } from '@app/state/music' -import font from '@app/styles/font' -import AlbumArt from '@app/components/AlbumArt' -import GradientFlatList from '@app/components/GradientFlatList' -import colors from '@app/styles/colors' -import PressableOpacity from '@app/components/PressableOpacity' const AlbumItem: React.FC<{ id: string @@ -16,14 +16,15 @@ const AlbumItem: React.FC<{ size: number height: number artist?: string -}> = ({ id, name, artist, size, height }) => { + coverArtUri?: string +}> = ({ id, name, artist, size, height, coverArtUri }) => { const navigation = useNavigation() return ( navigation.navigate('AlbumView', { id, title: name })}> - + {name} @@ -42,6 +43,7 @@ const AlbumListRenderItem: React.FC<{ }> = ({ item }) => ( { - const albums = useAtomValue(albumsAtom) - const updating = useAtomValue(albumsUpdatingAtom) - const updateAlbums = useUpdateAlbums() + const state = albumLists.alphabeticalByArtist + const list = useAtomValue(state.listAtom) + const updating = useAtomValue(state.updatingAtom) + const updateList = state.useUpdateList() + const layout = useWindowDimensions() const size = layout.width / 3 - styles.item.marginHorizontal * 2 const height = size + 44 - const albumsList = Object.values(albums).map(album => ({ album, size, height })) + const albumsList = list.map(album => ({ album, size, height })) useEffect(() => { if (albumsList.length === 0) { - updateAlbums() + updateList() } }) @@ -75,7 +79,7 @@ const AlbumsList = () => { numColumns={3} removeClippedSubviews={true} refreshing={updating} - onRefresh={updateAlbums} + onRefresh={updateList} overScrollMode="never" getItemLayout={(_data, index) => ({ length: height, diff --git a/app/screens/NowPlayingLayout.tsx b/app/screens/NowPlayingLayout.tsx index 7270b53..1159d9a 100644 --- a/app/screens/NowPlayingLayout.tsx +++ b/app/screens/NowPlayingLayout.tsx @@ -73,12 +73,7 @@ const SongCoverArt = () => { return ( - } - height={'100%'} - width={'100%'} - coverArtUri={track?.artwork as string} - /> + ) } diff --git a/app/state/music.ts b/app/state/music.ts index 1cdd4df..8035e73 100644 --- a/app/state/music.ts +++ b/app/state/music.ts @@ -1,6 +1,6 @@ import { Atom, atom, useAtom, WritableAtom } from 'jotai' import { atomFamily, useAtomValue, useUpdateAtom } from 'jotai/utils' -import { Album, AlbumArt, AlbumListItem, AlbumWithSongs, Artist, ArtistArt, ArtistInfo, Song } from '@app/models/music' +import { Album, AlbumListItem, AlbumWithSongs, Artist, ArtistArt, ArtistInfo, Song } from '@app/models/music' import { SubsonicApiClient } from '@app/subsonic/api' import { AlbumID3Element, ArtistInfo2Element, ChildElement } from '@app/subsonic/elements' import { GetArtistResponse } from '@app/subsonic/responses' @@ -39,42 +39,11 @@ export const useUpdateArtists = () => { } } -export const albumsAtom = atom>({}) -export const albumsUpdatingAtom = atom(false) - -export const useUpdateAlbums = () => { - const server = useAtomValue(activeServerAtom) - const [updating, setUpdating] = useAtom(albumsUpdatingAtom) - const setAlbums = useUpdateAtom(albumsAtom) - - if (!server) { - return () => Promise.resolve() - } - - return async () => { - if (updating) { - return - } - setUpdating(true) - - const client = new SubsonicApiClient(server) - const response = await client.getAlbumList2({ type: 'alphabeticalByArtist', size: 500 }) - - setAlbums( - response.data.albums.reduce((acc, next) => { - const album = mapAlbumID3(next, client) - acc[album.id] = album - return acc - }, {} as Record), - ) - setUpdating(false) - } -} - const useUpdateAlbumListBase = ( type: GetAlbumList2Type, albumListAtom: WritableAtom, updatingAtom: WritableAtom, + size: number, ) => { const server = useAtomValue(activeServerAtom) const setAlbumList = useUpdateAtom(albumListAtom) @@ -91,19 +60,19 @@ const useUpdateAlbumListBase = ( setUpdating(true) const client = new SubsonicApiClient(server) - const response = await client.getAlbumList2({ type, size: 20 }) + const response = await client.getAlbumList2({ type, size }) setAlbumList(response.data.albums.map(a => mapAlbumID3toAlbumListItem(a, client))) setUpdating(false) } } -function createAlbumList(type: GetAlbumList2Type) { +function createAlbumList(type: GetAlbumList2Type, size = 20) { const listAtom = atom([]) const listReadAtom = atom(get => get(listAtom)) const updatingAtom = atom(false) const updatingReadAtom = atom(get => get(updatingAtom)) - const useUpdateAlbumList = () => useUpdateAlbumListBase(type, listAtom, updatingAtom) + const useUpdateAlbumList = () => useUpdateAlbumListBase(type, listAtom, updatingAtom, size) return { listAtom, listReadAtom, updatingAtom, updatingReadAtom, useUpdateAlbumList } } @@ -114,6 +83,7 @@ type ListState = { useUpdateList: () => () => Promise } +const alphabeticalByArtist = createAlbumList('alphabeticalByArtist', 500) const recent = createAlbumList('recent') const starred = createAlbumList('starred') const frequent = createAlbumList('frequent') @@ -121,6 +91,11 @@ const random = createAlbumList('random') const newest = createAlbumList('newest') export const albumLists: { [key: string]: ListState } = { + alphabeticalByArtist: { + listAtom: alphabeticalByArtist.listReadAtom, + updatingAtom: alphabeticalByArtist.updatingReadAtom, + useUpdateList: alphabeticalByArtist.useUpdateAlbumList, + }, recent: { listAtom: recent.listReadAtom, updatingAtom: recent.updatingReadAtom, @@ -148,35 +123,6 @@ export const albumLists: { [key: string]: ListState } = { }, } -export const useRecentAlbums = () => { - const server = useAtomValue(activeServerAtom) - const [updating, setUpdating] = useAtom(albumsUpdatingAtom) - const setAlbums = useUpdateAtom(albumsAtom) - - if (!server) { - return async () => {} - } - - return async () => { - if (updating) { - return - } - setUpdating(true) - - const client = new SubsonicApiClient(server) - const response = await client.getAlbumList2({ type: 'alphabeticalByArtist', size: 500 }) - - setAlbums( - response.data.albums.reduce((acc, next) => { - const album = mapAlbumID3(next, client) - acc[album.id] = album - return acc - }, {} as Record), - ) - setUpdating(false) - } -} - export const albumAtomFamily = atomFamily((id: string) => atom(async get => { const server = get(activeServerAtom) @@ -190,28 +136,6 @@ export const albumAtomFamily = atomFamily((id: string) => }), ) -export const albumArtAtomFamily = atomFamily((id: string) => - atom(async get => { - const server = get(activeServerAtom) - if (!server) { - return undefined - } - - const albums = get(albumsAtom) - const album = id in albums ? albums[id] : undefined - if (!album) { - return undefined - } - - const client = new SubsonicApiClient(server) - - return { - uri: album.coverArt ? client.getCoverArtUri({ id: album.coverArt }) : undefined, - thumbUri: album.coverArt ? client.getCoverArtUri({ id: album.coverArt, size: '256' }) : undefined, - } - }), -) - export const artistInfoAtomFamily = atomFamily((id: string) => atom(async get => { const server = get(activeServerAtom)