@@ -22,26 +22,41 @@ Future<void> main() async {
2222class AppDataBloc {
2323 final store = SimpleJsonPersistence .getForTypeWithDefault (
2424 (json) => AppData .fromJson (json),
25- defaultCreator: () => AppData (files: []),
25+ defaultCreator: () => AppData (files: [], directories : [] ),
2626 );
2727}
2828
2929class AppData implements HasToJson {
30- AppData ({required this .files});
30+ AppData ({required this .files, required this .directories });
3131 final List <FileInfo > files;
32+ final List <DirectoryInfo > directories;
3233
3334 static AppData fromJson (Map <String , dynamic > json) => AppData (
34- files: (json['files' ] as List <dynamic >)
35- .where ((dynamic element) => element != null )
36- .map ((dynamic e) => FileInfo .fromJson (e as Map <String , dynamic >))
37- .toList ());
35+ files: (json['files' ] as List <dynamic >? ?? < dynamic > [])
36+ .where ((dynamic element) => element != null )
37+ .map ((dynamic e) => FileInfo .fromJson (e as Map <String , dynamic >))
38+ .toList (),
39+ directories: (json['directories' ] as List <dynamic >? ?? < dynamic > [])
40+ .where ((dynamic element) => element != null )
41+ .map ((dynamic e) =>
42+ DirectoryInfo .fromJson (e as Map <String , dynamic >))
43+ .toList (),
44+ );
3845
3946 @override
4047 Map <String , dynamic > toJson () => < String , dynamic > {
4148 'files' : files,
49+ 'directories' : directories,
4250 };
4351
44- AppData copyWith ({required List <FileInfo > files}) => AppData (files: files);
52+ AppData copyWith ({
53+ List <FileInfo >? files,
54+ List <DirectoryInfo >? directories,
55+ }) =>
56+ AppData (
57+ files: files ?? this .files,
58+ directories: directories ?? this .directories,
59+ );
4560}
4661
4762class MyApp extends StatefulWidget {
@@ -143,14 +158,25 @@ class _MainScreenState extends State<MainScreen> {
143158 child: const Text ('Dispose All IDs' ),
144159 onPressed: FilePickerWritable ().disposeAllIdentifiers,
145160 ),
161+ const SizedBox (width: 32 ),
162+ ElevatedButton (
163+ child: const Text ('Open Directory Picker' ),
164+ onPressed: _openDirectoryPicker,
165+ ),
146166 ],
147167 ),
148- ...? (! snapshot.hasData
149- ? null
150- : snapshot.data! .files.map ((fileInfo) => FileInfoDisplay (
151- fileInfo: fileInfo,
152- appDataBloc: _appDataBloc,
153- ))),
168+ if (snapshot.hasData)
169+ for (final fileInfo in snapshot.data! .files)
170+ EntityInfoDisplay (
171+ entityInfo: fileInfo,
172+ appDataBloc: _appDataBloc,
173+ ),
174+ if (snapshot.hasData)
175+ for (final directoryInfo in snapshot.data! .directories)
176+ EntityInfoDisplay (
177+ entityInfo: directoryInfo,
178+ appDataBloc: _appDataBloc,
179+ ),
154180 ],
155181 ),
156182 ),
@@ -190,17 +216,29 @@ class _MainScreenState extends State<MainScreen> {
190216 await _appDataBloc.store
191217 .save (data.copyWith (files: data.files + [fileInfo]));
192218 }
219+
220+ Future <void > _openDirectoryPicker () async {
221+ final directoryInfo = await FilePickerWritable ().openDirectory ();
222+ if (directoryInfo == null ) {
223+ _logger.fine ('User cancelled.' );
224+ } else {
225+ _logger.fine ('Got picker result: $directoryInfo ' );
226+ final data = await _appDataBloc.store.load ();
227+ await _appDataBloc.store
228+ .save (data.copyWith (directories: data.directories + [directoryInfo]));
229+ }
230+ }
193231}
194232
195- class FileInfoDisplay extends StatelessWidget {
196- const FileInfoDisplay ({
233+ class EntityInfoDisplay extends StatelessWidget {
234+ const EntityInfoDisplay ({
197235 Key ? key,
198- required this .fileInfo ,
236+ required this .entityInfo ,
199237 required this .appDataBloc,
200238 }) : super (key: key);
201239
202240 final AppDataBloc appDataBloc;
203- final FileInfo fileInfo ;
241+ final EntityInfo entityInfo ;
204242
205243 @override
206244 Widget build (BuildContext context) {
@@ -213,77 +251,99 @@ class FileInfoDisplay extends StatelessWidget {
213251 padding: const EdgeInsets .all (16.0 ),
214252 child: Column (
215253 children: < Widget > [
216- const Text ('Selected File:' ),
254+ if (entityInfo is FileInfo ) const Text ('Selected File:' ),
255+ if (entityInfo is DirectoryInfo )
256+ const Text ('Selected Directory:' ),
217257 Text (
218- fileInfo .fileName ?? 'null' ,
258+ entityInfo .fileName ?? 'null' ,
219259 maxLines: 4 ,
220260 overflow: TextOverflow .ellipsis,
221261 style: theme.textTheme.caption! .apply (fontSizeFactor: 0.75 ),
222262 ),
223263 Text (
224- fileInfo .identifier,
264+ entityInfo .identifier,
225265 maxLines: 1 ,
226266 overflow: TextOverflow .ellipsis,
227267 ),
228268 Text (
229- 'uri:${fileInfo .uri }' ,
269+ 'uri:${entityInfo .uri }' ,
230270 style: theme.textTheme.bodyText2!
231271 .apply (fontSizeFactor: 0.7 )
232272 .copyWith (fontWeight: FontWeight .bold),
233273 ),
234274 Text (
235- 'fileName: ${fileInfo .fileName }' ,
275+ 'fileName: ${entityInfo .fileName }' ,
236276 style: theme.textTheme.bodyText2!
237277 .apply (fontSizeFactor: 0.7 )
238278 .copyWith (fontWeight: FontWeight .bold),
239279 ),
240280 ButtonBar (
241281 alignment: MainAxisAlignment .end,
242282 children: < Widget > [
243- TextButton (
244- onPressed: () async {
245- try {
246- await FilePickerWritable ().readFile (
247- identifier: fileInfo.identifier,
248- reader: (fileInfo, file) async {
249- await SimpleAlertDialog
250- .readFileContentsAndShowDialog (
251- fileInfo, file, context);
283+ if (entityInfo is FileInfo ) ...[
284+ TextButton (
285+ onPressed: () async {
286+ try {
287+ await FilePickerWritable ().readFile (
288+ identifier: entityInfo.identifier,
289+ reader: (fileInfo, file) async {
290+ await SimpleAlertDialog
291+ .readFileContentsAndShowDialog (
292+ fileInfo, file, context);
293+ });
294+ } on Exception catch (e) {
295+ await SimpleAlertDialog .showErrorDialog (e, context);
296+ }
297+ },
298+ child: const Text ('Read' ),
299+ ),
300+ TextButton (
301+ onPressed: () async {
302+ await FilePickerWritable ().writeFile (
303+ identifier: entityInfo.identifier,
304+ writer: (file) async {
305+ final content =
306+ 'New Content written at ${DateTime .now ()}.\n\n ' ;
307+ await file.writeAsString (content);
308+ await SimpleAlertDialog (
309+ bodyText: 'Written: $content ' ,
310+ ).show (context);
252311 });
253- } on Exception catch (e) {
254- await SimpleAlertDialog .showErrorDialog (e, context);
255- }
256- },
257- child: const Text ('Read' ),
258- ),
259- TextButton (
260- onPressed: () async {
261- await FilePickerWritable ().writeFile (
262- identifier: fileInfo.identifier,
263- writer: (file) async {
264- final content =
265- 'New Content written at ${DateTime .now ()}.\n\n ' ;
266- await file.writeAsString (content);
267- await SimpleAlertDialog (
268- bodyText: 'Written: $content ' ,
269- ).show (context);
270- });
271- },
272- child: const Text ('Overwrite' ),
273- ),
312+ },
313+ child: const Text ('Overwrite' ),
314+ ),
315+ TextButton (
316+ onPressed: () async {
317+ final directoryInfo = await FilePickerWritable ()
318+ .openDirectory (initialDirUri: entityInfo.uri);
319+ if (directoryInfo != null ) {
320+ final data = await appDataBloc.store.load ();
321+ await appDataBloc.store.save (data.copyWith (
322+ directories: data.directories + [directoryInfo]));
323+ }
324+ },
325+ child: const Text ('Pick dir' ),
326+ ),
327+ ],
274328 IconButton (
275329 onPressed: () async {
276330 try {
277331 await FilePickerWritable ()
278- .disposeIdentifier (fileInfo .identifier);
332+ .disposeIdentifier (entityInfo .identifier);
279333 } on Exception catch (e) {
280334 await SimpleAlertDialog .showErrorDialog (e, context);
281335 }
282336 final appData = await appDataBloc.store.load ();
283- await appDataBloc.store.save (appData.copyWith (
337+ await appDataBloc.store.save (
338+ appData.copyWith (
284339 files: appData.files
285- .where ((element) => element != fileInfo)
286- .toList ()));
340+ .where ((element) => element != entityInfo)
341+ .toList (),
342+ directories: appData.directories
343+ .where ((element) => element != entityInfo)
344+ .toList (),
345+ ),
346+ );
287347 },
288348 icon: const Icon (Icons .remove_circle_outline),
289349 ),
0 commit comments