1- import { UvxYtdlpIcon } from "@/components/branding/uvxytdlp-icon"
2- import { gridButtonClasses , gridClasses , gridNameClasses , listButtonClasses , listClasses , listNameClasses , roundButtonClasses , thinIconStyle } from "@/lib/icon-style"
3- import LongPressButton from "@/components/ocodo-ui/long-press-button"
4- import { useApiBase } from "@/contexts/api-base-context"
5- import { useDownloaded , type DownloadedFileType } from "@/contexts/downloaded-context"
6- import { DownloadIcon , PlayIcon , Trash2Icon } from "lucide-react"
1+ import { UvxYtdlpIcon } from "@/components/branding/uvxytdlp-icon" ;
2+ import {
3+ gridButtonClasses ,
4+ gridClasses ,
5+ gridNameClasses ,
6+ listButtonClasses ,
7+ listClasses ,
8+ listNameClasses ,
9+ roundButtonClasses ,
10+ thinIconStyle ,
11+ } from "@/lib/style" ;
12+ import LongPressButton from "@/components/ocodo-ui/long-press-button" ;
13+ import { useApiBase } from "@/contexts/api-base-context" ;
14+ import {
15+ useDownloaded ,
16+ type DownloadedFileType ,
17+ } from "@/contexts/downloaded-context" ;
18+ import {
19+ DownloadIcon ,
20+ EllipsisVerticalIcon ,
21+ PlayIcon ,
22+ Trash2Icon ,
23+ } from "lucide-react" ;
724
8- import type React from "react"
9- import { Img } from "react-image"
25+ import { Img } from "react-image" ;
26+ import { cn } from "@/lib/utils" ;
27+ import { type FC } from "react" ;
1028
1129interface DowloadedFileProps {
12- file : DownloadedFileType
13- handlePlay : ( name : string ) => void
14- handleDelete : ( name : string ) => void
15- handleDownload : ( name : string ) => void
16- selectedFile : string | undefined
17- isDeleting : string | undefined
30+ file : DownloadedFileType ;
31+ handlePlay : ( name : string ) => void ;
32+ handleDelete : ( name : string ) => void ;
33+ handleDownload : ( name : string ) => void ;
34+ selectedFile ?: string ;
35+ isDeleting ?: string ;
36+ isExpanded : boolean ;
37+ onToggleExpand : ( ) => void ;
1838}
1939
20- export const DowloadedFile : React . FC < DowloadedFileProps > = ( props ) => {
21- const { file, handlePlay, handleDownload, handleDelete, isDeleting } = props
22- const { apiBase } = useApiBase ( )
23- const { viewType } = useDownloaded ( )
40+ export const DowloadedFile : FC < DowloadedFileProps > = ( props ) => {
41+ const {
42+ file,
43+ handlePlay,
44+ handleDownload,
45+ handleDelete,
46+ isDeleting,
47+ isExpanded,
48+ onToggleExpand,
49+ } = props ;
50+
51+ const { apiBase } = useApiBase ( ) ;
52+ const { viewType } = useDownloaded ( ) ;
53+ const isGrid = viewType === "grid" ;
54+ const isList = viewType === "list" ;
2455
2556 const formatDuration = ( duration : string | null ) => {
26- if ( duration == null ) {
27- return ''
28- }
29- if ( duration ?. includes ( ':' ) ) {
30- return duration
31- } else {
32- return `${ duration } s`
33- }
34- }
57+ if ( ! duration ) return "" ;
58+ return duration . includes ( ":" ) ? duration : `${ duration } s` ;
59+ } ;
3560
3661 const ContentImage = ( ) => (
3762 < div
3863 className = "flex flex-col justify-center items-center relative gap-1 bg-black rounded-t-xl group"
39- onClick = { ( ) => handlePlay ( file . name ) } >
40- < div className = { `absolute cursor-pointer opacity-10
41- group-hover:opacity-100
42- transition-opacity duration-500
43- rounded-full bg-background/30
44- w-20 h-20 mb-[22px]
45- flex flex-row items-center justify-center` } >
64+ onClick = { ( ) => handlePlay ( file . name ) }
65+ >
66+ < div
67+ className = "
68+ absolute cursor-pointer opacity-10 group-hover:opacity-100
69+ transition-opacity duration-500 rounded-full bg-background/30
70+ w-20 h-20 mb-[22px] flex items-center justify-center
71+ "
72+ >
4673 < PlayIcon
47- style = { { stroke : '#fff' , ...thinIconStyle } }
48- className = "w-12 h-12 ml-[3px]" />
74+ style = { { stroke : "#fff" , ...thinIconStyle } }
75+ className = "w-12 h-12 ml-[3px]"
76+ />
4977 </ div >
50- < div className = " rounded-t-xl overflow-hidden rounded-b-none w-full h-[200px] flex flex-row items-center justify-center" >
78+
79+ < div className = "rounded-t-xl overflow-hidden w-full h-[200px] flex items-center justify-center" >
5180 < Img
5281 className = "object-cover"
5382 src = { `${ apiBase } /thumbnail/${ file . name } ` }
@@ -63,67 +92,89 @@ export const DowloadedFile: React.FC<DowloadedFileProps> = (props) => {
6392 />
6493 </ div >
6594 </ div >
66- )
67-
68- const playButton = ( ) => (
69- < div className = { roundButtonClasses }
70- onClick = { ( ) => handlePlay ( file . name ) } >
71- < PlayIcon
72- className = "h-6 w-6 ml-[3px] cursor-pointer"
73- style = { thinIconStyle }
74- />
95+ ) ;
96+
97+ const PlayButtonControl = ( ) => (
98+ < div className = { roundButtonClasses } onClick = { ( ) => handlePlay ( file . name ) } >
99+ < PlayIcon className = "h-6 w-6 ml-[3px]" style = { thinIconStyle } />
75100 </ div >
76- )
77-
78- const downloadButton = ( ) => (
79- < div className = { roundButtonClasses }
80- onClick = { ( ) => handleDownload ( file . name ) } >
81- < DownloadIcon
82- className = "h-6 w-6 cursor-pointer"
83- style = { thinIconStyle }
84- />
101+ ) ;
102+
103+ const DownloadButtonControl = ( ) => (
104+ < div className = { roundButtonClasses } onClick = { ( ) => handleDownload ( file . name ) } >
105+ < DownloadIcon className = "h-6 w-6" style = { thinIconStyle } />
85106 </ div >
86- )
107+ ) ;
87108
88- const deleteButton = ( ) => (
109+ const DeleteButtonControl = ( ) => (
89110 < LongPressButton
90111 onLongPress = { ( ) => handleDelete ( file . name ) }
91112 longPressDuration = { 1000 }
92113 fillUpColorClass = "dark:bg-red-700 bg-red-700"
93- className = { `cursor-pointer animate-color hover:border-red-700
94- border-[1pt] border-transparent animate-all duration-500` }
114+ className = "cursor-pointer animate-color hover:border-red-700 border border-transparent animate-all duration-500"
95115 >
96116 { isDeleting === file . name ? (
97- < Trash2Icon
98- style = { thinIconStyle }
99- className = "animate-pulse" /> // Optional: visual feedback
117+ < Trash2Icon style = { thinIconStyle } className = "animate-pulse" />
100118 ) : (
101- < Trash2Icon
102- style = { thinIconStyle } />
119+ < Trash2Icon style = { thinIconStyle } />
103120 ) }
104-
105121 </ LongPressButton >
106- )
122+ ) ;
107123
108- const isGrid = viewType == 'grid'
109- const isList = viewType == 'list'
124+ const MoreButtonControl = ( ) => (
125+ < EllipsisVerticalIcon
126+ style = { thinIconStyle }
127+ onClick = { onToggleExpand }
128+ className = { cn ( roundButtonClasses , "cursor-pointer w-10 h-10" ) }
129+ />
130+ ) ;
110131
111- return (
112- < div className = { isList ? listClasses : gridClasses } >
113- { isGrid && ContentImage ( ) }
114- < div
115- className = { isList ? listNameClasses : gridNameClasses } >
116- { file . title || file . name }
117- < div className = "text-xs" >
118- { formatDuration ( file . duration ) }
132+ if ( ! isExpanded ) {
133+ return (
134+ < div className = { isList ? listClasses : gridClasses } >
135+ { isGrid && < ContentImage /> }
136+
137+ < div className = { isList ? listNameClasses : gridNameClasses } >
138+ { file . title || file . name }
139+ < div className = "text-xs" > { formatDuration ( file . duration ) } </ div >
140+ </ div >
141+
142+ < div className = { isList ? listButtonClasses : gridButtonClasses } >
143+ < PlayButtonControl />
144+ < DownloadButtonControl />
145+ < DeleteButtonControl />
146+ < MoreButtonControl />
119147 </ div >
120148 </ div >
121- < div
122- className = { isList ? listButtonClasses : gridButtonClasses } >
123- { playButton ( ) }
124- { downloadButton ( ) }
125- { deleteButton ( ) }
149+ ) ;
150+ }
151+
152+ return (
153+ < div className = { cn ( gridClasses , "col-span-full p-4" ) } >
154+ < div className = "flex flex-row gap-4 items-start" >
155+
156+ < div className = "w-1/4 min-w-[180px]" >
157+ < ContentImage />
158+ </ div >
159+
160+ < div className = "flex flex-col gap-2 flex-1" >
161+ < div className = "font-bold text-lg" > { file . title || file . name } </ div >
162+ < div className = "text-xs" > { formatDuration ( file . duration ) } </ div >
163+
164+ { /* Placeholder expanded content */ }
165+ < div className = "text-sm opacity-70" >
166+ Expanded view — add your future metadata/details here.
167+ </ div >
168+
169+ < div className = "flex flex-row gap-2 mt-2" >
170+ < PlayButtonControl />
171+ < DownloadButtonControl />
172+ < DeleteButtonControl />
173+ < MoreButtonControl /> { /* This now closes it */ }
174+ </ div >
175+ </ div >
176+
126177 </ div >
127178 </ div >
128- )
129- }
179+ ) ;
180+ } ;
0 commit comments