creek
The AI Image Editor of 2030git clone https://github.com/maydayv7/creek
lib/ui/widgets/file_card.dart (5887B)
1import 'dart:io';
2import 'package:flutter/material.dart';
3import 'package:creekui/data/models/file_model.dart';
4import 'package:creekui/ui/styles/variables.dart';
5
6class FileCard extends StatelessWidget {
7 final FileModel file;
8 final String breadcrumb;
9 final String dimensions;
10 final String previewPath;
11 final String timeAgo;
12 final VoidCallback onTap;
13
14 // Optional actions for the context menu
15 final Function(String)? onMenuAction;
16
17 const FileCard({
18 super.key,
19 required this.file,
20 required this.breadcrumb,
21 required this.dimensions,
22 required this.previewPath,
23 required this.timeAgo,
24 required this.onTap,
25 this.onMenuAction,
26 });
27
28 @override
29 Widget build(BuildContext context) {
30 return GestureDetector(
31 onTap: onTap,
32 child: Container(
33 height: 110,
34 decoration: BoxDecoration(
35 color: Variables.background,
36 borderRadius: BorderRadius.circular(Variables.radiusMedium),
37 border: Border.all(color: Variables.borderSubtle),
38 ),
39 padding: const EdgeInsets.all(12),
40 child: Row(
41 children: [
42 // Preview Image
43 Container(
44 width: 76,
45 height: 76,
46 decoration: BoxDecoration(
47 color: Variables.surfaceSubtle,
48 borderRadius: BorderRadius.circular(Variables.radiusSmall),
49 ),
50 clipBehavior: Clip.antiAlias,
51 child:
52 previewPath.isNotEmpty
53 ? Image.file(
54 File(previewPath),
55 fit: BoxFit.cover,
56 errorBuilder:
57 (context, error, stackTrace) => const Center(
58 child: Icon(
59 Icons.broken_image,
60 color: Variables.textDisabled,
61 ),
62 ),
63 )
64 : const Center(
65 child: Icon(Icons.image, color: Variables.textDisabled),
66 ),
67 ),
68 const SizedBox(width: 16),
69 // Info
70 Expanded(
71 child: Column(
72 crossAxisAlignment: CrossAxisAlignment.start,
73 mainAxisAlignment: MainAxisAlignment.center,
74 children: [
75 if (breadcrumb.isNotEmpty)
76 Padding(
77 padding: const EdgeInsets.only(bottom: 4),
78 child: Text(
79 breadcrumb,
80 style: Variables.captionStyle,
81 maxLines: 1,
82 overflow: TextOverflow.ellipsis,
83 ),
84 ),
85 Text(
86 file.name,
87 style: Variables.bodyStyle.copyWith(
88 fontWeight: FontWeight.w600,
89 ),
90 maxLines: 1,
91 overflow: TextOverflow.ellipsis,
92 ),
93 const SizedBox(height: 4),
94 Text(dimensions, style: Variables.captionStyle),
95 const SizedBox(height: 2),
96 Text(
97 timeAgo,
98 style: Variables.captionStyle.copyWith(
99 color: Variables.textSecondary,
100 ),
101 ),
102 ],
103 ),
104 ),
105 // Menu Action
106 if (onMenuAction != null)
107 PopupMenuButton<String>(
108 icon: const Icon(
109 Icons.more_vert,
110 color: Variables.textSecondary,
111 ),
112 onSelected: onMenuAction,
113 itemBuilder:
114 (BuildContext context) => <PopupMenuEntry<String>>[
115 const PopupMenuItem<String>(
116 value: 'open',
117 child: Row(
118 children: [
119 Icon(Icons.file_open_outlined, size: 18),
120 SizedBox(width: 12),
121 Text(
122 'Open',
123 style: TextStyle(fontFamily: 'GeneralSans'),
124 ),
125 ],
126 ),
127 ),
128 const PopupMenuItem<String>(
129 value: 'rename',
130 child: Row(
131 children: [
132 Icon(Icons.edit_outlined, size: 18),
133 SizedBox(width: 12),
134 Text(
135 'Rename',
136 style: TextStyle(fontFamily: 'GeneralSans'),
137 ),
138 ],
139 ),
140 ),
141 const PopupMenuItem<String>(
142 value: 'delete',
143 child: Row(
144 children: [
145 Icon(
146 Icons.delete_outline,
147 size: 18,
148 color: Colors.red,
149 ),
150 SizedBox(width: 12),
151 Text(
152 'Delete',
153 style: TextStyle(
154 fontFamily: 'GeneralSans',
155 color: Colors.red,
156 ),
157 ),
158 ],
159 ),
160 ),
161 ],
162 ),
163 ],
164 ),
165 ),
166 );
167 }
168}