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 // Same "icon always, label only when selected" pill as
// Files' own type filter - not a fully-labelled track, so // Files' own type filter - not a fully-labelled track, so
// the two screens' filter sheets look and behave the same. // the two screens' filter sheets look and behave the same.
NooSegmentedControl<_PhotoTypeFilter>( FilterSection(
fill: true, icon: LucideIcons.layoutGrid,
onSurface: true, title: 'Type',
labelOnlySelected: true, child: NooSegmentedControl<_PhotoTypeFilter>(
value: _typeFilter, fill: true,
onChanged: (filter) => setState(() { onSurface: true,
_typeFilter = filter; labelOnlySelected: true,
setSheetState(() {}); value: _typeFilter,
}), onChanged: (filter) => setState(() {
options: const [ _typeFilter = filter;
NooSegmentOption( setSheetState(() {});
value: _PhotoTypeFilter.all, }),
icon: LucideIcons.layoutGrid, options: const [
label: 'All', NooSegmentOption(
), value: _PhotoTypeFilter.all,
NooSegmentOption( icon: LucideIcons.layoutGrid,
value: _PhotoTypeFilter.image, label: 'All',
icon: LucideIcons.image, ),
label: 'Photos', NooSegmentOption(
), value: _PhotoTypeFilter.image,
NooSegmentOption( icon: LucideIcons.image,
value: _PhotoTypeFilter.video, label: 'Photos',
icon: LucideIcons.film, ),
label: 'Videos', NooSegmentOption(
), value: _PhotoTypeFilter.video,
], icon: LucideIcons.film,
label: 'Videos',
),
],
),
), ),
const SizedBox(height: 22), const SizedBox(height: 22),
NooGroupedList( NooGroupedList(
+27 -23
View File
@@ -171,29 +171,33 @@ class FilesControlsRow extends StatelessWidget {
// Same "icon always, label only when selected" pill as // Same "icon always, label only when selected" pill as
// Photos' own type filter below - not a checkmark list, so // Photos' own type filter below - not a checkmark list, so
// the two screens' filter sheets look and behave the same. // the two screens' filter sheets look and behave the same.
NooSegmentedControl<FilesTypeFilter>( FilterSection(
fill: true, icon: LucideIcons.layoutGrid,
onSurface: true, title: 'Type',
labelOnlySelected: true, child: NooSegmentedControl<FilesTypeFilter>(
value: files.filesTypeFilter, fill: true,
onChanged: files.setFilesTypeFilter, onSurface: true,
options: const [ labelOnlySelected: true,
NooSegmentOption( value: files.filesTypeFilter,
value: FilesTypeFilter.all, onChanged: files.setFilesTypeFilter,
icon: LucideIcons.layoutGrid, options: const [
label: 'All', NooSegmentOption(
), value: FilesTypeFilter.all,
NooSegmentOption( icon: LucideIcons.layoutGrid,
value: FilesTypeFilter.filesOnly, label: 'All',
icon: LucideIcons.file, ),
label: 'Files', NooSegmentOption(
), value: FilesTypeFilter.filesOnly,
NooSegmentOption( icon: LucideIcons.file,
value: FilesTypeFilter.foldersOnly, label: 'Files',
icon: LucideIcons.folder, ),
label: 'Folders', NooSegmentOption(
), value: FilesTypeFilter.foldersOnly,
], icon: LucideIcons.folder,
label: 'Folders',
),
],
),
), ),
const SizedBox(height: 22), const SizedBox(height: 22),
HiddenFilesFilterRow( HiddenFilesFilterRow(
+48 -23
View File
@@ -39,7 +39,7 @@ class HiddenFilesFilterRow extends StatelessWidget {
NooSegmentOption( NooSegmentOption(
value: HiddenFilesFilter.include, value: HiddenFilesFilter.include,
icon: LucideIcons.layers, icon: LucideIcons.layers,
label: 'All + hidden', label: 'All',
), ),
], ],
); );
@@ -80,13 +80,48 @@ class StorageScopeRow extends StatelessWidget {
NooSegmentOption( NooSegmentOption(
value: StorageScope.all, value: StorageScope.all,
icon: LucideIcons.layers, 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 { class _FilterModeRow<T> extends StatelessWidget {
final IconData icon; final IconData icon;
final String title; final String title;
@@ -104,27 +139,17 @@ class _FilterModeRow<T> extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final colors = context.nooColors; return FilterSection(
return Column( icon: icon,
crossAxisAlignment: CrossAxisAlignment.start, title: title,
children: [ child: NooSegmentedControl<T>(
Row( fill: true,
children: [ onSurface: true,
Icon(icon, size: 18, color: colors.fg2), labelOnlySelected: true,
const SizedBox(width: 10), value: value,
Text(title, style: NooText.bodyL.copyWith(color: colors.fg1)), onChanged: onChanged,
], options: options,
), ),
const SizedBox(height: 10),
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.tap(find.byIcon(LucideIcons.layers));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(value, HiddenFilesFilter.include); expect(value, HiddenFilesFilter.include);
expect(find.text('All + hidden'), findsOneWidget); expect(find.text('All'), findsOneWidget);
}, },
); );
}); });
group('StorageScopeRow', () { group('StorageScopeRow', () {
testNooWidgets('offers cloud only / only external / all + external', ( testNooWidgets('offers cloud only / only external / all', (
tester, tester,
theme, theme,
c, c,
@@ -70,7 +70,7 @@ void main() {
await tester.tap(find.byIcon(LucideIcons.layers)); await tester.tap(find.byIcon(LucideIcons.layers));
await tester.pumpAndSettle(); await tester.pumpAndSettle();
expect(value, StorageScope.all); expect(value, StorageScope.all);
expect(find.text('All + external'), findsOneWidget); expect(find.text('All'), findsOneWidget);
}); });
}); });
} }