2022-01-02 02:28:52 +01:00
|
|
|
import useDefaultStyles from 'components/Colors';
|
|
|
|
|
import React, { useCallback, useMemo } from 'react';
|
2022-01-02 18:11:30 +01:00
|
|
|
import { Text, TouchableOpacity, View } from 'react-native';
|
2022-01-02 02:28:52 +01:00
|
|
|
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';
|
2022-01-02 18:11:30 +01:00
|
|
|
import ArrowClockwise from 'assets/arrow-clockwise.svg';
|
2022-01-02 02:28:52 +01:00
|
|
|
import { THEME_COLOR } from 'CONSTANTS';
|
|
|
|
|
import { useDispatch } from 'react-redux';
|
|
|
|
|
import { EntityId } from '@reduxjs/toolkit';
|
2022-01-02 18:11:30 +01:00
|
|
|
import { downloadTrack, removeDownloadedTrack } from 'store/downloads/actions';
|
2022-01-02 02:28:52 +01:00
|
|
|
import Button from 'components/Button';
|
|
|
|
|
import { t } from 'i18n-js';
|
2022-01-02 18:11:30 +01:00
|
|
|
import DownloadIcon from 'components/DownloadIcon';
|
2022-01-02 02:28:52 +01:00
|
|
|
|
|
|
|
|
function Downloads() {
|
|
|
|
|
const defaultStyles = useDefaultStyles();
|
|
|
|
|
const dispatch = useDispatch();
|
|
|
|
|
|
|
|
|
|
const { entities, ids } = useTypedSelector((state) => state.downloads);
|
|
|
|
|
const tracks = useTypedSelector((state) => state.music.tracks.entities);
|
|
|
|
|
|
|
|
|
|
// Calculate the total download size
|
|
|
|
|
const totalDownloadSize = useMemo(() => (
|
|
|
|
|
ids?.reduce<number>((sum, id) => sum + (entities[id]?.size || 0), 0)
|
|
|
|
|
), [ids, entities]);
|
|
|
|
|
|
2022-01-02 18:11:30 +01:00
|
|
|
// Describe handlers
|
2022-01-02 02:28:52 +01:00
|
|
|
const handleDelete = useCallback((id: EntityId) => {
|
|
|
|
|
dispatch(removeDownloadedTrack(id));
|
|
|
|
|
}, [dispatch]);
|
|
|
|
|
const handleDeleteAllTracks = useCallback(() => {
|
|
|
|
|
ids.forEach((id) => dispatch(removeDownloadedTrack(id)));
|
|
|
|
|
}, [dispatch, ids]);
|
2022-01-02 18:11:30 +01:00
|
|
|
const retryTrack = useCallback((id: EntityId) => {
|
|
|
|
|
dispatch(downloadTrack(id));
|
|
|
|
|
}, [dispatch]);
|
2022-01-02 02:28:52 +01:00
|
|
|
|
2022-01-02 18:11:30 +01:00
|
|
|
// If no tracks have beend ownloaded, show a short message describing this
|
2022-01-02 02:28:52 +01:00
|
|
|
if (!ids.length) {
|
|
|
|
|
return (
|
|
|
|
|
<View style={{ margin: 24, flex: 1, alignItems: 'center', justifyContent: 'center' }}>
|
|
|
|
|
<Text style={[{ textAlign: 'center'}, defaultStyles.textHalfOpacity]}>
|
|
|
|
|
{t('no-downloads')}
|
|
|
|
|
</Text>
|
|
|
|
|
</View>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (
|
2022-01-02 18:11:30 +01:00
|
|
|
<SafeAreaView style={{ flex: 1 }}>
|
2022-01-02 02:28:52 +01:00
|
|
|
<FlatList
|
|
|
|
|
style={{ flex: 1 }}
|
2022-01-02 18:11:30 +01:00
|
|
|
contentContainerStyle={{ flexGrow: 1 }}
|
2022-01-02 02:28:52 +01:00
|
|
|
ListHeaderComponent={
|
|
|
|
|
<Text style={[{ textAlign: 'center', marginVertical: 6 }, defaultStyles.textHalfOpacity]}>
|
|
|
|
|
{t('total-download-size')}: {formatBytes(totalDownloadSize)}
|
|
|
|
|
</Text>
|
|
|
|
|
}
|
|
|
|
|
ListFooterComponent={
|
2022-01-02 18:11:30 +01:00
|
|
|
<View style={{ marginHorizontal: 20 }}>
|
|
|
|
|
<Button
|
|
|
|
|
icon={TrashIcon}
|
|
|
|
|
title={t('delete-all-tracks')}
|
|
|
|
|
onPress={handleDeleteAllTracks}
|
|
|
|
|
disabled={!ids.length}
|
|
|
|
|
style={{ marginTop: 8 }}
|
|
|
|
|
/>
|
|
|
|
|
</View>
|
2022-01-02 02:28:52 +01:00
|
|
|
}
|
|
|
|
|
data={ids}
|
|
|
|
|
renderItem={({ item }) => (
|
2022-01-02 18:11:30 +01:00
|
|
|
<View
|
|
|
|
|
style={[
|
|
|
|
|
{
|
|
|
|
|
flex: 1,
|
|
|
|
|
flexDirection: 'row',
|
|
|
|
|
paddingVertical: 12,
|
|
|
|
|
alignItems: 'center',
|
|
|
|
|
marginHorizontal: 20,
|
|
|
|
|
borderBottomWidth: 1,
|
|
|
|
|
},
|
|
|
|
|
defaultStyles.border,
|
|
|
|
|
]}
|
|
|
|
|
>
|
|
|
|
|
<View style={{ marginRight: 12 }}>
|
|
|
|
|
<DownloadIcon trackId={item} />
|
2022-01-02 02:28:52 +01:00
|
|
|
</View>
|
2022-01-02 18:11:30 +01:00
|
|
|
<View style={{ flexShrink: 1, marginRight: 8 }}>
|
|
|
|
|
<Text style={{ fontSize: 16, marginBottom: 4 }} numberOfLines={1}>
|
|
|
|
|
{tracks[item]?.Name}
|
2022-01-02 02:28:52 +01:00
|
|
|
</Text>
|
2022-01-02 18:11:30 +01:00
|
|
|
<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' }}>
|
|
|
|
|
{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)}>
|
2022-01-02 02:28:52 +01:00
|
|
|
<TrashIcon height={24} width={24} fill={THEME_COLOR} />
|
2022-01-02 18:11:30 +01:00
|
|
|
</TouchableOpacity>
|
|
|
|
|
{!entities[item]?.isComplete && (
|
|
|
|
|
<TouchableOpacity onPress={() => retryTrack(item)}>
|
|
|
|
|
<ArrowClockwise height={18} width={18} fill={THEME_COLOR} />
|
|
|
|
|
</TouchableOpacity>
|
|
|
|
|
)}
|
2022-01-02 02:28:52 +01:00
|
|
|
</View>
|
|
|
|
|
</View>
|
|
|
|
|
)}
|
|
|
|
|
/>
|
|
|
|
|
</SafeAreaView>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default Downloads;
|