diff --git a/app/hooks/list.ts b/app/hooks/list.ts new file mode 100644 index 0000000..172f50b --- /dev/null +++ b/app/hooks/list.ts @@ -0,0 +1,69 @@ +import { useState, useCallback } from 'react' +import { useActiveServerRefresh } from './server' + +export const useFetchList = (fetchList: () => Promise) => { + const [list, setList] = useState([]) + const [refreshing, setRefreshing] = useState(false) + + const refresh = useCallback(() => { + setRefreshing(true) + + fetchList().then(items => { + setList(items) + setRefreshing(false) + }) + }, [fetchList]) + + useActiveServerRefresh( + useCallback(() => { + setList([]) + refresh() + }, [refresh]), + ) + + return { list, refreshing, refresh } +} + +export const useFetchPaginatedList = ( + fetchList: (size?: number, offset?: number) => Promise, + pageSize: number, +) => { + const [list, setList] = useState([]) + const [refreshing, setRefreshing] = useState(false) + const [offset, setOffset] = useState(0) + + const refresh = useCallback(() => { + setOffset(0) + setRefreshing(true) + + fetchList(pageSize, 0).then(firstPage => { + setList(firstPage) + setRefreshing(false) + }) + }, [fetchList, pageSize]) + + useActiveServerRefresh( + useCallback(() => { + setList([]) + refresh() + }, [refresh]), + ) + + const fetchNextPage = useCallback(() => { + const newOffset = offset + pageSize + setRefreshing(true) + + fetchList(pageSize, newOffset).then(nextPage => { + setRefreshing(false) + + if (nextPage.length === 0) { + return + } + + setList([...list, ...nextPage]) + setOffset(newOffset) + }) + }, [offset, pageSize, fetchList, list]) + + return { list, refreshing, refresh, fetchNextPage } +} diff --git a/app/hooks/server.ts b/app/hooks/server.ts index ea017ad..f6a29ab 100644 --- a/app/hooks/server.ts +++ b/app/hooks/server.ts @@ -18,32 +18,12 @@ export const useSwitchActiveServer = () => { } } -export const useActiveListRefresh = (list: unknown[], update: () => void) => { - const activeServer = useStore(selectSettings.activeServer) - - useEffect(() => { - if (list.length === 0) { - update() - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [activeServer]) -} - -export const useActiveListRefresh2 = (update: () => void) => { - const activeServer = useStore(selectSettings.activeServer) - - useEffect(() => { - update() - }, [activeServer, update]) -} - -export const useActiveServerRefresh = (update: () => void) => { +export const useActiveServerRefresh = (refresh: () => void) => { const activeServer = useStore(selectSettings.activeServer) useEffect(() => { if (activeServer) { - update() + refresh() } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [activeServer]) + }, [activeServer, refresh]) } diff --git a/app/screens/Home.tsx b/app/screens/Home.tsx index 6dc0c7a..a09a35a 100644 --- a/app/screens/Home.tsx +++ b/app/screens/Home.tsx @@ -3,7 +3,7 @@ import CoverArt from '@app/components/CoverArt' import GradientScrollView from '@app/components/GradientScrollView' import Header from '@app/components/Header' import NothingHere from '@app/components/NothingHere' -import { useActiveListRefresh2 } from '@app/hooks/server' +import { useActiveServerRefresh } from '@app/hooks/server' import { AlbumListItem } from '@app/models/music' import { selectMusic } from '@app/state/music' import { selectSettings } from '@app/state/settings' @@ -87,7 +87,7 @@ const Home = () => { const update = useStore(selectMusic.fetchHomeLists) const clear = useStore(selectMusic.clearHomeLists) - useActiveListRefresh2( + useActiveServerRefresh( useCallback(() => { clear() update() diff --git a/app/screens/LibraryAlbums.tsx b/app/screens/LibraryAlbums.tsx index c04315b..0d5879e 100644 --- a/app/screens/LibraryAlbums.tsx +++ b/app/screens/LibraryAlbums.tsx @@ -1,7 +1,7 @@ import { AlbumContextPressable } from '@app/components/ContextMenu' import CoverArt from '@app/components/CoverArt' import GradientFlatList from '@app/components/GradientFlatList' -import { useActiveListRefresh2 } from '@app/hooks/server' +import { useFetchPaginatedList } from '@app/hooks/list' import { Album, AlbumListItem } from '@app/models/music' import { selectMusic } from '@app/state/music' import { useStore } from '@app/state/store' @@ -48,31 +48,28 @@ const AlbumListRenderItem: React.FC<{ }> = ({ item }) => const AlbumsList = () => { - const list = useStore(selectMusic.albums) - const updating = useStore(selectMusic.albumsUpdating) - const updateList = useStore(selectMusic.fetchAlbums) - - useActiveListRefresh2(updateList) + const fetchAlbums = useStore(selectMusic.fetchAlbums) + const { list, refreshing, refresh, fetchNextPage } = useFetchPaginatedList(fetchAlbums, 60) const layout = useWindowDimensions() const size = layout.width / 3 - styles.itemWrapper.marginHorizontal * 2 const height = size + 36 - const albumsList = list.map(album => ({ album, size, height })) - return ( ({ album, size, height }))} renderItem={AlbumListRenderItem} keyExtractor={item => item.album.id} numColumns={3} removeClippedSubviews={true} - refreshing={updating} - onRefresh={updateList} + refreshing={refreshing} + onRefresh={refresh} overScrollMode="never" + onEndReached={fetchNextPage} + onEndReachedThreshold={1} getItemLayout={(_data, index) => ({ length: height, offset: height * Math.floor(index / 3), diff --git a/app/screens/LibraryArtists.tsx b/app/screens/LibraryArtists.tsx index 9dee807..ca06f01 100644 --- a/app/screens/LibraryArtists.tsx +++ b/app/screens/LibraryArtists.tsx @@ -1,6 +1,6 @@ import GradientFlatList from '@app/components/GradientFlatList' import ListItem from '@app/components/ListItem' -import { useActiveListRefresh2 } from '@app/hooks/server' +import { useFetchList } from '@app/hooks/list' import { Artist } from '@app/models/music' import { selectMusic } from '@app/state/music' import { useStore } from '@app/state/store' @@ -12,20 +12,17 @@ const ArtistRenderItem: React.FC<{ item: Artist }> = ({ item }) => ( ) const ArtistsList = () => { - const artists = useStore(selectMusic.artists) - const updating = useStore(selectMusic.artistsUpdating) - const updateArtists = useStore(selectMusic.fetchArtists) - - useActiveListRefresh2(updateArtists) + const fetchArtists = useStore(selectMusic.fetchArtists) + const { list, refreshing, refresh } = useFetchList(fetchArtists) return ( item.id} - onRefresh={updateArtists} - refreshing={updating} + onRefresh={refresh} + refreshing={refreshing} overScrollMode="never" /> ) diff --git a/app/screens/LibraryPlaylists.tsx b/app/screens/LibraryPlaylists.tsx index e6ff159..4f9449d 100644 --- a/app/screens/LibraryPlaylists.tsx +++ b/app/screens/LibraryPlaylists.tsx @@ -1,6 +1,6 @@ import GradientFlatList from '@app/components/GradientFlatList' import ListItem from '@app/components/ListItem' -import { useActiveListRefresh2 } from '@app/hooks/server' +import { useFetchList } from '@app/hooks/list' import { PlaylistListItem } from '@app/models/music' import { selectMusic } from '@app/state/music' import { useStore } from '@app/state/store' @@ -12,20 +12,17 @@ const PlaylistRenderItem: React.FC<{ item: PlaylistListItem }> = ({ item }) => ( ) const PlaylistsList = () => { - const playlists = useStore(selectMusic.playlists) - const updating = useStore(selectMusic.playlistsUpdating) - const updatePlaylists = useStore(selectMusic.fetchPlaylists) - - useActiveListRefresh2(updatePlaylists) + const fetchPlaylists = useStore(selectMusic.fetchPlaylists) + const { list, refreshing, refresh } = useFetchList(fetchPlaylists) return ( item.id} - onRefresh={updatePlaylists} - refreshing={updating} + onRefresh={refresh} + refreshing={refreshing} overScrollMode="never" /> ) diff --git a/app/screens/Search.tsx b/app/screens/Search.tsx index 967c154..0b85053 100644 --- a/app/screens/Search.tsx +++ b/app/screens/Search.tsx @@ -2,7 +2,7 @@ import GradientScrollView from '@app/components/GradientScrollView' import Header from '@app/components/Header' import ListItem from '@app/components/ListItem' import NothingHere from '@app/components/NothingHere' -import { useActiveListRefresh2 } from '@app/hooks/server' +import { useActiveServerRefresh } from '@app/hooks/server' import { ListableItem, SearchResults, Song } from '@app/models/music' import { selectMusic } from '@app/state/music' import { useStore } from '@app/state/store' @@ -68,7 +68,7 @@ const Search = () => { const updating = useStore(selectMusic.searchResultsUpdating) const results = useStore(selectMusic.searchResults) - useActiveListRefresh2( + useActiveServerRefresh( useCallback(() => { setText('') clearSearch() diff --git a/app/screens/Settings.tsx b/app/screens/Settings.tsx index fc74d22..28ef756 100644 --- a/app/screens/Settings.tsx +++ b/app/screens/Settings.tsx @@ -199,13 +199,6 @@ const SettingsContent = React.memo(() => { onPress={clear} buttonStyle="hollow" /> - {/*