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>
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
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)));
|
||||
}
|
||||
Reference in New Issue
Block a user