diff --git a/lib/data/api/briefing_api.dart b/lib/data/api/briefing_api.dart index e28b600..27e7c7e 100644 --- a/lib/data/api/briefing_api.dart +++ b/lib/data/api/briefing_api.dart @@ -70,6 +70,22 @@ class BriefingApi { } } + /// POST /api/briefing/articles/{itemId}/discuss body: {"conv_id": convId} + /// Injects the article as context and triggers LLM generation. + /// Returns the assistant_message_id of the generating placeholder. + Future discussArticle(int convId, int itemId) async { + try { + final response = await _dio.post( + '/api/briefing/articles/$itemId/discuss', + data: {'conv_id': convId}, + ); + final data = response.data as Map; + return data['assistant_message_id'] as int; + } on DioException catch (e) { + throw dioToApp(e); + } + } + /// DELETE /api/briefing/rss-reactions/{rssItemId} Future deleteRssReaction(int rssItemId) async { try { diff --git a/lib/screens/briefing/briefing_screen.dart b/lib/screens/briefing/briefing_screen.dart index 4ff546f..8b5bde0 100644 --- a/lib/screens/briefing/briefing_screen.dart +++ b/lib/screens/briefing/briefing_screen.dart @@ -93,6 +93,23 @@ class _BriefingScreenState extends ConsumerState } } + Future _handleDiscuss(int convId, int itemId) async { + try { + await ref.read(briefingProvider.notifier).discussArticle(convId, itemId); + } on AppException catch (e) { + if (mounted) { + ScaffoldMessenger.of(context) + .showSnackBar(SnackBar(content: Text(e.message))); + } + } catch (_) { + if (mounted) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Failed to start discussion.')), + ); + } + } + } + Future _handleReaction(int itemId, String reaction) async { final current = _reactions[itemId]; final next = current == reaction ? null : reaction; @@ -268,8 +285,10 @@ class _BriefingScreenState extends ConsumerState final msg = conv.messages[i]; return _BriefingMessageItem( message: msg, + convId: conv.id, reactions: _reactions, onReaction: _handleReaction, + onDiscuss: _handleDiscuss, ); }, ), @@ -370,13 +389,17 @@ class _BriefingScreenState extends ConsumerState /// and RSS reaction buttons below it (for assistant messages with metadata). class _BriefingMessageItem extends StatelessWidget { final Message message; + final int convId; final Map reactions; final void Function(int itemId, String reaction) onReaction; + final void Function(int convId, int itemId) onDiscuss; const _BriefingMessageItem({ required this.message, + required this.convId, required this.reactions, required this.onReaction, + required this.onDiscuss, }); @override @@ -388,11 +411,11 @@ class _BriefingMessageItem extends StatelessWidget { final bool hasWeatherKey = isAssistant && meta != null && meta.containsKey('weather'); final weatherData = hasWeatherKey ? meta['weather'] as Map? : null; - // RSS news cards + // RSS news cards — cap at 3 final rssItemsRaw = isAssistant && meta != null ? (meta['rss_items'] as List?)?.cast>() ?? [] : >[]; - final rssItems = rssItemsRaw.map(RssItemMeta.fromJson).toList(); + final rssItems = rssItemsRaw.map(RssItemMeta.fromJson).take(3).toList(); return Column( crossAxisAlignment: CrossAxisAlignment.stretch, @@ -408,6 +431,7 @@ class _BriefingMessageItem extends StatelessWidget { item: item, reaction: reactions[item.id], onReaction: onReaction, + onDiscuss: () => onDiscuss(convId, item.id), )).toList(), ), ), diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index bcdce0a..f06a07c 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -8,6 +8,7 @@ #include #include +#include #include void fl_register_plugins(FlPluginRegistry* registry) { @@ -17,6 +18,9 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) open_file_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "OpenFileLinuxPlugin"); open_file_linux_plugin_register_with_registrar(open_file_linux_registrar); + g_autoptr(FlPluginRegistrar) record_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "RecordLinuxPlugin"); + record_linux_plugin_register_with_registrar(record_linux_registrar); g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 8c4a3aa..641253b 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -5,6 +5,7 @@ list(APPEND FLUTTER_PLUGIN_LIST flutter_timezone open_file_linux + record_linux url_launcher_linux ) diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index bd01ad7..27878f5 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,18 +5,24 @@ import FlutterMacOS import Foundation +import audio_session import flutter_inappwebview_macos import flutter_timezone +import just_audio import open_file_mac import package_info_plus +import record_darwin import shared_preferences_foundation import url_launcher_macos func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin")) InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin")) FlutterTimezonePlugin.register(with: registry.registrar(forPlugin: "FlutterTimezonePlugin")) + JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin")) OpenFilePlugin.register(with: registry.registrar(forPlugin: "OpenFilePlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) + RecordPlugin.register(with: registry.registrar(forPlugin: "RecordPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) } diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index cb273b1..f1cac88 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -9,6 +9,7 @@ #include #include #include +#include #include void RegisterPlugins(flutter::PluginRegistry* registry) { @@ -18,6 +19,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("FlutterTimezonePluginCApi")); PermissionHandlerWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); + RecordWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("RecordWindowsPluginCApi")); UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); } diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 9474322..f53b4aa 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST flutter_inappwebview_windows flutter_timezone permission_handler_windows + record_windows url_launcher_windows )