Skip to content

Commit

Permalink
feat: 🎸 play or shuffle all artist tracks
Browse files Browse the repository at this point in the history
  • Loading branch information
eeston committed Mar 9, 2024
1 parent 2c36e86 commit c716c59
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 14 deletions.
22 changes: 22 additions & 0 deletions src/api/albums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,28 @@ export const useFetchAlbumSongs = (
return albumSongs;
};

export const useFetchArtistSongs = (api: Api, artistId: string) => {
// TODO: would be nicer to fetch by album so the cache can be shared with useFetchAlbumSongs
const user = useFetchUser(api);
const artistSongs = useQuery({
queryKey: ["artistSongs", artistId],
queryFn: async () => {
const result = await getItemsApi(api).getItems({
userId: user?.data?.Id,
parentId: artistId,
includeItemTypes: [BaseItemKind.Audio],
sortBy: [ItemSortBy.ProductionYear, ItemSortBy.SortName],
sortOrder: [SortOrder.Ascending],
recursive: true,
});
return result.data;
},
enabled: !!user.isSuccess,
});

return artistSongs;
};

export const useFetchMoreArtistAlbums = (
api: Api,
artistId: string,
Expand Down
9 changes: 4 additions & 5 deletions src/components/AlbumDetails/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,12 @@ import { AlbumCard } from "../AlbumCard";
import { Separator } from "../Separator";
import { Text } from "../Themed";

export const AlbumFooter = ({
albumDetails,
albumSongs,
}: {
type AlbumFooterProps = {
albumDetails?: BaseItemDto;
albumSongs?: BaseItemDto[];
}) => {
};

export const AlbumFooter = ({ albumDetails, albumSongs }: AlbumFooterProps) => {
const { styles } = useStyles(stylesheet);
const api = useApi((state) => state.api);
const moreAlbums = useFetchMoreArtistAlbums(
Expand Down
35 changes: 29 additions & 6 deletions src/components/ArtistDetails/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,43 @@
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client";
import { Image } from "expo-image";
import { View } from "react-native";
import { useStyles, createStyleSheet } from "react-native-unistyles";
import { createStyleSheet, useStyles } from "react-native-unistyles";

import { useFetchUser } from "../../api/user";
import { usePlayTracks } from "../../hooks/usePlayTracks";
import { useApi } from "../../store/useJelloAuth";
import { extractPrimaryHash } from "../../util/extractPrimaryHash";
import { generateTrackArtworkUrl } from "../../util/generateTrackArtworkUrl";
import { MusicButton } from "../MusicButton";
import { Text } from "../Themed";

type ArtistHeaderProps = {
artistDetails: BaseItemDto;
artistSongs: BaseItemDto[];
};

export const ArtistHeader = ({
artistDetails,
}: {
artistDetails: BaseItemDto;
}) => {
artistSongs,
}: ArtistHeaderProps) => {
const { styles } = useStyles(stylesheet);
const api = useApi((state) => state.api);
const playTracks = usePlayTracks();
const user = useFetchUser(api);

const onPressPlayArtist = () => {
playTracks({ tracks: artistSongs, api, userId: user.data?.Id });
};

const onPressShuffleArtist = () => {
playTracks({
tracks: artistSongs,
api,
userId: user.data?.Id,
shuffle: true,
});
};

return (
<View>
<View style={styles.headerImageContainer}>
Expand All @@ -28,8 +51,8 @@ export const ArtistHeader = ({
<Text style={styles.headerTitle}>{artistDetails?.Name}</Text>
</View>
<View style={styles.buttonContainer}>
{/* <MusicButton type="play" />
<MusicButton type="shuffle" /> */}
<MusicButton onPress={onPressPlayArtist} type="play" />
<MusicButton onPress={onPressShuffleArtist} type="shuffle" />
</View>
</View>
);
Expand Down
14 changes: 12 additions & 2 deletions src/navigation/screens/LibraryTab/ArtistDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { useCallback } from "react";
import { Animated, SafeAreaView, View } from "react-native";
import { createStyleSheet, useStyles } from "react-native-unistyles";

import { useFetchArtistSongs } from "../../../api/albums";
import {
useFetchArtistAlbums,
useFetchArtistDetails,
Expand All @@ -27,6 +28,8 @@ export const ArtistDetailsScreen = ({ route, navigation }: Props) => {
const api = useApi((state) => state.api);
const artistDetails = useFetchArtistDetails(api, artistId);
const artistAlbums = useFetchArtistAlbums(api, artistId);
const artistSongs = useFetchArtistSongs(api, artistId);

const headerHeight = useHeaderHeight();

const onPressArtistItem = useCallback(
Expand All @@ -51,15 +54,22 @@ export const ArtistDetailsScreen = ({ route, navigation }: Props) => {

const opacity = useFadeIn([artistDetails, artistAlbums]);

if (artistDetails.isPending || artistAlbums.isPending) {
if (
artistDetails.isPending ||
artistAlbums.isPending ||
artistSongs.isPending
) {
return <LoadingOverlay />;
}

return (
<SafeAreaView style={[styles.container, { marginTop: -headerHeight }]}>
<Animated.FlatList
ListHeaderComponent={
<ArtistHeader artistDetails={artistDetails.data} />
<ArtistHeader
artistDetails={artistDetails.data}
artistSongs={artistSongs.data?.Items}
/>
}
ListFooterComponent={<View style={styles.listFooterContainer} />}
data={artistAlbums.data?.Items}
Expand Down
1 change: 0 additions & 1 deletion src/navigation/screens/Modals/NowPlaying.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { Slider } from "react-native-awesome-slider";
import {
ContextMenuButton,
MenuActionConfig,
OnPressMenuItemEvent,
} from "react-native-ios-context-menu";
import LinearGradient from "react-native-linear-gradient";
import { useDerivedValue, useSharedValue } from "react-native-reanimated";
Expand Down

0 comments on commit c716c59

Please sign in to comment.