- 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>
117 lines
3.9 KiB
Dart
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,
|
|
),
|
|
);
|
|
}
|
|
}
|