diff --git a/example/DownloadExample.tsx b/example/DownloadExample.tsx new file mode 100644 index 0000000..ca5f4f7 --- /dev/null +++ b/example/DownloadExample.tsx @@ -0,0 +1,237 @@ +import React, { useEffect, useState } from 'react'; +import { + View, + Text, + FlatList, + TouchableOpacity, + StyleSheet, + Alert, +} from 'react-native'; +import { TPStreamsDownload } from 'react-native-tpstreams'; +import type { DownloadItem } from 'react-native-tpstreams'; + +interface DownloadExampleProps { + onBack?: () => void; +} + +export default function DownloadExample({ onBack }: DownloadExampleProps) { + const [downloads, setDownloads] = useState([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + loadDownloads(); + }, []); + + const loadDownloads = async () => { + try { + setLoading(true); + const downloadItems = await TPStreamsDownload.getDownloads(); + setDownloads(downloadItems); + } catch (error) { + Alert.alert('Error', 'Failed to load downloads'); + } finally { + setLoading(false); + } + }; + + const handlePauseResume = async (item: DownloadItem) => { + try { + if (item.state === 1) { + // DOWNLOADING + await TPStreamsDownload.pauseDownload(item.videoId); + } else if (item.state === 2) { + // PAUSED + await TPStreamsDownload.resumeDownload(item.videoId); + } + loadDownloads(); + } catch (error) { + Alert.alert('Error', `Failed to pause/resume download`); + } + }; + + const handleCancel = async (videoId: string) => { + try { + await TPStreamsDownload.cancelDownload(videoId); + loadDownloads(); + } catch (error) { + Alert.alert('Error', `Failed to cancel download`); + } + }; + + const getStateText = (state: number): string => { + switch (state) { + case 0: + return 'Idle'; + case 1: + return 'Downloading'; + case 2: + return 'Paused'; + case 3: + return 'Completed'; + case 4: + return 'Failed'; + default: + return 'Unknown'; + } + }; + + const renderDownloadItem = ({ item }: { item: DownloadItem }) => { + const isPaused = item.state === 2; + const isDownloading = item.state === 1; + + return ( + + + {item.title || 'Untitled'} + Status: {getStateText(item.state)} + + Progress: {Math.round(item.progressPercentage)}% + + + + + {(isDownloading || isPaused) && ( + handlePauseResume(item)} + > + + {isPaused ? 'Resume' : 'Pause'} + + + )} + + handleCancel(item.videoId)} + > + Delete + + + + ); + }; + + return ( + + + {onBack && ( + + ← Back + + )} + Downloads + + + {loading ? ( + Loading... + ) : downloads.length === 0 ? ( + No downloads found + ) : ( + item.videoId} + style={styles.list} + /> + )} + + + Refresh + + + ); +} + +const styles = StyleSheet.create({ + container: { + flex: 1, + padding: 16, + backgroundColor: '#f5f5f5', + }, + header: { + flexDirection: 'row', + alignItems: 'center', + marginBottom: 16, + }, + backButton: { + padding: 8, + marginRight: 8, + }, + backButtonText: { + fontSize: 16, + color: '#2196F3', + }, + headerTitle: { + fontSize: 20, + fontWeight: 'bold', + }, + loading: { + textAlign: 'center', + marginTop: 20, + }, + noDownloads: { + textAlign: 'center', + marginTop: 20, + color: '#666', + }, + list: { + flex: 1, + }, + downloadItem: { + backgroundColor: 'white', + borderRadius: 8, + padding: 16, + marginBottom: 12, + flexDirection: 'row', + justifyContent: 'space-between', + alignItems: 'center', + shadowColor: '#000', + shadowOffset: { width: 0, height: 1 }, + shadowOpacity: 0.2, + shadowRadius: 1, + elevation: 2, + }, + downloadInfo: { + flex: 1, + }, + title: { + fontSize: 16, + fontWeight: 'bold', + marginBottom: 4, + }, + status: { + fontSize: 14, + color: '#666', + marginBottom: 2, + }, + progress: { + fontSize: 14, + color: '#666', + }, + actions: { + flexDirection: 'row', + }, + button: { + backgroundColor: '#2196F3', + borderRadius: 4, + paddingVertical: 6, + paddingHorizontal: 12, + marginLeft: 8, + }, + cancelButton: { + backgroundColor: '#F44336', + }, + buttonText: { + color: 'white', + fontSize: 14, + fontWeight: '500', + }, + refreshButton: { + backgroundColor: '#4CAF50', + borderRadius: 4, + paddingVertical: 12, + alignItems: 'center', + marginTop: 16, + }, +}); diff --git a/example/src/App.tsx b/example/src/App.tsx index 88cff1b..a3ee725 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -2,10 +2,12 @@ import { useRef, useState } from 'react'; import { View, StyleSheet, Button, Text, ScrollView } from 'react-native'; import { TPStreamsPlayerView } from 'react-native-tpstreams'; import type { TPStreamsPlayerRef } from 'react-native-tpstreams'; +import DownloadExample from '../DownloadExample'; export default function App() { const playerRef = useRef(null); const [lastError, setLastError] = useState(null); + const [showDownloads, setShowDownloads] = useState(false); const handlePlay = () => { playerRef.current?.play(); @@ -99,6 +101,10 @@ export default function App() { setLastError(errorMessage); }; + if (showDownloads) { + return setShowDownloads(false)} />; + } + return ( @@ -175,6 +181,18 @@ export default function App() { + + + Downloads + + +