diff --git a/.github/workflows/publish-ota-update-pr.yml b/.github/workflows/publish-ota-update-pr.yml index 29b7d8ff..d1ad09fb 100644 --- a/.github/workflows/publish-ota-update-pr.yml +++ b/.github/workflows/publish-ota-update-pr.yml @@ -13,6 +13,8 @@ jobs: steps: - name: 🛒 Checkout uses: actions/checkout@v6 + with: + token: ${{ secrets.SIGNING_REPO_PAT }} - name: 🖥 Setup Bun uses: oven-sh/setup-bun@v2 @@ -29,3 +31,6 @@ jobs: - name: 🤖 Publish Update run: bun run sendOTA:PR ${{ github.event.pull_request.number }} + env: + SIGNING_REPO_PAT: ${{ secrets.SIGNING_REPO_PAT }} + diff --git a/src/api/queries/media/index.ts b/src/api/queries/media/index.ts index adceddd7..13c248f8 100644 --- a/src/api/queries/media/index.ts +++ b/src/api/queries/media/index.ts @@ -7,7 +7,7 @@ import { fetchMediaInfo } from './utils' import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client' import MediaInfoQueryKey from './keys' import { useApi } from '../../../stores' -import { ONE_DAY } from '../../../constants/query-client' +import { ONE_DAY, ONE_HOUR } from '../../../constants/query-client' /** * A React hook that will retrieve the latest media info @@ -32,8 +32,8 @@ const useStreamedMediaInfo = (itemId: string | null | undefined) => { queryKey: MediaInfoQueryKey({ api, deviceProfile, itemId }), queryFn: () => fetchMediaInfo(api, deviceProfile, itemId), enabled: Boolean(api && deviceProfile && itemId), - staleTime: ONE_DAY, // Only refetch when the user's device profile changes - gcTime: ONE_DAY, + staleTime: Infinity, // Only refetch when the user's device profile changes + gcTime: Infinity, }) } @@ -62,7 +62,7 @@ export const useDownloadedMediaInfo = (itemId: string | null | undefined) => { queryKey: MediaInfoQueryKey({ api, deviceProfile, itemId }), queryFn: () => fetchMediaInfo(api, deviceProfile, itemId), enabled: Boolean(api && deviceProfile && itemId), - staleTime: ONE_DAY, // Only refetch when the user's device profile changes - gcTime: ONE_DAY, + staleTime: ONE_HOUR * 6, // Only refetch when the user's device profile changes + gcTime: ONE_HOUR * 6, }) } diff --git a/src/components/Album/footer.tsx b/src/components/Album/footer.tsx index 81ad7a35..4d67332c 100644 --- a/src/components/Album/footer.tsx +++ b/src/components/Album/footer.tsx @@ -6,7 +6,7 @@ import { useNavigation } from '@react-navigation/native' import { NativeStackNavigationProp } from '@react-navigation/native-stack' import { FlashList } from '@shopify/flash-list' import { YStack, H5 } from 'tamagui' -import { ItemCard } from '../Global/components/item-card' +import ItemCard from '../Global/components/item-card' export default function AlbumTrackListFooter({ album }: { album: BaseItemDto }): React.JSX.Element { const navigation = diff --git a/src/components/Album/index.tsx b/src/components/Album/index.tsx index 61e343c3..cf0a78a5 100644 --- a/src/components/Album/index.tsx +++ b/src/components/Album/index.tsx @@ -18,7 +18,7 @@ import useAddToPendingDownloads, { useIsDownloading } from '../../stores/network import { useIsDownloaded } from '../../api/queries/download' import AlbumTrackListFooter from './footer' import AlbumTrackListHeader from './header' -import Animated, { FadeInUp, FadeOutDown, LinearTransition } from 'react-native-reanimated' +import Animated, { FadeIn, FadeOutDown, LinearTransition } from 'react-native-reanimated' import { useStorageContext } from '../../providers/Storage' /** @@ -69,7 +69,7 @@ export function Album({ album }: { album: BaseItemDto }): React.JSX.Element { {albumTrackList && (isDownloaded ? ( @@ -83,7 +83,7 @@ export function Album({ album }: { album: BaseItemDto }): React.JSX.Element { ) : ( diff --git a/src/components/Artist/OverviewTab.tsx b/src/components/Artist/OverviewTab.tsx index 0a2cd675..bb1753e9 100644 --- a/src/components/Artist/OverviewTab.tsx +++ b/src/components/Artist/OverviewTab.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useMemo } from 'react' +import React from 'react' import { useArtistContext } from '../../providers/Artist' import { NativeStackNavigationProp } from '@react-navigation/native-stack' import { BaseStackParamList } from '@/src/screens/types' @@ -16,43 +16,42 @@ export default function ArtistOverviewTab({ }): React.JSX.Element { const { featuredOn, artist, albums } = useArtistContext() - const sections: SectionListData[] = useMemo(() => { - return [ - { - title: 'Albums', - data: albums?.filter(({ ChildCount }) => (ChildCount ?? 0) > 6) ?? [], - }, - { - title: 'EPs', - data: - albums?.filter( - ({ ChildCount }) => (ChildCount ?? 0) <= 6 && (ChildCount ?? 0) >= 3, - ) ?? [], - }, - { - title: 'Singles', - data: albums?.filter(({ ChildCount }) => (ChildCount ?? 0) === 1) ?? [], - }, - { - title: '', - data: albums?.filter(({ ChildCount }) => typeof ChildCount !== 'number') ?? [], - }, - { - title: 'Featured On', - data: featuredOn ?? [], - }, - ] - }, [artist, albums?.map(({ Id }) => Id)]) + const sections: SectionListData[] = [ + { + title: 'Albums', + data: albums?.filter(({ ChildCount }) => (ChildCount ?? 0) > 6) ?? [], + }, + { + title: 'EPs', + data: + albums?.filter( + ({ ChildCount }) => (ChildCount ?? 0) <= 6 && (ChildCount ?? 0) >= 3, + ) ?? [], + }, + { + title: 'Singles', + data: albums?.filter(({ ChildCount }) => (ChildCount ?? 0) === 1) ?? [], + }, + { + title: '', + data: albums?.filter(({ ChildCount }) => typeof ChildCount !== 'number') ?? [], + }, + { + title: 'Featured On', + data: featuredOn ?? [], + }, + ] - const renderSectionHeader = useCallback( - ({ section }: { section: SectionListData }) => - section.data.length > 0 ? ( - - {section.title} - - ) : null, - [], - ) + const renderSectionHeader = ({ + section, + }: { + section: SectionListData + }) => + section.data.length > 0 ? ( + + {section.title} + + ) : null return ( void - sortBy: ItemSortBy - setSortBy: (sortBy: ItemSortBy) => void - sortOrder: SortOrder - setSortOrder: (sortOrder: SortOrder) => void -} - -export default function ArtistTabBar({ - isFavorites, - setIsFavorites, - sortBy, - setSortBy, - sortOrder, - setSortOrder, - ...props -}: ArtistTabBarProps) { - const trigger = useHapticFeedback() - const insets = useSafeAreaInsets() - - return ( - - - - {props.state.routes[props.state.index].name === 'Tracks' && ( - - { - trigger('impactLight') - setIsFavorites(!isFavorites) - }} - alignItems={'center'} - justifyContent={'center'} - > - - - - {isFavorites ? 'Favorites' : 'All'} - - - - { - trigger('impactLight') - if (sortBy === ItemSortBy.DateCreated) { - setSortBy(ItemSortBy.SortName) - setSortOrder(SortOrder.Ascending) - } else { - setSortBy(ItemSortBy.DateCreated) - setSortOrder(SortOrder.Descending) - } - }} - alignItems={'center'} - justifyContent={'center'} - > - {' '} - - {sortBy === ItemSortBy.DateCreated ? 'Date Added' : 'A-Z'} - - - - )} - - ) -} diff --git a/src/components/Artist/header.tsx b/src/components/Artist/header.tsx index 56981835..b64d772e 100644 --- a/src/components/Artist/header.tsx +++ b/src/components/Artist/header.tsx @@ -1,5 +1,5 @@ import { ImageType } from '@jellyfin/sdk/lib/generated-client' -import { XStack, YStack } from 'tamagui' +import { Text, XStack, YStack } from 'tamagui' import ItemImage from '../Global/components/image' import { useSafeAreaFrame } from 'react-native-safe-area-context' import { H5 } from '../Global/helpers/text' @@ -16,6 +16,8 @@ import { QueuingType } from '../../enums/queuing-type' import { useNetworkStatus } from '../../stores/network' import useStreamingDeviceProfile from '../../stores/device-profile' import { useApi } from '../../stores' +import Icon from '../Global/components/icon' +import useTracks from '../../api/queries/track' export default function ArtistHeader(): React.JSX.Element { const { width } = useSafeAreaFrame() @@ -62,6 +64,8 @@ export default function ArtistHeader(): React.JSX.Element { } } + const [trackPageParams, tracksInfiniteQuery] = useTracks(artist.Id) + return ( - +
@@ -90,10 +94,31 @@ export default function ArtistHeader(): React.JSX.Element { - {/* playArtist(true)} /> */} - + playArtist(true)} + /> + playArtist(false)} /> + + + navigation.push('Tracks', { + tracksInfiniteQuery, + }) + } + > + {`View Tracks`} + + + ) diff --git a/src/components/Artist/index.tsx b/src/components/Artist/index.tsx index ee24177c..4419e16e 100644 --- a/src/components/Artist/index.tsx +++ b/src/components/Artist/index.tsx @@ -1,71 +1,12 @@ -import React, { useState } from 'react' +import React from 'react' import { NativeStackNavigationProp } from '@react-navigation/native-stack' import { BaseStackParamList } from '@/src/screens/types' -import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs' import ArtistOverviewTab from './OverviewTab' -import ArtistTracksTab from './TracksTab' -import ArtistTabBar from './TabBar' -import { ItemSortBy, SortOrder } from '@jellyfin/sdk/lib/generated-client' -import { getTokenValue, useTheme } from 'tamagui' - -const Tab = createMaterialTopTabNavigator() export default function ArtistNavigation({ navigation, }: { navigation: NativeStackNavigationProp }): React.JSX.Element { - const [isFavorites, setIsFavorites] = useState(false) - const [sortBy, setSortBy] = useState(ItemSortBy.SortName) - const [sortOrder, setSortOrder] = useState(SortOrder.Ascending) - - const theme = useTheme() - - return ( - ( - - )} - screenOptions={{ - swipeEnabled: false, - tabBarIndicatorStyle: { - borderColor: theme.background.val, - borderBottomWidth: getTokenValue('$2'), - }, - tabBarActiveTintColor: theme.background.val, - tabBarInactiveTintColor: theme.background50.val, - tabBarStyle: { - backgroundColor: theme.primary.val, - }, - tabBarLabelStyle: { - fontSize: 16, - fontFamily: 'Figtree-Bold', - }, - tabBarPressOpacity: 0.5, - lazy: true, // Enable lazy loading to prevent all tabs from mounting simultaneously - }} - > - - {() => } - - - {() => ( - - )} - - - ) + return } diff --git a/src/components/Artist/similar.tsx b/src/components/Artist/similar.tsx index e6dcbfad..7a259565 100644 --- a/src/components/Artist/similar.tsx +++ b/src/components/Artist/similar.tsx @@ -15,7 +15,7 @@ export default function SimilarArtists(): React.JSX.Element { return ( {`Similar to ${artist.Name ?? 'Unknown Artist'}`} diff --git a/src/components/Discover/helpers/just-added.tsx b/src/components/Discover/helpers/just-added.tsx index 11e9926f..aae22d6e 100644 --- a/src/components/Discover/helpers/just-added.tsx +++ b/src/components/Discover/helpers/just-added.tsx @@ -1,6 +1,6 @@ import { NativeStackNavigationProp } from '@react-navigation/native-stack' import HorizontalCardList from '../../../components/Global/components/horizontal-list' -import { ItemCard } from '../../../components/Global/components/item-card' +import ItemCard from '../../../components/Global/components/item-card' import { H5, View, XStack } from 'tamagui' import Icon from '../../Global/components/icon' import { useNavigation } from '@react-navigation/native' diff --git a/src/components/Discover/helpers/public-playlists.tsx b/src/components/Discover/helpers/public-playlists.tsx index 2504b6ee..78d2bf92 100644 --- a/src/components/Discover/helpers/public-playlists.tsx +++ b/src/components/Discover/helpers/public-playlists.tsx @@ -2,7 +2,7 @@ import { H5, XStack } from 'tamagui' import { NativeStackNavigationProp } from '@react-navigation/native-stack' import Icon from '../../Global/components/icon' import HorizontalCardList from '../../Global/components/horizontal-list' -import { ItemCard } from '../../Global/components/item-card' +import ItemCard from '../../Global/components/item-card' import { useSafeAreaFrame } from 'react-native-safe-area-context' import { useNavigation } from '@react-navigation/native' import DiscoverStackParamList from '../../../screens/Discover/types' diff --git a/src/components/Discover/helpers/suggested-artists.tsx b/src/components/Discover/helpers/suggested-artists.tsx index 06b363f4..a248a3b8 100644 --- a/src/components/Discover/helpers/suggested-artists.tsx +++ b/src/components/Discover/helpers/suggested-artists.tsx @@ -1,7 +1,7 @@ import { H5, View, XStack } from 'tamagui' import Icon from '../../Global/components/icon' import HorizontalCardList from '../../Global/components/horizontal-list' -import { ItemCard } from '../../Global/components/item-card' +import ItemCard from '../../Global/components/item-card' import { NativeStackNavigationProp } from '@react-navigation/native-stack' import { useNavigation } from '@react-navigation/native' import DiscoverStackParamList from '../../../screens/Discover/types' diff --git a/src/components/Global/components/icon.tsx b/src/components/Global/components/icon.tsx index 1bbe6417..757251ca 100644 --- a/src/components/Global/components/icon.tsx +++ b/src/components/Global/components/icon.tsx @@ -57,8 +57,6 @@ export default function Icon({ onPress={onPress} onPressIn={onPressIn} hitSlop={getTokenValue('$2.5')} - width={size + getToken('$0.5')} - height={size + getToken('$0.5')} flex={flex} > (onPress ? { scale: 0.925 } : undefined), [onPress]) + const hoverStyle = onPress ? { scale: 0.925 } : undefined - const pressStyle = useMemo(() => (onPress ? { scale: 0.875 } : undefined), [onPress]) + const pressStyle = onPress ? { scale: 0.875 } : undefined - const handlePressIn = useCallback( - () => (item.Type !== 'Audio' ? warmContext(item) : undefined), - [item.Id, warmContext], - ) + const handlePressIn = () => (item.Type !== 'Audio' ? warmContext(item) : undefined) - const background = useMemo( - () => ( - - - - ), - [item.Id, squared], + const background = ( + + + ) return ( @@ -88,62 +82,41 @@ function ItemCardComponent({ ) } -const ItemCardComponentCaption = memo( - function ItemCardComponentCaption({ - size, - captionAlign = 'center', - caption, - subCaption, - }: { - size: string | number - captionAlign: 'center' | 'left' | 'right' - caption?: string | null | undefined - subCaption?: string | null | undefined - }): React.JSX.Element | null { - if (!caption) return null +function ItemCardComponentCaption({ + size, + captionAlign = 'center', + caption, + subCaption, +}: { + size: string | number + captionAlign: 'center' | 'left' | 'right' + caption?: string | null | undefined + subCaption?: string | null | undefined +}): React.JSX.Element | null { + if (!caption) return null - return ( - + return ( + + + {caption} + + + {subCaption && ( - {caption} + {subCaption} - - {subCaption && ( - - {subCaption} - - )} - - ) - }, - (prevProps, nextProps) => - prevProps.size === nextProps.size && - prevProps.captionAlign === nextProps.captionAlign && - prevProps.caption === nextProps.caption && - prevProps.subCaption === nextProps.subCaption, -) - -export const ItemCard = React.memo( - ItemCardComponent, - (a, b) => - a.item.Id === b.item.Id && - a.item.Type === b.item.Type && - a.caption === b.caption && - a.subCaption === b.subCaption && - a.squared === b.squared && - a.size === b.size && - a.testId === b.testId && - !!a.onPress === !!b.onPress && - a.captionAlign === b.captionAlign, -) + )} + + ) +} diff --git a/src/components/Home/helpers/frequent-artists.tsx b/src/components/Home/helpers/frequent-artists.tsx index 6f9e3d51..251c15ea 100644 --- a/src/components/Home/helpers/frequent-artists.tsx +++ b/src/components/Home/helpers/frequent-artists.tsx @@ -1,7 +1,7 @@ import HorizontalCardList from '../../../components/Global/components/horizontal-list' import { NativeStackNavigationProp } from '@react-navigation/native-stack' import React, { useCallback } from 'react' -import { ItemCard } from '../../../components/Global/components/item-card' +import ItemCard from '../../../components/Global/components/item-card' import { H5, XStack } from 'tamagui' import Icon from '../../Global/components/icon' import { useDisplayContext } from '../../../providers/Display/display-provider' diff --git a/src/components/Home/helpers/frequent-tracks.tsx b/src/components/Home/helpers/frequent-tracks.tsx index feafa02c..f379a796 100644 --- a/src/components/Home/helpers/frequent-tracks.tsx +++ b/src/components/Home/helpers/frequent-tracks.tsx @@ -1,7 +1,7 @@ import { NativeStackNavigationProp } from '@react-navigation/native-stack' import { H5, XStack } from 'tamagui' import HorizontalCardList from '../../../components/Global/components/horizontal-list' -import { ItemCard } from '../../../components/Global/components/item-card' +import ItemCard from '../../../components/Global/components/item-card' import { QueuingType } from '../../../enums/queuing-type' import Icon from '../../Global/components/icon' import { useLoadNewQueue } from '../../../providers/Player/hooks/mutations' diff --git a/src/components/Home/helpers/recent-artists.tsx b/src/components/Home/helpers/recent-artists.tsx index f77ef719..68e54101 100644 --- a/src/components/Home/helpers/recent-artists.tsx +++ b/src/components/Home/helpers/recent-artists.tsx @@ -1,7 +1,7 @@ import React, { useCallback } from 'react' import { H5, View, XStack } from 'tamagui' import { RootStackParamList } from '../../../screens/types' -import { ItemCard } from '../../Global/components/item-card' +import ItemCard from '../../Global/components/item-card' import { NativeStackNavigationProp } from '@react-navigation/native-stack' import HorizontalCardList from '../../../components/Global/components/horizontal-list' import Icon from '../../Global/components/icon' diff --git a/src/components/Home/helpers/recently-played.tsx b/src/components/Home/helpers/recently-played.tsx index 39a4a7a1..41124f85 100644 --- a/src/components/Home/helpers/recently-played.tsx +++ b/src/components/Home/helpers/recently-played.tsx @@ -1,6 +1,6 @@ import React from 'react' import { H5, XStack } from 'tamagui' -import { ItemCard } from '../../Global/components/item-card' +import ItemCard from '../../Global/components/item-card' import { RootStackParamList } from '../../../screens/types' import { NativeStackNavigationProp } from '@react-navigation/native-stack' import { QueuingType } from '../../../enums/queuing-type' diff --git a/src/components/Player/queue.tsx b/src/components/Player/queue.tsx index 3d062807..42451c1f 100644 --- a/src/components/Player/queue.tsx +++ b/src/components/Player/queue.tsx @@ -2,8 +2,8 @@ import Icon from '../Global/components/icon' import Track from '../Global/components/track' import { RootStackParamList } from '../../screens/types' import { NativeStackNavigationProp } from '@react-navigation/native-stack' -import { ScrollView, XStack } from 'tamagui' -import { useLayoutEffect, useCallback, useState } from 'react' +import { ScrollView, Text, XStack } from 'tamagui' +import { useLayoutEffect, useState } from 'react' import JellifyTrack from '../../types/JellifyTrack' import { useRemoveFromQueue, @@ -13,8 +13,9 @@ import { } from '../../providers/Player/hooks/mutations' import { usePlayerQueueStore, useQueueRef } from '../../stores/player/queue' import Sortable from 'react-native-sortables' -import { RenderItemInfo } from 'react-native-sortables/dist/typescript/types' +import { OrderChangeParams, RenderItemInfo } from 'react-native-sortables/dist/typescript/types' import { useReducedHapticsSetting } from '../../stores/settings/app' +import uuid from 'react-native-uuid' export default function Queue({ navigation, @@ -35,51 +36,62 @@ export default function Queue({ useLayoutEffect(() => { navigation.setOptions({ headerRight: () => { - return + return ( + + Clear Upcoming + { + await removeUpcomingTracks() + setQueue(usePlayerQueueStore.getState().queue) + }} + /> + + ) }, }) }, [navigation, removeUpcomingTracks]) - const keyExtractor = useCallback((item: JellifyTrack) => `${item.item.Id}`, []) + const keyExtractor = (item: JellifyTrack) => item.item.Id ?? uuid.v4() // Memoize renderItem function for better performance - const renderItem = useCallback( - ({ item: queueItem, index }: RenderItemInfo) => ( - - - - + const renderItem = ({ item: queueItem, index }: RenderItemInfo) => ( + + + + - skip(index)} - style={{ - flexGrow: 1, - }} - > - - + skip(index)} + style={{ + flexGrow: 1, + }} + > + + - { - setQueue(queue.filter(({ item }) => item.Id !== queueItem.item.Id)) - await removeFromQueue(index) - }} - > - - - - ), - [queueRef, skip, removeFromQueue], + { + setQueue(queue.filter(({ item }) => item.Id !== queueItem.item.Id)) + await removeFromQueue(index) + }} + > + + + ) + const handleReorder = async ({ fromIndex, toIndex }: OrderChangeParams) => + await reorderQueue({ fromIndex, toIndex }) + return ( { - setQueue(data) - }} + onOrderChange={handleReorder} + onDragEnd={({ data }) => setQueue(data)} overDrag='vertical' customHandle hapticsEnabled={!reducedHaptics} diff --git a/src/components/Playlist/index.tsx b/src/components/Playlist/index.tsx index 941d5373..19180bbd 100644 --- a/src/components/Playlist/index.tsx +++ b/src/components/Playlist/index.tsx @@ -151,69 +151,72 @@ export default function Playlist({ const handleDownload = () => addToDownloadQueue(playlistTracks ?? []) + const editModeActions = ( + + + { + navigationRef.dispatch( + StackActions.push('DeletePlaylist', { + playlist, + onDelete: navigation.goBack, + }), + ) + }} + /> + + + + + ) + + const downloadActions = ( + + {playlistTracks && + (isDownloaded ? ( + + + + ) : playlistDownloadPending ? ( + + ) : ( + + + + ))} + + ) + useLayoutEffect(() => { navigation.setOptions({ headerRight: () => ( - {playlistTracks && - (isDownloaded ? ( - - - - ) : playlistDownloadPending ? ( - - ) : ( - - - - ))} - {canEdit && - (editing ? ( - - - { - navigationRef.dispatch( - StackActions.push('DeletePlaylist', { - playlist, - onDelete: navigation.goBack, - }), - ) - }} - /> - - - - - ) : isUpdating || isPreparingEditMode ? ( - - ) : ( + {playlistTracks && !editing && downloadActions} + {canEdit && ( + + {editing ? ( + editModeActions + ) : isUpdating || isPreparingEditMode ? ( + + ) : null} - ))} - ) + + )} ), }) diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index cd547534..27b510cf 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -7,12 +7,11 @@ import { QueryKeys } from '../../enums/query-keys' import { fetchSearchResults } from '../../api/queries/search' import { useQuery } from '@tanstack/react-query' import { FlatList } from 'react-native' -import { fetchSearchSuggestions } from '../../api/queries/suggestions/utils/suggestions' import { getToken, H3, Separator, Spinner, YStack } from 'tamagui' import Suggestions from './suggestions' import { isEmpty } from 'lodash' import HorizontalCardList from '../Global/components/horizontal-list' -import { ItemCard } from '../Global/components/item-card' +import ItemCard from '../Global/components/item-card' import SearchParamList from '../../screens/Search/types' import { closeAllSwipeableRows } from '../Global/components/swipeable-row-registry' import { useApi, useJellifyLibrary, useJellifyUser } from '../../stores' diff --git a/src/components/Search/suggestions.tsx b/src/components/Search/suggestions.tsx index 26554e8e..5f98ffd2 100644 --- a/src/components/Search/suggestions.tsx +++ b/src/components/Search/suggestions.tsx @@ -1,7 +1,7 @@ import ItemRow from '../Global/components/item-row' import { Text } from '../Global/helpers/text' import { H5, Separator, Spinner, YStack } from 'tamagui' -import { ItemCard } from '../Global/components/item-card' +import ItemCard from '../Global/components/item-card' import HorizontalCardList from '../Global/components/horizontal-list' import { FlashList } from '@shopify/flash-list' import SearchParamList from '../../screens/Search/types' diff --git a/src/configs/axios.config.ts b/src/configs/axios.config.ts index 052356f2..a642a181 100644 --- a/src/configs/axios.config.ts +++ b/src/configs/axios.config.ts @@ -1,4 +1,29 @@ -import axios from 'axios' +import axios, { AxiosAdapter } from 'axios' +import { fetch } from 'react-native-nitro-fetch' + +const nitroAxiosAdapter: AxiosAdapter = async (config) => { + const response = await fetch(config.url!, { + method: config.method?.toUpperCase(), + headers: config.headers, + body: config.data, + }) + + const data = await response.json() + + const headers: Record = {} + response.headers.forEach((value, key) => { + headers[key] = value + }) + + return { + data, + status: response.status, + statusText: response.statusText, + headers, + config, + request: null, + } +} /** * The Axios instance for making HTTP requests. @@ -7,6 +32,7 @@ import axios from 'axios' */ const AXIOS_INSTANCE = axios.create({ timeout: 60000, + adapter: nitroAxiosAdapter, }) export default AXIOS_INSTANCE diff --git a/src/providers/Player/hooks/mutations.ts b/src/providers/Player/hooks/mutations.ts index 2aff2a62..6c45d705 100644 --- a/src/providers/Player/hooks/mutations.ts +++ b/src/providers/Player/hooks/mutations.ts @@ -226,9 +226,11 @@ export const useRemoveFromQueue = () => { return async (index: number) => { trigger('impactMedium') TrackPlayer.remove([index]) - const newQueue = await TrackPlayer.getQueue() - usePlayerQueueStore.getState().setQueue(newQueue as JellifyTrack[]) + const prevQueue = usePlayerQueueStore.getState().queue + const newQueue = prevQueue.filter((_, i) => i !== index) + + usePlayerQueueStore.getState().setQueue(newQueue) } } @@ -244,9 +246,15 @@ export const useRemoveUpcomingTracks = () => { export const useReorderQueue = () => { return async ({ fromIndex, toIndex }: QueueOrderMutation) => { await TrackPlayer.move(fromIndex, toIndex) - const newQueue = await TrackPlayer.getQueue() - usePlayerQueueStore.getState().setQueue(newQueue as JellifyTrack[]) + const queue = usePlayerQueueStore.getState().queue + + const itemToMove = queue[fromIndex] + const newQueue = [...queue] + newQueue.splice(fromIndex, 1) + newQueue.splice(toIndex, 0, itemToMove) + + usePlayerQueueStore.getState().setQueue(newQueue) } } diff --git a/src/screens/Artist/index.tsx b/src/screens/Artist/index.tsx index 55ee95f7..ba9d9287 100644 --- a/src/screens/Artist/index.tsx +++ b/src/screens/Artist/index.tsx @@ -1,10 +1,10 @@ +import ArtistNavigation from '../../components/Artist' +import { ArtistProvider } from '../../providers/Artist' import { RouteProp } from '@react-navigation/native' import { NativeStackNavigationProp } from '@react-navigation/native-stack' import { BaseStackParamList } from '../types' -import { ArtistProvider } from '../../providers/Artist' -import ArtistNavigation from '../../components/Artist' -export function ArtistScreen({ +export default function ArtistScreen({ route, navigation, }: { diff --git a/src/screens/Discover/index.tsx b/src/screens/Discover/index.tsx index a6b4b437..8ea59bc2 100644 --- a/src/screens/Discover/index.tsx +++ b/src/screens/Discover/index.tsx @@ -1,7 +1,7 @@ import { createNativeStackNavigator } from '@react-navigation/native-stack' import Index from '../../components/Discover/component' import AlbumScreen from '../Album' -import { ArtistScreen } from '../Artist' +import ArtistScreen from '../Artist' import { getTokenValue, useTheme } from 'tamagui' import RecentlyAdded from './albums' import PublicPlaylists from './playlists' @@ -10,6 +10,7 @@ import SuggestedArtists from './artists' import DiscoverStackParamList from './types' import InstantMix from '../../components/InstantMix/component' import { getItemName } from '../../utils/text' +import TracksScreen from '../Tracks' export const DiscoverStack = createNativeStackNavigator() @@ -101,6 +102,8 @@ export function Discover(): React.JSX.Element { headerTitle: `${getItemName(route.params.item)} Mix`, })} /> + + ) } diff --git a/src/screens/Home/index.tsx b/src/screens/Home/index.tsx index f5260527..a1de9c7f 100644 --- a/src/screens/Home/index.tsx +++ b/src/screens/Home/index.tsx @@ -2,7 +2,7 @@ import _ from 'lodash' import { createNativeStackNavigator } from '@react-navigation/native-stack' import { PlaylistScreen } from '../Playlist' import { Home as HomeComponent } from '../../components/Home' -import { ArtistScreen } from '../Artist' +import ArtistScreen from '../Artist' import { getTokenValue, useTheme } from 'tamagui' import HomeArtistsScreen from './artists' import HomeTracksScreen from './tracks' @@ -10,6 +10,7 @@ import AlbumScreen from '../Album' import HomeStackParamList from './types' import InstantMix from '../../components/InstantMix/component' import { getItemName } from '../../utils/text' +import TracksScreen from '../Tracks' const HomeStack = createNativeStackNavigator() @@ -99,6 +100,8 @@ export default function Home(): React.JSX.Element { headerTitle: `${getItemName(route.params.item)} Mix`, })} /> + + ) diff --git a/src/screens/Library/index.tsx b/src/screens/Library/index.tsx index e3672fda..d394969d 100644 --- a/src/screens/Library/index.tsx +++ b/src/screens/Library/index.tsx @@ -2,7 +2,7 @@ import React from 'react' import Library from '../../components/Library/component' import { PlaylistScreen } from '../Playlist' import AddPlaylist from './add-playlist' -import { ArtistScreen } from '../Artist' +import ArtistScreen from '../Artist' import { useTheme } from 'tamagui' import { createNativeStackNavigator } from '@react-navigation/native-stack' import AlbumScreen from '../Album' @@ -10,6 +10,7 @@ import LibraryStackParamList from './types' import InstantMix from '../../components/InstantMix/component' import { getItemName } from '../../utils/text' import { Platform } from 'react-native' +import TracksScreen from '../Tracks' const LibraryStack = createNativeStackNavigator() @@ -81,6 +82,8 @@ export default function LibraryScreen(): React.JSX.Element { sheetAllowedDetents: Platform.OS === 'ios' ? 'fitToContents' : [0.5], }} /> + + ) } diff --git a/src/screens/Search/index.tsx b/src/screens/Search/index.tsx index a0d69e23..b4bc0b64 100644 --- a/src/screens/Search/index.tsx +++ b/src/screens/Search/index.tsx @@ -1,5 +1,5 @@ import { createNativeStackNavigator } from '@react-navigation/native-stack' -import { ArtistScreen } from '../Artist' +import ArtistScreen from '../Artist' import AlbumScreen from '../Album' import { PlaylistScreen } from '../Playlist' import { getTokenValue, useTheme } from 'tamagui' @@ -7,6 +7,7 @@ import Search from '../../components/Search' import SearchParamList from './types' import InstantMix from '../../components/InstantMix/component' import { getItemName } from '../../utils/text' +import TracksScreen from '../Tracks' const Stack = createNativeStackNavigator() @@ -68,6 +69,8 @@ export default function SearchStack(): React.JSX.Element { headerTitle: `${getItemName(route.params.item)} Mix`, })} /> + + ) } diff --git a/src/screens/types.d.ts b/src/screens/types.d.ts index f0291f32..3ce40154 100644 --- a/src/screens/types.d.ts +++ b/src/screens/types.d.ts @@ -36,7 +36,7 @@ export type BaseStackParamList = { } Tracks: { - tracksInfiniteQuery: UseInfiniteQueryResult + tracksInfiniteQuery: UseInfiniteQueryResult<(string | number | BaseItemDto)[], Error> } }