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:
@@ -1,11 +1,18 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:lucide_icons_flutter/lucide_icons.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import '../../models/nextcloud_item.dart';
|
||||
import '../../providers/item_operations.dart';
|
||||
import '../../providers/session_controller.dart';
|
||||
import '../../theme/design_tokens.dart';
|
||||
import '../noo/lists/noo_grouped_list.dart';
|
||||
import '../noo/media/noo_activity_item.dart';
|
||||
import '../noo/media/noo_photo_tile.dart';
|
||||
|
||||
/// Per-file activity feed — same list-item look as the account-wide
|
||||
/// Activity tab (activity_view.dart), scoped to a single item.
|
||||
/// Per-file activity feed - the same actor/verb/tail mapping and
|
||||
/// avatar-palette convention as the account-wide Activity tab
|
||||
/// (`activity_view.dart`), scoped to a single item.
|
||||
class DetailsActivityTab extends StatefulWidget {
|
||||
final NextcloudItem item;
|
||||
|
||||
@@ -36,107 +43,52 @@ class _DetailsActivityTabState extends State<DetailsActivityTab> {
|
||||
_requested = true;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => _load());
|
||||
}
|
||||
final theme = Theme.of(context);
|
||||
final colorScheme = theme.colorScheme;
|
||||
final colors = context.nooColors;
|
||||
final session = context.watch<SessionController>();
|
||||
|
||||
if (_isLoading) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
return const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 32),
|
||||
child: Center(child: CircularProgressIndicator()),
|
||||
);
|
||||
}
|
||||
if (_activities.isEmpty) {
|
||||
return Center(
|
||||
child: Text(
|
||||
'No recent activity',
|
||||
style: theme.textTheme.titleMedium?.copyWith(
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 32),
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(LucideIcons.activity, size: 40, color: colors.fg3),
|
||||
const SizedBox(height: NooSpace.sm),
|
||||
Text(
|
||||
'No recent activity',
|
||||
style: NooText.cardTitle.copyWith(fontSize: 16, color: colors.fg2),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return ListView.builder(
|
||||
padding: const EdgeInsets.fromLTRB(20, 12, 20, 24),
|
||||
itemCount: _activities.length,
|
||||
itemBuilder: (context, index) {
|
||||
final act = _activities[index];
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 12),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: colorScheme.surfaceContainerLow,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
border: Border.all(
|
||||
color: colorScheme.outlineVariant.withValues(alpha: 0.2),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(
|
||||
color: colorScheme.primaryContainer,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(
|
||||
act.icon,
|
||||
color: colorScheme.onPrimaryContainer,
|
||||
size: 20,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 14),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
act.title,
|
||||
style: theme.textTheme.titleMedium?.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
DateFormat.jm().format(act.timestamp),
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
fontSize: 11,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
act.subject,
|
||||
style: theme.textTheme.bodyMedium?.copyWith(
|
||||
color: colorScheme.onSurfaceVariant,
|
||||
fontSize: 13,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Text(
|
||||
'By ${act.author} • ${DateFormat.MMMd().format(act.timestamp)}',
|
||||
style: theme.textTheme.bodySmall?.copyWith(
|
||||
color: colorScheme.primary,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 11,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
return NooGroupedList(
|
||||
children: [
|
||||
for (final act in _activities)
|
||||
ColoredBox(
|
||||
color: colors.surface,
|
||||
child: NooActivityItem(
|
||||
actor: act.author,
|
||||
verb: act.title,
|
||||
tail: act.subject.isNotEmpty && act.subject != act.title
|
||||
? act.subject
|
||||
: null,
|
||||
time: DateFormat.yMMMd().add_jm().format(act.timestamp),
|
||||
avatarColor: NooPhotoTile.paletteColor(act.author.hashCode),
|
||||
currentUser:
|
||||
act.author.toLowerCase() == session.username.toLowerCase(),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user