import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../core/constants.dart'; import '../../data/models/note.dart'; import '../../data/models/task.dart'; import '../../providers/notes_provider.dart'; import '../../providers/projects_provider.dart'; import '../../providers/tasks_provider.dart'; import '../../widgets/library_item_card.dart'; enum _LibraryFilter { all, notes, tasks, projects } enum _TaskStatusFilter { all, todo, inProgress, done } class LibraryScreen extends ConsumerStatefulWidget { const LibraryScreen({super.key}); @override ConsumerState createState() => _LibraryScreenState(); } class _LibraryScreenState extends ConsumerState { _LibraryFilter _filter = _LibraryFilter.all; _TaskStatusFilter _taskStatus = _TaskStatusFilter.all; bool _searchActive = false; String _searchQuery = ''; final _searchController = TextEditingController(); @override void dispose() { _searchController.dispose(); super.dispose(); } bool _matchesSearch(String text) { if (_searchQuery.isEmpty) return true; return text.toLowerCase().contains(_searchQuery.toLowerCase()); } @override Widget build(BuildContext context) { final theme = Theme.of(context); final notesAsync = ref.watch(notesProvider); final tasksAsync = ref.watch(tasksProvider); final projectsAsync = ref.watch(projectsProvider); return Scaffold( appBar: AppBar( title: _searchActive ? TextField( controller: _searchController, autofocus: true, decoration: const InputDecoration( hintText: 'Search…', border: InputBorder.none, isDense: true, ), onChanged: (q) => setState(() => _searchQuery = q), ) : Text('Library', style: theme.textTheme.titleLarge), actions: [ IconButton( icon: Icon(_searchActive ? Icons.close : Icons.search), onPressed: () => setState(() { _searchActive = !_searchActive; if (!_searchActive) { _searchQuery = ''; _searchController.clear(); } }), ), ], ), body: Column( children: [ // ── Filter pills ────────────────────────────────────────────────── SingleChildScrollView( scrollDirection: Axis.horizontal, padding: const EdgeInsets.fromLTRB(12, 8, 12, 4), child: Row( children: _LibraryFilter.values.map((f) { final label = switch (f) { _LibraryFilter.all => 'All', _LibraryFilter.notes => 'Notes', _LibraryFilter.tasks => 'Tasks', _LibraryFilter.projects => 'Projects', }; final selected = _filter == f; return Padding( padding: const EdgeInsets.only(right: 8), child: FilterChip( label: Text(label), selected: selected, onSelected: (_) => setState(() { _filter = f; _taskStatus = _TaskStatusFilter.all; }), selectedColor: theme.colorScheme.primary.withValues(alpha: 0.18), checkmarkColor: theme.colorScheme.primary, ), ); }).toList(), ), ), // ── Task status sub-filter (Tasks pill only) ─────────────────── if (_filter == _LibraryFilter.tasks) SingleChildScrollView( scrollDirection: Axis.horizontal, padding: const EdgeInsets.fromLTRB(12, 0, 12, 4), child: Row( children: _TaskStatusFilter.values.map((s) { final label = switch (s) { _TaskStatusFilter.all => 'All', _TaskStatusFilter.todo => 'To Do', _TaskStatusFilter.inProgress => 'In Progress', _TaskStatusFilter.done => 'Done', }; return Padding( padding: const EdgeInsets.only(right: 8), child: ChoiceChip( label: Text(label), selected: _taskStatus == s, onSelected: (_) => setState(() => _taskStatus = s), selectedColor: theme.colorScheme.secondary.withValues(alpha: 0.15), ), ); }).toList(), ), ), const Divider(height: 1), // ── Content ─────────────────────────────────────────────────────── Expanded( child: switch (_filter) { _LibraryFilter.notes => _buildNotesList(notesAsync), _LibraryFilter.tasks => _buildTasksList(tasksAsync), _LibraryFilter.projects => _buildProjectsList(projectsAsync), _LibraryFilter.all => _buildAllList(notesAsync, tasksAsync), }, ), ], ), floatingActionButton: FloatingActionButton( onPressed: () => _showCreateSheet(context), child: const Icon(Icons.add), ), ); } Widget _buildNotesList(AsyncValue> notesAsync) { return notesAsync.when( loading: () => const Center(child: CircularProgressIndicator()), error: (e, _) => Center(child: Text('Error: $e')), data: (notes) { final filtered = notes .where((n) => _matchesSearch(n.title) || _matchesSearch(n.body)) .toList(); if (filtered.isEmpty) { return const Center(child: Text('No notes found')); } return RefreshIndicator( onRefresh: () async => ref.invalidate(notesProvider), child: ListView.builder( itemCount: filtered.length, itemBuilder: (_, i) => NoteLibraryCard(note: filtered[i]), ), ); }, ); } Widget _buildTasksList(AsyncValue> tasksAsync) { return tasksAsync.when( loading: () => const Center(child: CircularProgressIndicator()), error: (e, _) => Center(child: Text('Error: $e')), data: (tasks) { var filtered = tasks.where((t) => _matchesSearch(t.title)).toList(); if (_taskStatus != _TaskStatusFilter.all) { final status = switch (_taskStatus) { _TaskStatusFilter.todo => TaskStatus.todo, _TaskStatusFilter.inProgress => TaskStatus.inProgress, _TaskStatusFilter.done => TaskStatus.done, _ => TaskStatus.todo, }; filtered = filtered.where((t) => t.status == status).toList(); } if (filtered.isEmpty) { return const Center(child: Text('No tasks found')); } return RefreshIndicator( onRefresh: () async => ref.invalidate(tasksProvider), child: ListView.builder( itemCount: filtered.length, itemBuilder: (_, i) => TaskLibraryCard(task: filtered[i]), ), ); }, ); } Widget _buildProjectsList(AsyncValue> projectsAsync) { return projectsAsync.when( loading: () => const Center(child: CircularProgressIndicator()), error: (e, _) => Center(child: Text('Error: $e')), data: (projects) { if (projects.isEmpty) { return const Center(child: Text('No projects')); } return RefreshIndicator( onRefresh: () async => ref.invalidate(projectsProvider), child: ListView.builder( itemCount: projects.length, itemBuilder: (_, i) => ProjectLibraryCard(project: projects[i]), ), ); }, ); } Widget _buildAllList( AsyncValue> notesAsync, AsyncValue> tasksAsync, ) { final notes = notesAsync.valueOrNull ?? []; final tasks = tasksAsync.valueOrNull ?? []; // Merge and sort by updatedAt desc final items = <(DateTime, Widget)>[]; for (final n in notes) { if (_matchesSearch(n.title) || _matchesSearch(n.body)) { items.add((n.updatedAt, NoteLibraryCard(note: n))); } } for (final t in tasks) { if (_matchesSearch(t.title)) { items.add((t.updatedAt, TaskLibraryCard(task: t))); } } items.sort((a, b) => b.$1.compareTo(a.$1)); if (notesAsync.isLoading || tasksAsync.isLoading) { return const Center(child: CircularProgressIndicator()); } if (items.isEmpty) { return const Center(child: Text('Nothing here yet')); } return RefreshIndicator( onRefresh: () async { ref.invalidate(notesProvider); ref.invalidate(tasksProvider); }, child: ListView.builder( itemCount: items.length, itemBuilder: (_, i) => items[i].$2, ), ); } void _showCreateSheet(BuildContext context) { showModalBottomSheet( context: context, builder: (_) => SafeArea( child: Column( mainAxisSize: MainAxisSize.min, children: [ ListTile( leading: const Icon(Icons.article_outlined), title: const Text('New note'), onTap: () { Navigator.pop(context); context.push(Routes.noteNew); }, ), ListTile( leading: const Icon(Icons.check_box_outlined), title: const Text('New task'), onTap: () { Navigator.pop(context); context.push(Routes.taskNew); }, ), ], ), ), ); } }