Allow retries for failed tracks
This commit is contained in:
3
src/assets/arrow-clockwise.svg
Normal file
3
src/assets/arrow-clockwise.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="20" viewBox="0 0 16 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.74512 9.09863C8 9.09863 8.20215 9.01953 8.36035 8.85254L11.9639 5.22266C12.1572 5.0293 12.2451 4.81836 12.2451 4.57227C12.2451 4.33496 12.1484 4.10645 11.9639 3.93066L8.36035 0.265625C8.20215 0.0898438 8 0.00195312 7.74512 0.00195312C7.27051 0.00195312 6.89258 0.397461 6.89258 0.880859C6.89258 1.11816 6.98047 1.31152 7.12988 1.47852L9.23047 3.53516C8.81738 3.47363 8.39551 3.43848 7.97363 3.43848C3.62305 3.43848 0.142578 6.91895 0.142578 11.2783C0.142578 15.6377 3.64941 19.1445 8 19.1445C12.3594 19.1445 15.8574 15.6377 15.8574 11.2783C15.8574 10.751 15.4883 10.373 14.9609 10.373C14.4512 10.373 14.1084 10.751 14.1084 11.2783C14.1084 14.6709 11.3926 17.3955 8 17.3955C4.61621 17.3955 1.8916 14.6709 1.8916 11.2783C1.8916 7.85938 4.58984 5.15234 7.97363 5.15234C8.54492 5.15234 9.07227 5.19629 9.53809 5.27539L7.13867 7.64844C6.98047 7.80664 6.89258 8 6.89258 8.2373C6.89258 8.7207 7.27051 9.09863 7.74512 9.09863Z" />
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -1,17 +1,19 @@
|
||||
import useDefaultStyles from 'components/Colors';
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
import { Pressable, Text, View } from 'react-native';
|
||||
import { Text, TouchableOpacity, View } from 'react-native';
|
||||
import { FlatList } from 'react-native-gesture-handler';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import { useTypedSelector } from 'store';
|
||||
import formatBytes from 'utility/formatBytes';
|
||||
import TrashIcon from 'assets/trash.svg';
|
||||
import ArrowClockwise from 'assets/arrow-clockwise.svg';
|
||||
import { THEME_COLOR } from 'CONSTANTS';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { EntityId } from '@reduxjs/toolkit';
|
||||
import { removeDownloadedTrack } from 'store/downloads/actions';
|
||||
import { downloadTrack, removeDownloadedTrack } from 'store/downloads/actions';
|
||||
import Button from 'components/Button';
|
||||
import { t } from 'i18n-js';
|
||||
import DownloadIcon from 'components/DownloadIcon';
|
||||
|
||||
function Downloads() {
|
||||
const defaultStyles = useDefaultStyles();
|
||||
@@ -25,13 +27,18 @@ function Downloads() {
|
||||
ids?.reduce<number>((sum, id) => sum + (entities[id]?.size || 0), 0)
|
||||
), [ids, entities]);
|
||||
|
||||
// Describe handlers
|
||||
const handleDelete = useCallback((id: EntityId) => {
|
||||
dispatch(removeDownloadedTrack(id));
|
||||
}, [dispatch]);
|
||||
const handleDeleteAllTracks = useCallback(() => {
|
||||
ids.forEach((id) => dispatch(removeDownloadedTrack(id)));
|
||||
}, [dispatch, ids]);
|
||||
const retryTrack = useCallback((id: EntityId) => {
|
||||
dispatch(downloadTrack(id));
|
||||
}, [dispatch]);
|
||||
|
||||
// If no tracks have beend ownloaded, show a short message describing this
|
||||
if (!ids.length) {
|
||||
return (
|
||||
<View style={{ margin: 24, flex: 1, alignItems: 'center', justifyContent: 'center' }}>
|
||||
@@ -43,37 +50,66 @@ function Downloads() {
|
||||
}
|
||||
|
||||
return (
|
||||
<SafeAreaView style={{ flex: 1, marginHorizontal: 24 }}>
|
||||
<SafeAreaView style={{ flex: 1 }}>
|
||||
<FlatList
|
||||
style={{ flex: 1 }}
|
||||
contentContainerStyle={{ flexGrow: 1 }}
|
||||
ListHeaderComponent={
|
||||
<Text style={[{ textAlign: 'center', marginVertical: 6 }, defaultStyles.textHalfOpacity]}>
|
||||
{t('total-download-size')}: {formatBytes(totalDownloadSize)}
|
||||
</Text>
|
||||
}
|
||||
ListFooterComponent={
|
||||
<Button
|
||||
icon={TrashIcon}
|
||||
title={t('delete-all-tracks')}
|
||||
onPress={handleDeleteAllTracks}
|
||||
disabled={!ids.length}
|
||||
style={{ marginTop: 8 }}
|
||||
/>
|
||||
<View style={{ marginHorizontal: 20 }}>
|
||||
<Button
|
||||
icon={TrashIcon}
|
||||
title={t('delete-all-tracks')}
|
||||
onPress={handleDeleteAllTracks}
|
||||
disabled={!ids.length}
|
||||
style={{ marginTop: 8 }}
|
||||
/>
|
||||
</View>
|
||||
}
|
||||
data={ids}
|
||||
renderItem={({ item }) => (
|
||||
<View style={{ flex: 1, flexDirection: 'row', paddingVertical: 8, alignItems: 'center' }}>
|
||||
<View>
|
||||
<Text style={{ fontSize: 16, marginBottom: 4 }} numberOfLines={1}>{tracks[item]?.Name}</Text>
|
||||
<Text style={[{ flexShrink: 1, fontSize: 11 }, defaultStyles.textHalfOpacity]} numberOfLines={1}>{tracks[item]?.AlbumArtist} ({tracks[item]?.Album})</Text>
|
||||
<View
|
||||
style={[
|
||||
{
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
paddingVertical: 12,
|
||||
alignItems: 'center',
|
||||
marginHorizontal: 20,
|
||||
borderBottomWidth: 1,
|
||||
},
|
||||
defaultStyles.border,
|
||||
]}
|
||||
>
|
||||
<View style={{ marginRight: 12 }}>
|
||||
<DownloadIcon trackId={item} />
|
||||
</View>
|
||||
<View style={{ flexShrink: 1, marginRight: 8 }}>
|
||||
<Text style={{ fontSize: 16, marginBottom: 4 }} numberOfLines={1}>
|
||||
{tracks[item]?.Name}
|
||||
</Text>
|
||||
<Text style={[{ flexShrink: 1, fontSize: 11 }, defaultStyles.textHalfOpacity]} numberOfLines={1}>
|
||||
{tracks[item]?.AlbumArtist} ({tracks[item]?.Album})
|
||||
</Text>
|
||||
</View>
|
||||
<View style={{ marginLeft: 'auto', flexDirection: 'row', alignItems: 'center' }}>
|
||||
<Text style={[defaultStyles.textHalfOpacity, { marginRight: 6 }]}>
|
||||
{formatBytes(entities[item]?.size || 0)}
|
||||
</Text>
|
||||
<Pressable onPress={() => handleDelete(item)}>
|
||||
{entities[item]?.isComplete && entities[item]?.size ? (
|
||||
<Text style={[defaultStyles.textHalfOpacity, { marginRight: 6, fontSize: 12 }]}>
|
||||
{formatBytes(entities[item]?.size || 0)}
|
||||
</Text>
|
||||
) : null}
|
||||
<TouchableOpacity onPress={() => handleDelete(item)}>
|
||||
<TrashIcon height={24} width={24} fill={THEME_COLOR} />
|
||||
</Pressable>
|
||||
</TouchableOpacity>
|
||||
{!entities[item]?.isComplete && (
|
||||
<TouchableOpacity onPress={() => retryTrack(item)}>
|
||||
<ArrowClockwise height={18} width={18} fill={THEME_COLOR} />
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
|
||||
@@ -61,7 +61,6 @@ export function generateTrackUrl(trackId: string, credentials: Credentials) {
|
||||
|
||||
const trackParams = new URLSearchParams(trackOptions).toString();
|
||||
const url = encodeURI(`${credentials?.uri}/Audio/${trackId}/universal?${trackParams}`);
|
||||
console.log(url);
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user