Files
noo/lib/widgets/create_menu.dart
T
ayushyaandClaude Opus 5.5 56784ef212 Rebuild UI on the Noo design system
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>
2026-09-26 01:51:58 -04:00

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)));
}