fix: show loading indicator when pressing song in music

This commit is contained in:
Fredrik Burmester
2026-01-03 16:24:06 +01:00
parent baa96d222f
commit 6487c8b5a1
4 changed files with 109 additions and 37 deletions

View File

@@ -4,7 +4,13 @@ import { Image } from "expo-image";
import { useRouter } from "expo-router";
import { useAtom } from "jotai";
import React, { useCallback, useMemo } from "react";
import { Platform, StyleSheet, TouchableOpacity, View } from "react-native";
import {
ActivityIndicator,
Platform,
StyleSheet,
TouchableOpacity,
View,
} from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { Text } from "@/components/common/Text";
import { apiAtom } from "@/providers/JellyfinProvider";
@@ -18,8 +24,15 @@ export const MiniPlayerBar: React.FC = () => {
const [api] = useAtom(apiAtom);
const insets = useSafeAreaInsets();
const router = useRouter();
const { currentTrack, isPlaying, progress, duration, togglePlayPause, next } =
useMusicPlayer();
const {
currentTrack,
isPlaying,
isLoading,
progress,
duration,
togglePlayPause,
next,
} = useMusicPlayer();
const imageUrl = useMemo(() => {
if (!api || !currentTrack) return null;
@@ -87,24 +100,30 @@ export const MiniPlayerBar: React.FC = () => {
{/* Controls */}
<View style={styles.controls}>
<TouchableOpacity
onPress={handlePlayPause}
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
style={styles.controlButton}
>
<Ionicons
name={isPlaying ? "pause" : "play"}
size={26}
color='white'
/>
</TouchableOpacity>
<TouchableOpacity
onPress={handleNext}
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
style={styles.controlButton}
>
<Ionicons name='play-forward' size={22} color='white' />
</TouchableOpacity>
{isLoading ? (
<ActivityIndicator size='small' color='white' style={styles.loader} />
) : (
<>
<TouchableOpacity
onPress={handlePlayPause}
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
style={styles.controlButton}
>
<Ionicons
name={isPlaying ? "pause" : "play"}
size={26}
color='white'
/>
</TouchableOpacity>
<TouchableOpacity
onPress={handleNext}
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
style={styles.controlButton}
>
<Ionicons name='play-forward' size={22} color='white' />
</TouchableOpacity>
</>
)}
</View>
{/* Progress bar at bottom */}
@@ -219,6 +238,9 @@ const styles = StyleSheet.create({
controlButton: {
padding: 8,
},
loader: {
marginHorizontal: 16,
},
progressContainer: {
position: "absolute",
bottom: 0,

View File

@@ -4,7 +4,7 @@ import type { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
import { Image } from "expo-image";
import { useAtom } from "jotai";
import React, { useCallback, useMemo } from "react";
import { TouchableOpacity, View } from "react-native";
import { ActivityIndicator, TouchableOpacity, View } from "react-native";
import { Text } from "@/components/common/Text";
import { apiAtom } from "@/providers/JellyfinProvider";
import { useMusicPlayer } from "@/providers/MusicPlayerProvider";
@@ -26,8 +26,14 @@ export const MusicTrackItem: React.FC<Props> = ({
}) => {
const [api] = useAtom(apiAtom);
const { showActionSheetWithOptions } = useActionSheet();
const { playTrack, playNext, addToQueue, currentTrack, isPlaying } =
useMusicPlayer();
const {
playTrack,
playNext,
addToQueue,
currentTrack,
isPlaying,
loadingTrackId,
} = useMusicPlayer();
const imageUrl = useMemo(() => {
const albumId = track.AlbumId || track.ParentId;
@@ -38,6 +44,7 @@ export const MusicTrackItem: React.FC<Props> = ({
}, [api, track]);
const isCurrentTrack = currentTrack?.Id === track.Id;
const isTrackLoading = loadingTrackId === track.Id;
const duration = useMemo(() => {
if (!track.RunTimeTicks) return "";
@@ -109,6 +116,22 @@ export const MusicTrackItem: React.FC<Props> = ({
<Ionicons name='musical-note' size={20} color='#737373' />
</View>
)}
{isTrackLoading && (
<View
style={{
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: "rgba(0, 0, 0, 0.6)",
alignItems: "center",
justifyContent: "center",
}}
>
<ActivityIndicator size='small' color='white' />
</View>
)}
</View>
)}