Files
noo/lib/widgets/settings/settings_action_bar.dart
T
ayushyaandClaude Sonnet 5 f9653bc0f2 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>
2026-09-29 03:49:24 -04:00

117 lines
3.9 KiB
Dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../models/selection_action.dart';
import '../../providers/settings_controller.dart';
import '../../theme/design_tokens.dart';
import '../noo/lists/noo_tab_order_row.dart';
import '../noo/noo_layout.dart';
import 'settings_section.dart';
/// Settings section: the priority order bulk actions (favorite, share,
/// download, ...) show in on the Files/Photos/Favorites multi-select
/// action bar. Every action stays available everywhere - this only decides
/// which ones land in `NooSelectionBar`'s fixed inline slots (3 mobile / 4
/// desktop, see its own doc comment) vs. behind its trailing "More" -
/// there's no pin/hide concept here the way Tabs has, so this is just a
/// reorder list, not a whole section of its own option rows.
class SettingsActionBarSection extends StatelessWidget {
const SettingsActionBarSection({super.key});
static const _subtitle =
'Drag to reorder - the first ones shown appear directly in the bar, the rest sit behind "More"';
void _handleReorder(SettingsController settings, int oldIndex, int newIndex) {
final order = List<SelectionActionKind>.from(settings.selectionActionOrder);
final kind = order.removeAt(oldIndex);
order.insert(newIndex, kind);
settings.setSelectionActionOrder(order);
}
@override
Widget build(BuildContext context) {
final settings = context.watch<SettingsController>();
final desktop = NooLayout.isDesktop(context);
final orderList = _ActionOrderList(
order: settings.selectionActionOrder,
onReorder: (oldIndex, newIndex) =>
_handleReorder(settings, oldIndex, newIndex),
);
final colors = context.nooColors;
if (!desktop) {
return SettingsSection(
title: 'Action bar',
subtitle: _subtitle,
children: [orderList],
);
}
return Container(
decoration: BoxDecoration(
color: colors.surface,
border: Border.all(color: colors.line),
borderRadius: BorderRadius.circular(NooRadii.card),
),
padding: const EdgeInsets.all(NooSpace.lg),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Action bar',
style: NooText.cardTitle.copyWith(color: colors.fg1),
),
const SizedBox(height: 4),
Text(_subtitle, style: NooText.meta.copyWith(color: colors.fg3)),
const SizedBox(height: NooSpace.md),
orderList,
],
),
);
}
}
/// The reorderable [NooTabOrderRow] stack for [SelectionActionKind]s - same
/// radius-20, line-divided card `settings_tabs.dart`'s `_TabOrderList`
/// draws, minus the pin toggle (`showPin: false`): there's nothing to
/// show/hide here, only an order.
class _ActionOrderList extends StatelessWidget {
final List<SelectionActionKind> order;
final void Function(int oldIndex, int newIndex) onReorder;
const _ActionOrderList({required this.order, required this.onReorder});
@override
Widget build(BuildContext context) {
final colors = context.nooColors;
final list = ReorderableListView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
buildDefaultDragHandles: false,
itemCount: order.length,
onReorderItem: onReorder,
itemBuilder: (context, index) {
final kind = order[index];
return Padding(
key: ValueKey(kind),
padding: EdgeInsets.only(top: index > 0 ? 1 : 0),
child: NooTabOrderRow(
icon: kind.icon,
label: kind.label,
showPin: false,
dragIndex: index,
),
);
},
);
return ClipRRect(
borderRadius: BorderRadius.circular(NooRadii.card),
child: DecoratedBox(
decoration: BoxDecoration(color: colors.line),
child: list,
),
);
}
}