Replaces the Material 3 screens with the Noo design system: warm neutrals, one violet accent, pill controls, Schibsted Grotesk/ Instrument Sans, Lucide icons, no gradients/shadows. - New lib/widgets/noo/ component kit (core, lists, files, media, nav, overlays) plus lib/theme/design_tokens.dart for the color/type/space/ radius/motion tokens. - Rebuilt the app shell (top/bottom bars, drawer, desktop sidebar and toolbar), every tab (Files/Offline, Photos, Favorites, Recent, Activity, Trash, Shares), Settings, the lock and login screens, the media viewer, search, the details/share sheets, and the share-upload and move/copy destination pickers. - Added a design canvas (linked from DESIGN_SYSTEM.md) covering the screens the spec didn't already describe, with matching Android and iOS chrome; wrote up the approved recipes into DESIGN_SYSTEM.md §4. - Removed now-dead legacy widgets (media_grid_tile, swipeable_item, sync_status_badge, selectable_thumbnail) and updated architecture.md/styling.md/standards.md to describe the new structure and component/testing conventions. - Added widget tests for the noo/ component kit. This is a UI-only rework: no provider/model/service behavior changed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
120 lines
3.6 KiB
Dart
120 lines
3.6 KiB
Dart
import 'package:file_picker/file_picker.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:lucide_icons_flutter/lucide_icons.dart';
|
|
import 'package:provider/provider.dart';
|
|
import '../providers/files_controller.dart';
|
|
import '../services/share_intent_service.dart';
|
|
import '../views/share_upload_view.dart';
|
|
import 'noo/core/noo_button.dart';
|
|
import 'noo/lists/noo_grouped_list.dart';
|
|
import 'noo/lists/noo_settings_row.dart';
|
|
import 'noo/overlays/noo_dialog.dart';
|
|
import 'noo/overlays/noo_sheet.dart';
|
|
import 'noo/overlays/noo_text_field.dart';
|
|
|
|
/// The Files tab's "+"/FAB action: upload a file or create a folder into
|
|
/// the current folder. Shared by `FilesView`'s own create button and
|
|
/// `MainShellView`'s FAB (the Noo Design System project's FAB component),
|
|
/// since both need to trigger the exact same flow.
|
|
void showCreateMenu(BuildContext context) {
|
|
showNooSheet(
|
|
context,
|
|
children: [
|
|
NooGroupedList(
|
|
children: [
|
|
NooSettingsRow(
|
|
icon: LucideIcons.upload,
|
|
label: const Text('Upload file'),
|
|
onTap: () {
|
|
Navigator.pop(context);
|
|
_pickAndUploadFile(context);
|
|
},
|
|
),
|
|
NooSettingsRow(
|
|
icon: LucideIcons.folder,
|
|
label: const Text('New folder'),
|
|
onTap: () {
|
|
Navigator.pop(context);
|
|
_showCreateFolderDialog(context);
|
|
},
|
|
),
|
|
],
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
void _showCreateFolderDialog(BuildContext context) {
|
|
final files = context.read<FilesController>();
|
|
final controller = TextEditingController();
|
|
|
|
Future<void> submit(BuildContext ctx) async {
|
|
final name = controller.text.trim();
|
|
if (name.isEmpty) return;
|
|
Navigator.pop(ctx);
|
|
final success = await files.createFolder(name);
|
|
if (ctx.mounted) {
|
|
ScaffoldMessenger.of(ctx).showSnackBar(
|
|
SnackBar(
|
|
content: Text(success ? 'Created folder $name' : 'Failed to create folder'),
|
|
behavior: SnackBarBehavior.floating,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
showNooDialog<void>(
|
|
context,
|
|
title: 'New folder',
|
|
children: [
|
|
NooTextField(
|
|
controller: controller,
|
|
placeholder: 'e.g. Finance',
|
|
autofocus: true,
|
|
onSurface: false,
|
|
onSubmitted: (_) => submit(context),
|
|
),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.end,
|
|
spacing: 10,
|
|
children: [
|
|
NooButton(
|
|
variant: NooButtonVariant.secondary,
|
|
onTap: () => Navigator.pop(context),
|
|
child: const Text('Cancel'),
|
|
),
|
|
NooButton(
|
|
variant: NooButtonVariant.primary,
|
|
onTap: () => submit(context),
|
|
child: const Text('Create'),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
// Mirrors `main.dart`'s `_handleSharedFiles` exactly, so picking a file via
|
|
// "+"/the FAB lands on the same destination-picker screen and background
|
|
// foreground-service upload as receiving one via Android's "Share to..."
|
|
// sheet does, rather than a separate in-app-only upload path.
|
|
Future<void> _pickAndUploadFile(BuildContext context) async {
|
|
final picked = await FilePicker.pickFiles();
|
|
if (picked.isEmpty) return;
|
|
final files = picked
|
|
.where((f) => f.path != null)
|
|
.map(
|
|
(f) => SharedFileRef(
|
|
uri: Uri.file(f.path!).toString(),
|
|
name: f.name,
|
|
size: f.lengthSync(),
|
|
),
|
|
)
|
|
.toList();
|
|
if (files.isEmpty || !context.mounted) return;
|
|
|
|
Navigator.of(
|
|
context,
|
|
).push(MaterialPageRoute(builder: (_) => ShareUploadView(files: files)));
|
|
}
|