import 'package:flutter/material.dart'; import 'package:lucide_icons/lucide_icons.dart'; import 'package:go_router/go_router.dart'; import '../data/local/database.dart'; import '../data/models/knowledge_item.dart'; import 'pending_sync_badge.dart'; class KnowledgeItemCard extends StatelessWidget { final KnowledgeItem item; const KnowledgeItemCard({super.key, required this.item}); String get _pendingDomain => item.noteType == 'task' ? kSyncDomainTasks : kSyncDomainNotes; IconData get _icon => switch (item.noteType) { 'person' => LucideIcons.user, 'place' => LucideIcons.mapPin, 'list' => LucideIcons.listChecks, 'task' => LucideIcons.checkCircle2, _ => LucideIcons.fileText, }; Color _statusColor(BuildContext context) { if (item.noteType != 'task') return Theme.of(context).colorScheme.primary; return switch (item.status) { 'done' => Colors.green, 'in_progress' => Colors.orange, 'cancelled' => Colors.grey, _ => Theme.of(context).colorScheme.primary, }; } String? get _subtitle { if (item.noteType == 'task') { if (item.body.trim().isNotEmpty) { final preview = item.body.trim().replaceAll('\n', ' '); return preview.length > 200 ? '${preview.substring(0, 200)}…' : preview; } if (item.dueDate != null) return 'Due ${item.dueDate}'; return item.status; } if (item.body.trim().isEmpty) return null; final preview = item.body.trim().replaceAll('\n', ' '); return preview.length > 200 ? '${preview.substring(0, 200)}…' : preview; } void _onTap(BuildContext context) { if (item.noteType == 'task') { context.push('/tasks/${item.id}/edit'); } else { context.push('/notes/${item.id}'); } } @override Widget build(BuildContext context) { return ListTile( leading: Icon(_icon, color: _statusColor(context)), title: Row( children: [ Flexible( child: Text( item.title.isEmpty ? '(untitled)' : item.title, maxLines: 1, overflow: TextOverflow.ellipsis, ), ), PendingSyncBadge(domain: _pendingDomain, id: item.id), ], ), subtitle: _subtitle != null ? Text( _subtitle!, maxLines: 2, overflow: TextOverflow.ellipsis, style: Theme.of(context).textTheme.bodySmall, ) : null, trailing: item.tags.isNotEmpty ? _TagChips(tags: item.tags) : null, onTap: () => _onTap(context), ); } Widget buildGridCard(BuildContext context) { final scheme = Theme.of(context).colorScheme; final textTheme = Theme.of(context).textTheme; return Card( elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), side: BorderSide(color: scheme.outlineVariant), ), child: InkWell( borderRadius: BorderRadius.circular(10), onTap: () => _onTap(context), child: Padding( padding: const EdgeInsets.all(12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(_icon, size: 18, color: _statusColor(context)), const SizedBox(width: 8), Expanded( child: Text( item.title.isEmpty ? '(untitled)' : item.title, maxLines: 2, overflow: TextOverflow.ellipsis, style: textTheme.titleSmall ?.copyWith(fontWeight: FontWeight.w600), ), ), PendingSyncBadge(domain: _pendingDomain, id: item.id), ], ), if (_subtitle != null) ...[ const SizedBox(height: 8), Expanded( child: Text( _subtitle!, overflow: TextOverflow.ellipsis, maxLines: 4, style: textTheme.bodySmall?.copyWith( color: scheme.onSurfaceVariant, height: 1.4, ), ), ), ], if (item.tags.isNotEmpty) ...[ const Spacer(), _TagChips(tags: item.tags), ], ], ), ), ), ); } } class _TagChips extends StatelessWidget { final List tags; const _TagChips({required this.tags}); @override Widget build(BuildContext context) { final shown = tags.take(2).toList(); final extra = tags.length - shown.length; return Wrap( spacing: 4, children: [ for (final t in shown) Chip( label: Text(t, style: const TextStyle(fontSize: 10)), padding: EdgeInsets.zero, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, visualDensity: VisualDensity.compact, ), if (extra > 0) Chip( label: Text('+$extra', style: const TextStyle(fontSize: 10)), padding: EdgeInsets.zero, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, visualDensity: VisualDensity.compact, ), ], ); } }