diff --git a/lib/ui/collections/device_folders_grid_view_widget.dart b/lib/ui/collections/device_folders_grid_view_widget.dart index 51b99eebf..6e514abbe 100644 --- a/lib/ui/collections/device_folders_grid_view_widget.dart +++ b/lib/ui/collections/device_folders_grid_view_widget.dart @@ -87,7 +87,7 @@ class _DeviceFoldersGridViewWidgetState itemCount: snapshot.data.length, ); } else if (snapshot.hasError) { - logger.severe("failed to load device galler", snapshot.error); + logger.severe("failed to load device gallery", snapshot.error); return const Text("Failed to load albums"); } else { return const EnteLoadingWidget(); diff --git a/lib/ui/tools/debug/path_storage_viewer.dart b/lib/ui/tools/debug/path_storage_viewer.dart index 417f7ffdb..37a31bbcb 100644 --- a/lib/ui/tools/debug/path_storage_viewer.dart +++ b/lib/ui/tools/debug/path_storage_viewer.dart @@ -1,8 +1,10 @@ +import 'dart:io'; + import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:logging/logging.dart'; import 'package:photos/theme/ente_theme.dart'; -import 'package:photos/ui/common/loading_widget.dart'; import 'package:photos/ui/components/captioned_text_widget.dart'; import 'package:photos/ui/components/menu_item_widget.dart'; import 'package:photos/utils/data_util.dart'; @@ -39,47 +41,63 @@ class PathStorageViewer extends StatefulWidget { } class _PathStorageViewerState extends State { - Map? _sizeAndFileCountInfo; + final Logger _logger = Logger((_PathStorageViewerState).toString()); @override void initState() { - _initLogs(); super.initState(); } - void _initLogs() { - directoryStat(widget.item.path).then((logs) { - setState(() { - _sizeAndFileCountInfo = logs; - }); - }); + void _safeRefresh() async { + if (mounted) { + setState(() => {}); + } } @override Widget build(BuildContext context) { - return _getBody(); + return FutureBuilder( + future: getDirectorySize(Directory(widget.item.path)), + builder: (context, snapshot) { + if (snapshot.hasData) { + return _buildMenuItemWidget(snapshot.data, null); + } else if (snapshot.hasError) { + _logger.severe( + "Failed to get state for ${widget.item.title}", + snapshot.error, + ); + return _buildMenuItemWidget(null, snapshot.error); + } else { + return _buildMenuItemWidget(null, null); + } + }, + ); } - Widget _getBody() { - if (_sizeAndFileCountInfo == null) { - return const EnteLoadingWidget(); - } - final int fileCount = _sizeAndFileCountInfo!["fileCount"] ?? -1; - final int size = _sizeAndFileCountInfo!['size'] ?? 0; - + Widget _buildMenuItemWidget(DirectoryStat? stat, Object? err) { return MenuItemWidget( alignCaptionedTextToLeft: true, captionedTextWidget: CaptionedTextWidget( title: widget.item.title, - subTitle: '$fileCount', + subTitle: stat != null ? '${stat.fileCount}' : null, subTitleColor: getEnteColorScheme(context).textFaint, ), - trailingWidget: Text( - formatBytes(size), - style: getEnteTextTheme(context) - .small - .copyWith(color: getEnteColorScheme(context).textFaint), - ), + trailingWidget: stat != null + ? Text( + formatBytes(stat.size), + style: getEnteTextTheme(context) + .small + .copyWith(color: getEnteColorScheme(context).textFaint), + ) + : SizedBox.fromSize( + size: const Size.square(14), + child: CircularProgressIndicator( + strokeWidth: 2, + color: getEnteColorScheme(context).strokeMuted, + ), + ), + trailingIcon: err != null ? Icons.error_outline_outlined : null, + trailingIconIsMuted: err != null, borderRadius: 8, menuItemColor: getEnteColorScheme(context).fillFaint, isBottomBorderRadiusRemoved: widget.removeBottomRadius, @@ -93,7 +111,7 @@ class _PathStorageViewerState extends State { onDoubleTap: () async { if (widget.item.allowCacheClear && widget.enableDoubleTapClear) { await deleteDirectoryContents(widget.item.path); - _initLogs(); + _safeRefresh(); } }, ); diff --git a/lib/utils/directory_content.dart b/lib/utils/directory_content.dart index 8f8ca0192..f9fcd5965 100644 --- a/lib/utils/directory_content.dart +++ b/lib/utils/directory_content.dart @@ -1,27 +1,38 @@ import 'dart:io'; -import 'package:flutter/foundation.dart'; +class DirectoryStat { + final int subDirectoryCount; + final int size; + final int fileCount; -Future> directoryStat(String dirPath) async { + DirectoryStat(this.subDirectoryCount, this.size, this.fileCount); +} + +Future getDirectorySize(Directory directory) async { + int size = 0; + int subDirCount = 0; int fileCount = 0; - int totalSizeInBytes = 0; - final dir = Directory(dirPath); - try { - if (await dir.exists()) { - dir - .listSync(recursive: true, followLinks: false) - .forEach((FileSystemEntity entity) { - if (entity is File) { - fileCount++; - totalSizeInBytes += entity.lengthSync(); - } - }); - } - } catch (e) { - debugPrint(e.toString()); - } - return {'fileCount': fileCount, 'size': totalSizeInBytes}; + if (await directory.exists()) { + // Get a list of all the files and directories in the directory + final List entities = directory.listSync(); + // Iterate through the list of entities and add the sizes of the files to the total size + for (FileSystemEntity entity in entities) { + if (entity is File) { + size += (await File(entity.path).length()); + fileCount++; + } else if (entity is Directory) { + subDirCount++; + // If the entity is a directory, recursively calculate its size + final DirectoryStat subDirStat = + await getDirectorySize(Directory(entity.path)); + size += subDirStat.size; + subDirCount += subDirStat.subDirectoryCount; + fileCount += subDirStat.fileCount; + } + } + } + return DirectoryStat(subDirCount, size, fileCount); } Future deleteDirectoryContents(String directoryPath) async {