improved performance and battery usage on older devices

This commit is contained in:
2026-09-25 23:58:08 +02:00
parent ed8e52f475
commit 56a497985b
70 changed files with 1631 additions and 621 deletions
@@ -104,32 +104,43 @@ class FilesSearchResults extends StatelessWidget {
Widget _resultList(BuildContext context, List<CacheableFile> combined) {
final groups = _groupByParent(combined);
final orderedKeys = groups.keys.toList()..sort();
final items = <Widget>[];
for (final folder in orderedKeys) {
final segments = _segmentsOf(folder);
items.add(
_FolderHeader(
folder: folder,
onOpen: () {
onResultTap?.call();
AppRoutes.openFolder(context, segments);
},
),
);
for (final file in groups[folder]!) {
items.add(
FileElement(
file,
segments,
controller.retry,
highlight: controller.query,
),
// Flat (folder header | file) rows built lazily: results can run into
// the hundreds and arrive in several batches per query.
final rows = <(String, CacheableFile?)>[
for (final folder in orderedKeys) ...[
(folder, null),
for (final file in groups[folder]!) (folder, file),
],
];
return ListView.builder(
padding: EdgeInsets.zero,
itemCount: rows.length,
itemBuilder: (context, index) {
final (folder, file) = rows[index];
final segments = _segmentsOf(folder);
if (file == null) {
return _FolderHeader(
key: ValueKey('folder:$folder'),
folder: folder,
onOpen: () {
onResultTap?.call();
AppRoutes.openFolder(context, segments);
},
);
}
return FileElement(
file,
segments,
controller.retry,
key: ValueKey('file:${file.path}'),
highlight: controller.query,
);
}
}
return ListView(padding: EdgeInsets.zero, children: items);
},
);
}
static final RegExp _edgeSlashes = RegExp(r'^/+|/+$');
Map<String, List<CacheableFile>> _groupByParent(List<CacheableFile> files) {
final map = <String, List<CacheableFile>>{};
for (final file in files) {
@@ -139,7 +150,7 @@ class FilesSearchResults extends StatelessWidget {
}
String _parentOf(CacheableFile file) {
final stripped = file.path.replaceAll(RegExp(r'^/+|/+$'), '');
final stripped = file.path.replaceAll(_edgeSlashes, '');
final segments = stripped.split('/');
if (segments.length <= 1) return '/';
segments.removeLast();
@@ -147,7 +158,7 @@ class FilesSearchResults extends StatelessWidget {
}
List<String> _segmentsOf(String folder) {
final stripped = folder.replaceAll(RegExp(r'^/+|/+$'), '');
final stripped = folder.replaceAll(_edgeSlashes, '');
if (stripped.isEmpty) return const [];
return stripped.split('/');
}
@@ -156,7 +167,11 @@ class FilesSearchResults extends StatelessWidget {
class _FolderHeader extends StatelessWidget {
final String folder;
final VoidCallback onOpen;
const _FolderHeader({required this.folder, required this.onOpen});
const _FolderHeader({
required this.folder,
required this.onOpen,
super.key,
});
@override
Widget build(BuildContext context) {