Files
noo/lib/widgets/more_tabs_button.dart
T
ayushyaandClaude Sonnet 5 f2bba2914e
Build APK / build (push) Successful in 5m27s
Offline tab as Files view, automatic background sync, sync notifications
- Offline tab is now FilesView(offline: true) over a FolderBrowser interface
  (FilesController / OfflineController) sharing controls, tiles, thumbnails
- Synced files follow the Files Cache rule (default: refresh every 15 min):
  per-account WorkManager jobs, in-app timer, resume and pull triggers;
  root-etag shortcut skips full walks when nothing changed
- Single sync at a time (shared lock); logging out stops that account's sync
- Sync safety: PROPFIND failures skip the path instead of deleting local files
- Mirror empty folders and remove deleted ones; drop synced paths deleted on
  the server; missing local files are re-downloaded
- Notifications: silent per-account sync notifications, "Background sync
  notifications" setting, audible upload/download completion
- Files refresh in place (no spinner flash); retry after network returns
- Fix sync badges not updating (shared native status stream), "Sync off" on
  launch (eager providers), Files Cache section moved under Device Sync

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-21 18:06:55 -04:00

64 lines
2.3 KiB
Dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../models/app_tab.dart';
import '../providers/connectivity_controller.dart';
import '../providers/pick_controller.dart';
import '../providers/settings_controller.dart';
import 'app_tab_view_builder.dart';
/// Opens a tab that's currently hidden from the bottom nav bar as its own
/// standalone screen. Shown in every tab's toolbar (not just Files) so
/// hidden destinations stay reachable no matter which tab is active.
/// Always visible; dims/disables itself when nothing is hidden.
class MoreTabsButton extends StatelessWidget {
const MoreTabsButton({super.key});
@override
Widget build(BuildContext context) {
final pick = context.watch<PickController>();
final settings = context.watch<SettingsController>();
final connectivity = context.watch<ConnectivityController>();
// While picking (another app's GET_CONTENT request), MainShellView
// already restricts the bottom nav to Files/Photos - this button would
// otherwise be the one remaining way to reach a tab that isn't a valid
// pick source (Trash, Shares, ...), so it hides entirely rather than
// just disabling. Same idea while offline: every hidden tab needs a
// network request to show anything useful, so there's nothing this
// button could usefully open.
if (pick.isPicking || connectivity.isOffline) return const SizedBox.shrink();
return PopupMenuButton<AppTab>(
icon: const Icon(Icons.apps_rounded),
tooltip: 'More tabs',
enabled: settings.hiddenTabs.isNotEmpty,
onSelected: (tab) => _openHiddenTab(context, tab),
itemBuilder: (context) => [
for (final tab in settings.tabOrder.where(
(t) => settings.hiddenTabs.contains(t),
))
PopupMenuItem(
value: tab,
child: Row(
children: [
Icon(tab.icon, size: 20),
const SizedBox(width: 12),
Text(tab.label),
],
),
),
],
);
}
void _openHiddenTab(BuildContext context, AppTab tab) {
Navigator.push(
context,
MaterialPageRoute(
builder: (_) =>
Scaffold(body: buildAppTabView(tab, ScrollController())),
),
);
}
}