Filter sheets: 'Type' label above the type control; shorten 'All + ...' to 'All'

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Ayushya Amitabh
2026-10-05 22:38:37 -04:00
co-authored by Claude Sonnet 5.5
parent 3c60f8c709
commit 5fbac333d5
4 changed files with 108 additions and 75 deletions
+30 -26
View File
@@ -522,32 +522,36 @@ class _PhotosViewState extends State<PhotosView> {
// Same "icon always, label only when selected" pill as
// Files' own type filter - not a fully-labelled track, so
// the two screens' filter sheets look and behave the same.
NooSegmentedControl<_PhotoTypeFilter>(
fill: true,
onSurface: true,
labelOnlySelected: true,
value: _typeFilter,
onChanged: (filter) => setState(() {
_typeFilter = filter;
setSheetState(() {});
}),
options: const [
NooSegmentOption(
value: _PhotoTypeFilter.all,
icon: LucideIcons.layoutGrid,
label: 'All',
),
NooSegmentOption(
value: _PhotoTypeFilter.image,
icon: LucideIcons.image,
label: 'Photos',
),
NooSegmentOption(
value: _PhotoTypeFilter.video,
icon: LucideIcons.film,
label: 'Videos',
),
],
FilterSection(
icon: LucideIcons.layoutGrid,
title: 'Type',
child: NooSegmentedControl<_PhotoTypeFilter>(
fill: true,
onSurface: true,
labelOnlySelected: true,
value: _typeFilter,
onChanged: (filter) => setState(() {
_typeFilter = filter;
setSheetState(() {});
}),
options: const [
NooSegmentOption(
value: _PhotoTypeFilter.all,
icon: LucideIcons.layoutGrid,
label: 'All',
),
NooSegmentOption(
value: _PhotoTypeFilter.image,
icon: LucideIcons.image,
label: 'Photos',
),
NooSegmentOption(
value: _PhotoTypeFilter.video,
icon: LucideIcons.film,
label: 'Videos',
),
],
),
),
const SizedBox(height: 22),
NooGroupedList(
+27 -23
View File
@@ -171,29 +171,33 @@ class FilesControlsRow extends StatelessWidget {
// Same "icon always, label only when selected" pill as
// Photos' own type filter below - not a checkmark list, so
// the two screens' filter sheets look and behave the same.
NooSegmentedControl<FilesTypeFilter>(
fill: true,
onSurface: true,
labelOnlySelected: true,
value: files.filesTypeFilter,
onChanged: files.setFilesTypeFilter,
options: const [
NooSegmentOption(
value: FilesTypeFilter.all,
icon: LucideIcons.layoutGrid,
label: 'All',
),
NooSegmentOption(
value: FilesTypeFilter.filesOnly,
icon: LucideIcons.file,
label: 'Files',
),
NooSegmentOption(
value: FilesTypeFilter.foldersOnly,
icon: LucideIcons.folder,
label: 'Folders',
),
],
FilterSection(
icon: LucideIcons.layoutGrid,
title: 'Type',
child: NooSegmentedControl<FilesTypeFilter>(
fill: true,
onSurface: true,
labelOnlySelected: true,
value: files.filesTypeFilter,
onChanged: files.setFilesTypeFilter,
options: const [
NooSegmentOption(
value: FilesTypeFilter.all,
icon: LucideIcons.layoutGrid,
label: 'All',
),
NooSegmentOption(
value: FilesTypeFilter.filesOnly,
icon: LucideIcons.file,
label: 'Files',
),
NooSegmentOption(
value: FilesTypeFilter.foldersOnly,
icon: LucideIcons.folder,
label: 'Folders',
),
],
),
),
const SizedBox(height: 22),
HiddenFilesFilterRow(
+48 -23
View File
@@ -39,7 +39,7 @@ class HiddenFilesFilterRow extends StatelessWidget {
NooSegmentOption(
value: HiddenFilesFilter.include,
icon: LucideIcons.layers,
label: 'All + hidden',
label: 'All',
),
],
);
@@ -80,13 +80,48 @@ class StorageScopeRow extends StatelessWidget {
NooSegmentOption(
value: StorageScope.all,
icon: LucideIcons.layers,
label: 'All + external',
label: 'All',
),
],
);
}
}
/// An icon + title line above [child] - the shape every row of the Files/
/// Photos filter sheets shares, including their type (All/Files/Folders)
/// control, which lives in its own file.
class FilterSection extends StatelessWidget {
final IconData icon;
final String title;
final Widget child;
const FilterSection({
super.key,
required this.icon,
required this.title,
required this.child,
});
@override
Widget build(BuildContext context) {
final colors = context.nooColors;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(icon, size: 18, color: colors.fg2),
const SizedBox(width: 10),
Text(title, style: NooText.bodyL.copyWith(color: colors.fg1)),
],
),
const SizedBox(height: 10),
child,
],
);
}
}
class _FilterModeRow<T> extends StatelessWidget {
final IconData icon;
final String title;
@@ -104,27 +139,17 @@ class _FilterModeRow<T> extends StatelessWidget {
@override
Widget build(BuildContext context) {
final colors = context.nooColors;
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(icon, size: 18, color: colors.fg2),
const SizedBox(width: 10),
Text(title, style: NooText.bodyL.copyWith(color: colors.fg1)),
],
),
const SizedBox(height: 10),
NooSegmentedControl<T>(
fill: true,
onSurface: true,
labelOnlySelected: true,
value: value,
onChanged: onChanged,
options: options,
),
],
return FilterSection(
icon: icon,
title: title,
child: NooSegmentedControl<T>(
fill: true,
onSurface: true,
labelOnlySelected: true,
value: value,
onChanged: onChanged,
options: options,
),
);
}
}
+3 -3
View File
@@ -34,13 +34,13 @@ void main() {
await tester.tap(find.byIcon(LucideIcons.layers));
await tester.pumpAndSettle();
expect(value, HiddenFilesFilter.include);
expect(find.text('All + hidden'), findsOneWidget);
expect(find.text('All'), findsOneWidget);
},
);
});
group('StorageScopeRow', () {
testNooWidgets('offers cloud only / only external / all + external', (
testNooWidgets('offers cloud only / only external / all', (
tester,
theme,
c,
@@ -70,7 +70,7 @@ void main() {
await tester.tap(find.byIcon(LucideIcons.layers));
await tester.pumpAndSettle();
expect(value, StorageScope.all);
expect(find.text('All + external'), findsOneWidget);
expect(find.text('All'), findsOneWidget);
});
});
}