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:
@@ -369,6 +369,46 @@ void main() {
|
||||
const Size(78, 34),
|
||||
);
|
||||
});
|
||||
|
||||
testNooWidgets(
|
||||
'labelOnlySelected shows every icon but only the selected label',
|
||||
(tester, theme, c) async {
|
||||
var value = 'all';
|
||||
await pumpNoo(
|
||||
tester,
|
||||
StatefulBuilder(
|
||||
builder: (context, setState) => NooSegmentedControl<String>(
|
||||
fill: true,
|
||||
labelOnlySelected: true,
|
||||
value: value,
|
||||
onChanged: (v) => setState(() => value = v),
|
||||
options: const [
|
||||
NooSegmentOption(
|
||||
value: 'all',
|
||||
icon: LucideIcons.layoutGrid,
|
||||
label: 'All',
|
||||
),
|
||||
NooSegmentOption(
|
||||
value: 'files',
|
||||
icon: LucideIcons.file,
|
||||
label: 'Files',
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
theme: theme,
|
||||
);
|
||||
expect(find.byIcon(LucideIcons.layoutGrid), findsOneWidget);
|
||||
expect(find.byIcon(LucideIcons.file), findsOneWidget);
|
||||
expect(find.text('All'), findsOneWidget);
|
||||
expect(find.text('Files'), findsNothing);
|
||||
|
||||
await tester.tap(find.byIcon(LucideIcons.file));
|
||||
await tester.pump();
|
||||
expect(find.text('Files'), findsOneWidget);
|
||||
expect(find.text('All'), findsNothing);
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
group('NooToggle', () {
|
||||
|
||||
@@ -105,6 +105,69 @@ void main() {
|
||||
// Rows paint their own surface; the gaps show the list's line fill.
|
||||
expect(decorationOf(tester, find.byKey(const Key('r1'))).color, c.line);
|
||||
});
|
||||
|
||||
testNooWidgets('collapsible starts expanded, tapping the label hides '
|
||||
'and re-shows the card', (tester, theme, c) async {
|
||||
await pumpNoo(
|
||||
tester,
|
||||
SizedBox(
|
||||
width: 360,
|
||||
child: NooGroupedList(
|
||||
label: 'Appearance',
|
||||
collapsible: true,
|
||||
children: [
|
||||
Container(key: const Key('r1'), height: 52, color: c.surface),
|
||||
],
|
||||
),
|
||||
),
|
||||
theme: theme,
|
||||
);
|
||||
expect(find.byIcon(LucideIcons.chevronDown), findsOneWidget);
|
||||
expect(tester.getSize(find.byKey(const Key('r1'))).height, 52);
|
||||
AnimatedCrossFade crossFade() =>
|
||||
tester.widget<AnimatedCrossFade>(find.byType(AnimatedCrossFade));
|
||||
expect(crossFade().crossFadeState, CrossFadeState.showFirst);
|
||||
|
||||
await tester.tap(find.text('Appearance'));
|
||||
await tester.pump();
|
||||
expect(crossFade().crossFadeState, CrossFadeState.showSecond);
|
||||
expect(
|
||||
tester.widget<AnimatedRotation>(find.byType(AnimatedRotation)).turns,
|
||||
0,
|
||||
);
|
||||
|
||||
await tester.tap(find.text('Appearance'));
|
||||
await tester.pump();
|
||||
expect(crossFade().crossFadeState, CrossFadeState.showFirst);
|
||||
expect(
|
||||
tester.widget<AnimatedRotation>(find.byType(AnimatedRotation)).turns,
|
||||
0.5,
|
||||
);
|
||||
});
|
||||
|
||||
testNooWidgets('non-collapsible has no chevron and ignores label taps', (
|
||||
tester,
|
||||
theme,
|
||||
c,
|
||||
) async {
|
||||
await pumpNoo(
|
||||
tester,
|
||||
SizedBox(
|
||||
width: 360,
|
||||
child: NooGroupedList(
|
||||
label: 'Accounts',
|
||||
children: [
|
||||
Container(key: const Key('r1'), height: 52, color: c.surface),
|
||||
],
|
||||
),
|
||||
),
|
||||
theme: theme,
|
||||
);
|
||||
expect(find.byIcon(LucideIcons.chevronDown), findsNothing);
|
||||
await tester.tap(find.text('Accounts'));
|
||||
await tester.pumpAndSettle();
|
||||
expect(tester.getSize(find.byKey(const Key('r1'))).height, 52);
|
||||
});
|
||||
});
|
||||
|
||||
group('NooSelectionBar', () {
|
||||
|
||||
Reference in New Issue
Block a user