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:
co-authored by
Claude Sonnet 5.5
parent
3c60f8c709
commit
5fbac333d5
+30
-26
@@ -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(
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user