Fix Trash/Shares list perf and live-update the Files sort/filter sheet
Trash and Shares built their mobile lists eagerly via NooGroupedList's own Column instead of a lazy sliver, so an account with hundreds of items made those tabs laggy - both now use a SliverList/ SliverChildBuilderDelegate instead, matching Files' own lazy list, while keeping the same one-continuous-card look via per-row corner rounding and a 1px divider. FilesControlsRow's sort/filter sheets also had a live-update bug: since showNooSheet's children are built once up front, tapping a row inside the open sheet updated the controller but the already-built checkmarks/toggles stayed stale until the sheet was closed and reopened. Wrapping each sheet's content in a ListenableBuilder fixes that. Also adds NooSelectionBar to styling.md's widget inventory table.
This commit is contained in:
@@ -93,33 +93,49 @@ class FilesControlsRow extends StatelessWidget {
|
||||
showNooSheet(
|
||||
context,
|
||||
children: [
|
||||
NooSegmentedControl<bool>(
|
||||
fill: true,
|
||||
value: files.sortAscendingFor(folderPath),
|
||||
onChanged: (asc) {
|
||||
if (asc != files.sortAscendingFor(folderPath)) {
|
||||
files.toggleSortOrderFor(folderPath);
|
||||
}
|
||||
},
|
||||
options: const [
|
||||
NooSegmentOption(value: true, icon: LucideIcons.arrowUp, label: 'Ascending'),
|
||||
NooSegmentOption(value: false, icon: LucideIcons.arrowDown, label: 'Descending'),
|
||||
],
|
||||
),
|
||||
NooGroupedList(
|
||||
children: [
|
||||
for (final field in FileSortField.values)
|
||||
NooSettingsRow(
|
||||
label: Text(sortFieldLabel(field)),
|
||||
trailing: field == files.sortFieldFor(folderPath)
|
||||
? Icon(LucideIcons.check, size: 18, color: context.nooColors.accentText)
|
||||
: null,
|
||||
onTap: () {
|
||||
files.setSortFieldFor(folderPath, field);
|
||||
Navigator.pop(context);
|
||||
// `showNooSheet`'s `children` are built once, up front - a bare
|
||||
// checkmark/value here would freeze at whatever it was when the
|
||||
// sheet opened, since tapping a row calls `files.set...` and
|
||||
// notifies the controller, not this already-built widget tree.
|
||||
// `ListenableBuilder` re-runs its `builder` on every
|
||||
// `FilesController.notifyListeners()` instead, so the selection
|
||||
// updates live - see the identical fix in `_showFilterSheet`.
|
||||
ListenableBuilder(
|
||||
listenable: files,
|
||||
builder: (context, _) => Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
NooSegmentedControl<bool>(
|
||||
fill: true,
|
||||
value: files.sortAscendingFor(folderPath),
|
||||
onChanged: (asc) {
|
||||
if (asc != files.sortAscendingFor(folderPath)) {
|
||||
files.toggleSortOrderFor(folderPath);
|
||||
}
|
||||
},
|
||||
options: const [
|
||||
NooSegmentOption(value: true, icon: LucideIcons.arrowUp, label: 'Ascending'),
|
||||
NooSegmentOption(value: false, icon: LucideIcons.arrowDown, label: 'Descending'),
|
||||
],
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 22),
|
||||
NooGroupedList(
|
||||
children: [
|
||||
for (final field in FileSortField.values)
|
||||
NooSettingsRow(
|
||||
label: Text(sortFieldLabel(field)),
|
||||
trailing: field == files.sortFieldFor(folderPath)
|
||||
? Icon(LucideIcons.check, size: 18, color: context.nooColors.accentText)
|
||||
: null,
|
||||
onTap: () {
|
||||
files.setSortFieldFor(folderPath, field);
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -129,54 +145,66 @@ class FilesControlsRow extends StatelessWidget {
|
||||
showNooSheet(
|
||||
context,
|
||||
children: [
|
||||
NooGroupedList(
|
||||
label: 'Show',
|
||||
children: [
|
||||
NooSettingsRow(
|
||||
label: const Text('Files and folders'),
|
||||
trailing: files.filesTypeFilter == FilesTypeFilter.all
|
||||
? Icon(LucideIcons.check, size: 18, color: context.nooColors.accentText)
|
||||
: null,
|
||||
onTap: () => files.setFilesTypeFilter(FilesTypeFilter.all),
|
||||
),
|
||||
NooSettingsRow(
|
||||
label: const Text('Files only'),
|
||||
trailing: files.filesTypeFilter == FilesTypeFilter.filesOnly
|
||||
? Icon(LucideIcons.check, size: 18, color: context.nooColors.accentText)
|
||||
: null,
|
||||
onTap: () => files.setFilesTypeFilter(FilesTypeFilter.filesOnly),
|
||||
),
|
||||
NooSettingsRow(
|
||||
label: const Text('Folders only'),
|
||||
trailing: files.filesTypeFilter == FilesTypeFilter.foldersOnly
|
||||
? Icon(LucideIcons.check, size: 18, color: context.nooColors.accentText)
|
||||
: null,
|
||||
onTap: () => files.setFilesTypeFilter(FilesTypeFilter.foldersOnly),
|
||||
),
|
||||
],
|
||||
),
|
||||
NooGroupedList(
|
||||
children: [
|
||||
NooSettingsRow(
|
||||
icon: LucideIcons.eye,
|
||||
label: const Text('Show hidden files'),
|
||||
trailing: NooToggle(
|
||||
checked: files.showHiddenFiles,
|
||||
onChanged: (_) => files.toggleShowHiddenFiles(),
|
||||
),
|
||||
),
|
||||
if (showStorageScope)
|
||||
NooSettingsRow(
|
||||
icon: LucideIcons.hardDrive,
|
||||
label: const Text('External storage'),
|
||||
trailing: NooToggle(
|
||||
checked: files.storageScope == StorageScope.external,
|
||||
onChanged: (external) => files.setStorageScope(
|
||||
external ? StorageScope.external : StorageScope.cloud,
|
||||
// See `_showSortSheet`'s comment: without this, none of the
|
||||
// checkmarks/toggles below would move until the sheet is closed
|
||||
// and reopened.
|
||||
ListenableBuilder(
|
||||
listenable: files,
|
||||
builder: (context, _) => Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
NooGroupedList(
|
||||
label: 'Show',
|
||||
children: [
|
||||
NooSettingsRow(
|
||||
label: const Text('Files and folders'),
|
||||
trailing: files.filesTypeFilter == FilesTypeFilter.all
|
||||
? Icon(LucideIcons.check, size: 18, color: context.nooColors.accentText)
|
||||
: null,
|
||||
onTap: () => files.setFilesTypeFilter(FilesTypeFilter.all),
|
||||
),
|
||||
),
|
||||
NooSettingsRow(
|
||||
label: const Text('Files only'),
|
||||
trailing: files.filesTypeFilter == FilesTypeFilter.filesOnly
|
||||
? Icon(LucideIcons.check, size: 18, color: context.nooColors.accentText)
|
||||
: null,
|
||||
onTap: () => files.setFilesTypeFilter(FilesTypeFilter.filesOnly),
|
||||
),
|
||||
NooSettingsRow(
|
||||
label: const Text('Folders only'),
|
||||
trailing: files.filesTypeFilter == FilesTypeFilter.foldersOnly
|
||||
? Icon(LucideIcons.check, size: 18, color: context.nooColors.accentText)
|
||||
: null,
|
||||
onTap: () => files.setFilesTypeFilter(FilesTypeFilter.foldersOnly),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 22),
|
||||
NooGroupedList(
|
||||
children: [
|
||||
NooSettingsRow(
|
||||
icon: LucideIcons.eye,
|
||||
label: const Text('Show hidden files'),
|
||||
trailing: NooToggle(
|
||||
checked: files.showHiddenFiles,
|
||||
onChanged: (_) => files.toggleShowHiddenFiles(),
|
||||
),
|
||||
),
|
||||
if (showStorageScope)
|
||||
NooSettingsRow(
|
||||
icon: LucideIcons.hardDrive,
|
||||
label: const Text('External storage'),
|
||||
trailing: NooToggle(
|
||||
checked: files.storageScope == StorageScope.external,
|
||||
onChanged: (external) => files.setStorageScope(
|
||||
external ? StorageScope.external : StorageScope.cloud,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user