Files
noo/lib/widgets/breadcrumbs.dart
T
ayushyaandClaude Sonnet 5 d68cc43368 Add Trash/Shares/Recent tabs, file sharing, Details sheet, and rebrand to Noo
Major additions since the initial rebuild:
- New tabs: Trash, Shares, Recent, configurable tab visibility/order/default
- Nextcloud sharing: search users/teams, internal link, email shares,
  public links, "others with access" - in its own Share bottom sheet
- Details bottom sheet (Info/Versions/Activity) with a persistent peek
  panel in the media viewer, reachable from selection, swipe, and the
  media viewer
- Files/Photos: tap-and-hold multi-select with a sticky selection toolbar,
  swipe actions (favorite/delete/share), sticky sort/filter controls,
  list/grid views, breadcrumb chips, whole-account Photos view
- Media viewer: pinch/double-tap zoom on images, predictive-back support,
  fixed PDF zoom-out floor
- Settings: Material You theming incl. AMOLED black, configurable bottom
  bar tabs, swipe actions, media seek bar style, and folder-listing cache
  policy (never/periodic/manual) to cut down on refetching
- Login flow moved to an in-app Chrome Custom Tab with retry-tolerant
  polling
- Replaced ad hoc widgets with native Material 3 equivalents (toggle
  IconButtons, SliverAppBar selection toolbar, SearchBar, drag handles)
- Rebrand: app renamed to Noo throughout, package id -> dev.ayushya.noo,
  new adaptive launcher icon

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 22:44:42 -04:00

73 lines
2.4 KiB
Dart

import 'package:flutter/material.dart';
/// Tappable "Home / Folder / Sub-folder" trail shown whenever the user has
/// navigated below the root, in both the Files and Photos tabs.
class Breadcrumbs extends StatelessWidget {
final List<String> pathStack;
final ValueChanged<int> onTap;
const Breadcrumbs({super.key, required this.pathStack, required this.onTap});
String _labelFor(int index) {
if (index == 0) return 'Home';
final segments = pathStack[index]
.split('/')
.where((s) => s.isNotEmpty)
.toList();
return segments.isEmpty ? 'Home' : segments.last;
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final colorScheme = theme.colorScheme;
final lastIndex = pathStack.length - 1;
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
for (var i = 0; i < pathStack.length; i++) ...[
if (i > 0)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 2),
child: Icon(
Icons.chevron_right_rounded,
size: 16,
color: colorScheme.outlineVariant,
),
),
if (i == lastIndex)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Text(
_labelFor(i),
style: theme.textTheme.bodySmall?.copyWith(
fontWeight: FontWeight.w700,
color: colorScheme.onSurface,
),
),
)
else
// A chip's whole pill is the tap target (not just the text),
// so the previous plain-text crumbs were fiddly to hit.
ActionChip(
label: Text(_labelFor(i)),
labelStyle: theme.textTheme.bodySmall?.copyWith(
fontWeight: FontWeight.w600,
color: colorScheme.primary,
),
onPressed: () => onTap(i),
backgroundColor: colorScheme.surfaceContainerHigh,
side: BorderSide.none,
visualDensity: VisualDensity.compact,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
padding: const EdgeInsets.symmetric(horizontal: 4),
),
],
],
),
);
}
}