From 425a100ed97f5bdca47deb35e7673786d6053ed8 Mon Sep 17 00:00:00 2001
From: Violet Caulfield <42452695+anultravioletaurora@users.noreply.github.com>
Date: Sat, 8 Nov 2025 02:46:01 -0600
Subject: [PATCH] styling fixes
make buttons animate consistently
styling and animations for the library switcher
fix issue where the second line of the toast message wasn't using the figtree font
---
src/api/mutations/authentication/index.ts | 4 +-
src/components/AddToPlaylist/index.tsx | 28 +++++-
src/components/Context/index.tsx | 61 ++++++------
src/components/Global/components/icon.tsx | 2 +-
src/components/Global/components/image.tsx | 42 ++++----
.../Global/components/library-selector.tsx | 99 +++++++++++--------
src/components/Global/helpers/button.tsx | 12 ++-
src/components/Player/index.tsx | 2 +-
.../Settings/components/preferences-tab.tsx | 7 +-
src/components/jellify.tsx | 2 +-
src/{constants => configs}/toast.config.ts | 12 ++-
tamagui.config.ts | 9 --
12 files changed, 165 insertions(+), 115 deletions(-)
rename src/{constants => configs}/toast.config.ts (78%)
diff --git a/src/api/mutations/authentication/index.ts b/src/api/mutations/authentication/index.ts
index bb2f539b..a7bd712d 100644
--- a/src/api/mutations/authentication/index.ts
+++ b/src/api/mutations/authentication/index.ts
@@ -9,7 +9,7 @@ import { useApi, useJellifyUser } from '../../../stores'
interface AuthenticateUserByNameMutation {
onSuccess?: () => void
- onError?: () => void
+ onError?: (error: Error) => void
}
const useAuthenticateUserByName = ({ onSuccess, onError }: AuthenticateUserByNameMutation) => {
@@ -51,7 +51,7 @@ const useAuthenticateUserByName = ({ onSuccess, onError }: AuthenticateUserByNam
onError: async (error: Error) => {
console.error('An error occurred connecting to the Jellyfin instance', error)
- if (onError) onError()
+ if (onError) onError(error)
},
retry: 0,
gcTime: 0,
diff --git a/src/components/AddToPlaylist/index.tsx b/src/components/AddToPlaylist/index.tsx
index 1fb82da7..bbf79bae 100644
--- a/src/components/AddToPlaylist/index.tsx
+++ b/src/components/AddToPlaylist/index.tsx
@@ -3,7 +3,18 @@ import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models'
import { addManyToPlaylist, addToPlaylist } from '../../api/mutations/playlists'
import { useState } from 'react'
import Toast from 'react-native-toast-message'
-import { YStack, XStack, Spacer, YGroup, Separator, ListItem, getTokens, ScrollView } from 'tamagui'
+import {
+ YStack,
+ XStack,
+ Spacer,
+ YGroup,
+ Separator,
+ ListItem,
+ getTokens,
+ ScrollView,
+ useTheme,
+ Spinner,
+} from 'tamagui'
import Icon from '../Global/components/icon'
import { AddToPlaylistMutation } from './types'
import { Text } from '../Global/helpers/text'
@@ -16,6 +27,7 @@ import { usePlaylistTracks, useUserPlaylists } from '../../api/queries/playlist'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { useApi, useJellifyUser } from '../../stores'
import Animated, { FadeIn, FadeOut } from 'react-native-reanimated'
+import JellifyToastConfig from '../../configs/toast.config'
export default function AddToPlaylist({
track,
@@ -28,6 +40,8 @@ export default function AddToPlaylist({
}): React.JSX.Element {
const { bottom } = useSafeAreaInsets()
+ const theme = useTheme()
+
const {
data: playlists,
isPending: playlistsFetchPending,
@@ -69,6 +83,12 @@ export default function AddToPlaylist({
))}
)}
+
+
)
}
@@ -133,8 +153,8 @@ function AddToPlaylistRow({
animation={'quick'}
disabled={isInPlaylist}
hoverTheme
- opacity={isInPlaylist ? 0.7 : 1}
- pressStyle={{ opacity: 0.5 }}
+ opacity={isInPlaylist ? 0.5 : 1}
+ pressStyle={{ opacity: 0.6 }}
onPress={() => {
if (!isInPlaylist) {
useAddToPlaylist.mutate({
@@ -159,6 +179,8 @@ function AddToPlaylistRow({
{isInPlaylist ? (
+ ) : fetchingPlaylistTracks ? (
+
) : (
)}
diff --git a/src/components/Context/index.tsx b/src/components/Context/index.tsx
index e31eae8a..f86f005f 100644
--- a/src/components/Context/index.tsx
+++ b/src/components/Context/index.tsx
@@ -109,45 +109,40 @@ export default function ItemContext({
return (
// Tons of padding top for iOS on the scrollview otherwise the context sheet header overlaps the content
-
-
-
+
+
- {renderAddToQueueRow && }
+ {renderAddToQueueRow && }
- {renderAddToQueueRow && }
+ {renderAddToQueueRow && }
- {renderAddToPlaylistRow && (
- d.data) : undefined}
- source={isAlbum ? item : undefined}
- />
- )}
+ {renderAddToPlaylistRow && (
+ d.data) : undefined}
+ source={isAlbum ? item : undefined}
+ />
+ )}
- {(streamingMediaSourceInfo || downloadedMediaSourceInfo) && (
-
- )}
+ {(streamingMediaSourceInfo || downloadedMediaSourceInfo) && (
+
+ )}
- {renderViewAlbumRow && (
-
- )}
+ {renderViewAlbumRow && (
+
+ )}
- {!isPlaylist && (
-
- )}
-
-
+ {!isPlaylist && (
+
+ )}
+
)
}
diff --git a/src/components/Global/components/icon.tsx b/src/components/Global/components/icon.tsx
index 777903fc..00c85fc3 100644
--- a/src/components/Global/components/icon.tsx
+++ b/src/components/Global/components/icon.tsx
@@ -44,7 +44,7 @@ export default function Icon({
return (
(false)
const imageViewStyle = useMemo(
() =>
@@ -137,21 +136,24 @@ function Image({
)
return (
-
- {image ? (
-
- ) : (
-
- )}
-
+
+ (!isLoaded && (
+
+ ))
+ setIsLoaded(true)}
+ testID={testID}
+ entering={FadeIn}
+ exiting={FadeOut}
+ style={Styles.blurhash}
+ />
+
)
}
diff --git a/src/components/Global/components/library-selector.tsx b/src/components/Global/components/library-selector.tsx
index aa9b9e62..b02177d0 100644
--- a/src/components/Global/components/library-selector.tsx
+++ b/src/components/Global/components/library-selector.tsx
@@ -1,5 +1,5 @@
-import React, { useEffect, useState } from 'react'
-import { getToken, Spinner, ToggleGroup, YStack } from 'tamagui'
+import React, { useEffect, useMemo, useState } from 'react'
+import { Spinner, ToggleGroup, XStack, YStack } from 'tamagui'
import { H2, Text } from '../helpers/text'
import Button from '../helpers/button'
import { SafeAreaView } from 'react-native-safe-area-context'
@@ -85,10 +85,37 @@ export default function LibrarySelector({
}
}, [isPending, isSuccess, libraries])
+ const libraryToggleItems = useMemo(
+ () =>
+ musicLibraries.map((library) => {
+ const isSelected: boolean = selectedLibraryId === library.Id!
+
+ return (
+
+
+ {library.Name ?? 'Unnamed Library'}
+
+
+ )
+ }),
+ [selectedLibraryId, musicLibraries],
+ )
+
return (
-
+
{title}
@@ -99,7 +126,7 @@ export default function LibrarySelector({
)}
-
+
{isPending ? (
) : isError ? (
@@ -110,50 +137,42 @@ export default function LibrarySelector({
- {musicLibraries.map((library) => (
-
- {library.Name ?? 'Unnamed Library'}
-
- ))}
+ {libraryToggleItems}
)}
-
-
-
-
- {showCancelButton && (
-
- )}
-
+
+
+ {showCancelButton && (
+
+ )}
+
+
+
)
diff --git a/src/components/Global/helpers/button.tsx b/src/components/Global/helpers/button.tsx
index b185730c..2c51d98c 100644
--- a/src/components/Global/helpers/button.tsx
+++ b/src/components/Global/helpers/button.tsx
@@ -8,5 +8,15 @@ interface ButtonProps extends TamaguiButtonProps {
}
export default function Button(props: ButtonProps): React.JSX.Element {
- return
+ return (
+
+ )
}
diff --git a/src/components/Player/index.tsx b/src/components/Player/index.tsx
index 39fc507a..a2e476ff 100644
--- a/src/components/Player/index.tsx
+++ b/src/components/Player/index.tsx
@@ -4,7 +4,7 @@ import { YStack, useTheme, ZStack, useWindowDimensions, View, getTokenValue } fr
import Scrubber from './components/scrubber'
import Controls from './components/controls'
import Toast from 'react-native-toast-message'
-import JellifyToastConfig from '../../constants/toast.config'
+import JellifyToastConfig from '../../configs/toast.config'
import { useFocusEffect } from '@react-navigation/native'
import Footer from './components/footer'
import BlurredBackground from './components/blurred-background'
diff --git a/src/components/Settings/components/preferences-tab.tsx b/src/components/Settings/components/preferences-tab.tsx
index 2d90488b..22c6245b 100644
--- a/src/components/Settings/components/preferences-tab.tsx
+++ b/src/components/Settings/components/preferences-tab.tsx
@@ -34,9 +34,12 @@ export default function PreferencesTab(): React.JSX.Element {
onPress: () => void
}) => (