mirror of
https://github.com/anultravioletaurora/Jellify.git
synced 2025-12-21 05:20:06 -06:00
@@ -41,9 +41,8 @@ export default function Albums({
|
||||
.filter((value, index, indices) => indices.indexOf(value) === index)
|
||||
}, [showAlphabeticalSelector, albumsInfiniteQuery.data])
|
||||
|
||||
const { mutate: alphabetSelectorMutate } = useAlphabetSelector(
|
||||
(letter) => (pendingLetterRef.current = letter.toUpperCase()),
|
||||
)
|
||||
const { mutateAsync: alphabetSelectorMutate, isPending: isAlphabetSelectorPending } =
|
||||
useAlphabetSelector((letter) => (pendingLetterRef.current = letter.toUpperCase()))
|
||||
|
||||
const ItemSeparatorComponent = useCallback(
|
||||
({ leadingItem, trailingItem }: { leadingItem: unknown; trailingItem: unknown }) =>
|
||||
@@ -126,7 +125,7 @@ export default function Albums({
|
||||
ItemSeparatorComponent={ItemSeparatorComponent}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={albumsInfiniteQuery.isFetching}
|
||||
refreshing={albumsInfiniteQuery.isFetching && !isAlphabetSelectorPending}
|
||||
onRefresh={albumsInfiniteQuery.refetch}
|
||||
tintColor={theme.primary.val}
|
||||
/>
|
||||
|
||||
@@ -46,7 +46,7 @@ export default function Artists({
|
||||
|
||||
const pendingLetterRef = useRef<string | null>(null)
|
||||
|
||||
const { mutate: alphabetSelectorMutate, isPending: isAlphabetSelectorPending } =
|
||||
const { mutateAsync: alphabetSelectorMutate, isPending: isAlphabetSelectorPending } =
|
||||
useAlphabetSelector((letter) => (pendingLetterRef.current = letter.toUpperCase()))
|
||||
|
||||
const stickyHeaderIndices = useMemo(() => {
|
||||
@@ -126,7 +126,7 @@ export default function Artists({
|
||||
data={artists}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={artistsInfiniteQuery.isFetching || isAlphabetSelectorPending}
|
||||
refreshing={artistsInfiniteQuery.isPending && !isAlphabetSelectorPending}
|
||||
onRefresh={() => artistsInfiniteQuery.refetch()}
|
||||
tintColor={theme.primary.val}
|
||||
/>
|
||||
|
||||
@@ -1,17 +1,10 @@
|
||||
import React, { RefObject, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { LayoutChangeEvent, View as RNView } from 'react-native'
|
||||
import { getToken, useTheme, View, YStack } from 'tamagui'
|
||||
import { LayoutChangeEvent, Platform, View as RNView } from 'react-native'
|
||||
import { getToken, Spinner, useTheme, View, YStack } from 'tamagui'
|
||||
import { Gesture, GestureDetector } from 'react-native-gesture-handler'
|
||||
import Animated, {
|
||||
useSharedValue,
|
||||
useAnimatedStyle,
|
||||
withTiming,
|
||||
Easing,
|
||||
withSpring,
|
||||
} from 'react-native-reanimated'
|
||||
import { runOnJS } from 'react-native-worklets'
|
||||
import Animated, { useSharedValue, useAnimatedStyle, withSpring } from 'react-native-reanimated'
|
||||
import { scheduleOnRN } from 'react-native-worklets'
|
||||
import { Text } from '../helpers/text'
|
||||
import { useSafeAreaFrame } from 'react-native-safe-area-context'
|
||||
import { UseInfiniteQueryResult, useMutation } from '@tanstack/react-query'
|
||||
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client'
|
||||
import useHapticFeedback from '../../../hooks/use-haptic-feedback'
|
||||
@@ -30,12 +23,13 @@ const alphabet = '#ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('')
|
||||
export default function AZScroller({
|
||||
onLetterSelect,
|
||||
}: {
|
||||
onLetterSelect: (letter: string) => void
|
||||
onLetterSelect: (letter: string) => Promise<void>
|
||||
}) {
|
||||
const { width } = useSafeAreaFrame()
|
||||
const theme = useTheme()
|
||||
const trigger = useHapticFeedback()
|
||||
|
||||
const [operationPending, setOperationPending] = useState<boolean>(false)
|
||||
|
||||
const overlayOpacity = useSharedValue(0)
|
||||
|
||||
const gesturePositionY = useSharedValue(0)
|
||||
@@ -79,7 +73,7 @@ export default function AZScroller({
|
||||
const letter = alphabet[index]
|
||||
selectedLetter.value = letter
|
||||
setOverlayLetter(letter)
|
||||
runOnJS(showOverlay)()
|
||||
scheduleOnRN(showOverlay)
|
||||
}
|
||||
})
|
||||
.onUpdate((e) => {
|
||||
@@ -90,13 +84,20 @@ export default function AZScroller({
|
||||
const letter = alphabet[index]
|
||||
selectedLetter.value = letter
|
||||
setOverlayLetter(letter)
|
||||
runOnJS(showOverlay)()
|
||||
scheduleOnRN(showOverlay)
|
||||
}
|
||||
})
|
||||
.onEnd(() => {
|
||||
runOnJS(hideOverlay)()
|
||||
if (selectedLetter.value) {
|
||||
runOnJS(onLetterSelect)(selectedLetter.value.toLowerCase())
|
||||
scheduleOnRN(async () => {
|
||||
setOperationPending(true)
|
||||
onLetterSelect(selectedLetter.value.toLowerCase()).then(() => {
|
||||
scheduleOnRN(hideOverlay)
|
||||
setOperationPending(false)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
scheduleOnRN(hideOverlay)
|
||||
}
|
||||
}),
|
||||
[onLetterSelect],
|
||||
@@ -114,13 +115,21 @@ export default function AZScroller({
|
||||
const letter = alphabet[index]
|
||||
selectedLetter.value = letter
|
||||
setOverlayLetter(letter)
|
||||
runOnJS(showOverlay)()
|
||||
scheduleOnRN(showOverlay)
|
||||
}
|
||||
})
|
||||
.onEnd(() => {
|
||||
runOnJS(hideOverlay)()
|
||||
if (selectedLetter.value)
|
||||
runOnJS(onLetterSelect)(selectedLetter.value.toLowerCase())
|
||||
if (selectedLetter.value) {
|
||||
scheduleOnRN(async () => {
|
||||
setOperationPending(true)
|
||||
onLetterSelect(selectedLetter.value.toLowerCase()).then(() => {
|
||||
scheduleOnRN(hideOverlay)
|
||||
setOperationPending(false)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
scheduleOnRN(hideOverlay)
|
||||
}
|
||||
}),
|
||||
[onLetterSelect],
|
||||
)
|
||||
@@ -155,6 +164,8 @@ export default function AZScroller({
|
||||
requestAnimationFrame(() => {
|
||||
alphabetSelectorRef.current?.measureInWindow((x, y, width, height) => {
|
||||
alphabetSelectorTopY.current = y
|
||||
|
||||
if (Platform.OS === 'android') alphabetSelectorTopY.current += 20
|
||||
})
|
||||
})
|
||||
}}
|
||||
@@ -200,17 +211,26 @@ export default function AZScroller({
|
||||
animatedOverlayStyle,
|
||||
]}
|
||||
>
|
||||
<Animated.Text
|
||||
style={{
|
||||
fontSize: getToken('$12'),
|
||||
textAlign: 'center',
|
||||
fontFamily: 'Figtree-Bold',
|
||||
color: theme.background.val,
|
||||
marginHorizontal: 'auto',
|
||||
}}
|
||||
>
|
||||
{overlayLetter}
|
||||
</Animated.Text>
|
||||
{operationPending ? (
|
||||
<Spinner
|
||||
size='large'
|
||||
color={theme.background.val}
|
||||
alignSelf='center'
|
||||
justify={'center'}
|
||||
/>
|
||||
) : (
|
||||
<Animated.Text
|
||||
style={{
|
||||
fontSize: getToken('$12'),
|
||||
textAlign: 'center',
|
||||
fontFamily: 'Figtree-Bold',
|
||||
color: theme.background.val,
|
||||
marginHorizontal: 'auto',
|
||||
}}
|
||||
>
|
||||
{overlayLetter}
|
||||
</Animated.Text>
|
||||
)}
|
||||
</Animated.View>
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -46,9 +46,8 @@ export default function Tracks({
|
||||
.filter((value, index, indices) => indices.indexOf(value) === index)
|
||||
}, [showAlphabeticalSelector, tracksInfiniteQuery.data])
|
||||
|
||||
const { mutate: alphabetSelectorMutate } = useAlphabetSelector(
|
||||
(letter) => (pendingLetterRef.current = letter.toUpperCase()),
|
||||
)
|
||||
const { mutateAsync: alphabetSelectorMutate, isPending: isAlphabetSelectorPending } =
|
||||
useAlphabetSelector((letter) => (pendingLetterRef.current = letter.toUpperCase()))
|
||||
|
||||
// Memoize the expensive tracks processing to prevent memory leaks
|
||||
const tracksToDisplay = React.useMemo(
|
||||
@@ -151,7 +150,7 @@ export default function Tracks({
|
||||
renderItem={renderItem}
|
||||
refreshControl={
|
||||
<RefreshControl
|
||||
refreshing={tracksInfiniteQuery.isFetching}
|
||||
refreshing={tracksInfiniteQuery.isFetching && !isAlphabetSelectorPending}
|
||||
onRefresh={tracksInfiniteQuery.refetch}
|
||||
tintColor={theme.primary.val}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user