import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../core/exceptions.dart'; import '../../providers/api_client_provider.dart'; import '../../providers/notes_provider.dart'; import '../../providers/tasks_provider.dart'; class QuickCaptureScreen extends ConsumerStatefulWidget { const QuickCaptureScreen({super.key}); @override ConsumerState createState() => _QuickCaptureScreenState(); } class _QuickCaptureScreenState extends ConsumerState { final _controller = TextEditingController(); final _focusNode = FocusNode(); bool _loading = false; @override void dispose() { _controller.dispose(); _focusNode.dispose(); super.dispose(); } Future _send() async { final text = _controller.text.trim(); if (text.isEmpty) return; setState(() => _loading = true); try { final result = await ref.read(quickCaptureApiProvider).capture(text); // Invalidate the relevant provider so the list screen re-fetches. switch (result.type) { case 'note': ref.invalidate(notesProvider); case 'task': case 'todo': ref.invalidate(tasksProvider); } if (mounted) { // Use the server's human-readable message if available, else compose one. final msg = result.message.isNotEmpty ? result.message : '${_typeLabel(result.type)} created: ${result.title}'; ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(msg), behavior: SnackBarBehavior.floating, ), ); context.pop(); } } on AppException catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(e.message), behavior: SnackBarBehavior.floating, ), ); } } finally { if (mounted) setState(() => _loading = false); } } String _typeLabel(String type) => switch (type) { 'note' => 'Note', 'task' => 'Task', 'event' => 'Event', 'todo' => 'To-do', _ => type, }; @override Widget build(BuildContext context) { final theme = Theme.of(context); return Scaffold( appBar: AppBar(title: const Text('Quick Capture')), body: Padding( padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text( 'What\'s on your mind?', style: theme.textTheme.titleMedium, ), const SizedBox(height: 4), Text( 'Describe a note, task, event, or research item — Fabled will figure out the rest.', style: theme.textTheme.bodySmall?.copyWith( color: theme.colorScheme.onSurfaceVariant, ), ), const SizedBox(height: 16), TextField( controller: _controller, focusNode: _focusNode, autofocus: true, enabled: !_loading, maxLines: 6, minLines: 3, keyboardType: TextInputType.multiline, decoration: InputDecoration( hintText: 'e.g. "Remind me to call the dentist next Monday" or "Note: project meeting went well, key points were..."', border: const OutlineInputBorder(), alignLabelWithHint: true, suffixIcon: _controller.text.isNotEmpty ? IconButton( icon: const Icon(Icons.clear), onPressed: () { _controller.clear(); setState(() {}); }, ) : null, ), onChanged: (_) => setState(() {}), ), const SizedBox(height: 16), FilledButton.icon( onPressed: (_loading || _controller.text.trim().isEmpty) ? null : _send, icon: _loading ? const SizedBox( width: 18, height: 18, child: CircularProgressIndicator( strokeWidth: 2, color: Colors.white, ), ) : const Icon(Icons.auto_awesome), label: Text(_loading ? 'Processing...' : 'Capture'), ), ], ), ), ); } }