Fix share copy-link, destination-picker filters, and type-filter UX

- SharesController's fetchShares() built NextcloudShare objects through
  its own thin inline parser instead of _shareFromJson, so url/token/
  permissions/expireDate were always null - a public link share could
  never show "Copy link" in the Shares tab. Reuses _shareFromJson.
- Upload/Move/Copy's destination picker hid External storage in its
  filter sheet (showStorageScope: false) unlike Files' own controls
  row, despite the design doc already calling for full parity.
- Files' and Photos' type filter (All/Files/Folders, All/Photos/Videos)
  now render as one consistent style in both filter sheets: every icon
  always shown, label only on the selected segment
  (NooSegmentedControl's new labelOnlySelected), replacing Files' old
  checkmark list and Photos' own always-labelled track.
- Fixes Photos' type filter only visually updating after closing and
  reopening the filter sheet - it lived on PhotosView's own State, so
  Listenable.merge([photos, files]) never rebuilt the sheet when it
  changed; a StatefulBuilder now gives it that trigger.
- Replaces Settings' trailing section jump rail with per-section
  collapsible cards (NooGroupedList's new collapsible param, expanded
  by default) - one less parallel way to navigate a long screen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-29 03:49:24 -04:00
co-authored by Claude Sonnet 5
parent 4e6477a3ae
commit f9653bc0f2
14 changed files with 417 additions and 326 deletions
+24 -39
View File
@@ -159,52 +159,37 @@ class FilesControlsRow extends StatelessWidget {
showNooSheet(
context,
children: [
// See `_showSortSheet`'s comment: without this, none of the
// checkmarks/toggles below would move until the sheet is closed
// and reopened.
// See `_showSortSheet`'s comment: without this, neither the type
// filter's selected segment nor the 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),
// 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,
labelOnlySelected: true,
value: files.filesTypeFilter,
onChanged: files.setFilesTypeFilter,
options: const [
NooSegmentOption(
value: FilesTypeFilter.all,
icon: LucideIcons.layoutGrid,
label: '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),
NooSegmentOption(
value: FilesTypeFilter.filesOnly,
icon: LucideIcons.file,
label: 'Files',
),
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),
NooSegmentOption(
value: FilesTypeFilter.foldersOnly,
icon: LucideIcons.folder,
label: 'Folders',
),
],
),