fix: improve music page design, mostly headers

This commit is contained in:
Fredrik Burmester
2026-01-03 17:45:28 +01:00
parent 792eef20a9
commit 85d707ef45
9 changed files with 195 additions and 154 deletions

View File

@@ -56,7 +56,12 @@ export default function AlbumDetailScreen() {
}); });
useEffect(() => { useEffect(() => {
navigation.setOptions({ title: album?.Name ?? "" }); navigation.setOptions({
title: album?.Name ?? "",
headerTransparent: true,
headerStyle: { backgroundColor: "transparent" },
headerShadowVisible: false,
});
}, [album?.Name, navigation]); }, [album?.Name, navigation]);
const imageUrl = useMemo( const imageUrl = useMemo(
@@ -111,7 +116,10 @@ export default function AlbumDetailScreen() {
paddingBottom: insets.bottom + 100, paddingBottom: insets.bottom + 100,
}} }}
ListHeaderComponent={ ListHeaderComponent={
<View className='items-center px-4 pt-4 pb-6'> <View
className='items-center px-4 pb-6 bg-black'
style={{ paddingTop: insets.top + 60 }}
>
{/* Album artwork */} {/* Album artwork */}
<View <View
style={{ style={{

View File

@@ -77,7 +77,12 @@ export default function ArtistDetailScreen() {
}); });
useEffect(() => { useEffect(() => {
navigation.setOptions({ title: artist?.Name ?? "" }); navigation.setOptions({
title: artist?.Name ?? "",
headerTransparent: true,
headerStyle: { backgroundColor: "transparent" },
headerShadowVisible: false,
});
}, [artist?.Name, navigation]); }, [artist?.Name, navigation]);
const imageUrl = useMemo( const imageUrl = useMemo(
@@ -138,7 +143,10 @@ export default function ArtistDetailScreen() {
paddingBottom: insets.bottom + 100, paddingBottom: insets.bottom + 100,
}} }}
ListHeaderComponent={ ListHeaderComponent={
<View className='items-center px-4 pt-4 pb-6'> <View
className='items-center px-4 pb-6 bg-black'
style={{ paddingTop: insets.top + 50 }}
>
{/* Artist image */} {/* Artist image */}
<View <View
style={{ style={{

View File

@@ -54,7 +54,12 @@ export default function PlaylistDetailScreen() {
}); });
useEffect(() => { useEffect(() => {
navigation.setOptions({ title: playlist?.Name ?? "" }); navigation.setOptions({
title: playlist?.Name ?? "",
headerTransparent: true,
headerStyle: { backgroundColor: "transparent" },
headerShadowVisible: false,
});
}, [playlist?.Name, navigation]); }, [playlist?.Name, navigation]);
const imageUrl = useMemo( const imageUrl = useMemo(
@@ -111,7 +116,10 @@ export default function PlaylistDetailScreen() {
paddingBottom: insets.bottom + 100, paddingBottom: insets.bottom + 100,
}} }}
ListHeaderComponent={ ListHeaderComponent={
<View className='items-center px-4 pt-4 pb-6'> <View
className='items-center px-4 pb-6 bg-black'
style={{ paddingTop: insets.top + 50 }}
>
{/* Playlist artwork */} {/* Playlist artwork */}
<View <View
style={{ style={{

View File

@@ -29,7 +29,13 @@ const Layout = () => {
return ( return (
<> <>
<Stack.Screen options={{ title: t("music.title") }} /> <Stack.Screen
options={{
title: t("music.title"),
headerStyle: { backgroundColor: "black" },
headerShadowVisible: false,
}}
/>
<Tab <Tab
initialRouteName='suggestions' initialRouteName='suggestions'
keyboardDismissMode='none' keyboardDismissMode='none'

View File

@@ -95,42 +95,44 @@ export default function AlbumsScreen() {
} }
return ( return (
<FlashList <View className='flex-1 bg-black'>
data={albums} <FlashList
numColumns={numColumns} data={albums}
contentContainerStyle={{ numColumns={numColumns}
paddingBottom: insets.bottom + 100, contentContainerStyle={{
paddingTop: 16, paddingBottom: insets.bottom + 100,
paddingHorizontal: padding, paddingTop: 16,
}} paddingHorizontal: padding,
refreshControl={ }}
<RefreshControl refreshControl={
refreshing={false} <RefreshControl
onRefresh={refetch} refreshing={false}
tintColor='#9334E9' onRefresh={refetch}
/> tintColor='#9334E9'
} />
onEndReached={handleEndReached} }
onEndReachedThreshold={0.5} onEndReached={handleEndReached}
renderItem={({ item, index }) => ( onEndReachedThreshold={0.5}
<View renderItem={({ item, index }) => (
style={{ <View
width: itemWidth, style={{
marginRight: index % numColumns === 0 ? gap : 0, width: itemWidth,
marginBottom: gap, marginRight: index % numColumns === 0 ? gap : 0,
}} marginBottom: gap,
> }}
<MusicAlbumCard album={item} width={itemWidth} /> >
</View> <MusicAlbumCard album={item} width={itemWidth} />
)}
keyExtractor={(item) => item.Id!}
ListFooterComponent={
isFetchingNextPage ? (
<View className='py-4'>
<Loader />
</View> </View>
) : null )}
} keyExtractor={(item) => item.Id!}
/> ListFooterComponent={
isFetchingNextPage ? (
<View className='py-4'>
<Loader />
</View>
) : null
}
/>
</View>
); );
} }

View File

@@ -129,42 +129,44 @@ export default function ArtistsScreen() {
} }
return ( return (
<FlashList <View className='flex-1 bg-black'>
data={artists} <FlashList
numColumns={numColumns} data={artists}
contentContainerStyle={{ numColumns={numColumns}
paddingBottom: insets.bottom + 100, contentContainerStyle={{
paddingTop: 16, paddingBottom: insets.bottom + 100,
paddingHorizontal: padding, paddingTop: 16,
}} paddingHorizontal: padding,
refreshControl={ }}
<RefreshControl refreshControl={
refreshing={false} <RefreshControl
onRefresh={refetch} refreshing={false}
tintColor='#9334E9' onRefresh={refetch}
/> tintColor='#9334E9'
} />
onEndReached={handleEndReached} }
onEndReachedThreshold={0.5} onEndReached={handleEndReached}
renderItem={({ item, index }) => ( onEndReachedThreshold={0.5}
<View renderItem={({ item, index }) => (
style={{ <View
width: itemWidth, style={{
marginRight: index % numColumns !== numColumns - 1 ? gap : 0, width: itemWidth,
marginBottom: gap, marginRight: index % numColumns !== numColumns - 1 ? gap : 0,
}} marginBottom: gap,
> }}
<MusicArtistCard artist={item} size={itemWidth} /> >
</View> <MusicArtistCard artist={item} size={itemWidth} />
)}
keyExtractor={(item) => item.Id!}
ListFooterComponent={
isFetchingNextPage ? (
<View className='py-4'>
<Loader />
</View> </View>
) : null )}
} keyExtractor={(item) => item.Id!}
/> ListFooterComponent={
isFetchingNextPage ? (
<View className='py-4'>
<Loader />
</View>
) : null
}
/>
</View>
); );
} }

View File

@@ -129,42 +129,44 @@ export default function PlaylistsScreen() {
} }
return ( return (
<FlashList <View className='flex-1 bg-black'>
data={playlists} <FlashList
numColumns={numColumns} data={playlists}
contentContainerStyle={{ numColumns={numColumns}
paddingBottom: insets.bottom + 100, contentContainerStyle={{
paddingTop: 16, paddingBottom: insets.bottom + 100,
paddingHorizontal: padding, paddingTop: 16,
}} paddingHorizontal: padding,
refreshControl={ }}
<RefreshControl refreshControl={
refreshing={false} <RefreshControl
onRefresh={refetch} refreshing={false}
tintColor='#9334E9' onRefresh={refetch}
/> tintColor='#9334E9'
} />
onEndReached={handleEndReached} }
onEndReachedThreshold={0.5} onEndReached={handleEndReached}
renderItem={({ item, index }) => ( onEndReachedThreshold={0.5}
<View renderItem={({ item, index }) => (
style={{ <View
width: itemWidth, style={{
marginRight: index % numColumns === 0 ? gap : 0, width: itemWidth,
marginBottom: gap, marginRight: index % numColumns === 0 ? gap : 0,
}} marginBottom: gap,
> }}
<MusicPlaylistCard playlist={item} width={itemWidth} /> >
</View> <MusicPlaylistCard playlist={item} width={itemWidth} />
)}
keyExtractor={(item) => item.Id!}
ListFooterComponent={
isFetchingNextPage ? (
<View className='py-4'>
<Loader />
</View> </View>
) : null )}
} keyExtractor={(item) => item.Id!}
/> ListFooterComponent={
isFetchingNextPage ? (
<View className='py-4'>
<Loader />
</View>
) : null
}
/>
</View>
); );
} }

View File

@@ -243,44 +243,46 @@ export default function SuggestionsScreen() {
} }
return ( return (
<FlashList <View className='flex-1 bg-black'>
data={sections} <FlashList
contentContainerStyle={{ data={sections}
paddingBottom: insets.bottom + 100, contentContainerStyle={{
paddingTop: 16, paddingBottom: insets.bottom + 100,
}} paddingTop: 16,
refreshControl={ }}
<RefreshControl refreshControl={
refreshing={false} <RefreshControl
onRefresh={handleRefresh} refreshing={false}
tintColor='#9334E9' onRefresh={handleRefresh}
/> tintColor='#9334E9'
} />
renderItem={({ item: section }) => ( }
<View className='mb-6'> renderItem={({ item: section }) => (
<Text className='text-lg font-bold px-4 mb-3'>{section.title}</Text> <View className='mb-6'>
{section.type === "albums" ? ( <Text className='text-lg font-bold px-4 mb-3'>{section.title}</Text>
<HorizontalScroll {section.type === "albums" ? (
data={section.data} <HorizontalScroll
height={200} data={section.data}
keyExtractor={(item) => item.Id!} height={200}
renderItem={(item) => <MusicAlbumCard album={item} />} keyExtractor={(item) => item.Id!}
/> renderItem={(item) => <MusicAlbumCard album={item} />}
) : ( />
<View className='px-4'> ) : (
{section.data.slice(0, 5).map((track, index, _tracks) => ( <View className='px-4'>
<MusicTrackItem {section.data.slice(0, 5).map((track, index, _tracks) => (
key={track.Id} <MusicTrackItem
track={track} key={track.Id}
index={index + 1} track={track}
queue={section.data} index={index + 1}
/> queue={section.data}
))} />
</View> ))}
)} </View>
</View> )}
)} </View>
keyExtractor={(item) => item.title} )}
/> keyExtractor={(item) => item.title}
/>
</View>
); );
} }

View File

@@ -599,6 +599,9 @@
"artists": "Artists", "artists": "Artists",
"playlists": "Playlists" "playlists": "Playlists"
}, },
"filters": {
"all": "All"
},
"recently_added": "Recently Added", "recently_added": "Recently Added",
"recently_played": "Recently Played", "recently_played": "Recently Played",
"frequently_played": "Frequently Played", "frequently_played": "Frequently Played",