import 'package:flutter/material.dart'; import 'package:url_launcher/url_launcher.dart'; import '../models/news_article_model.dart'; import '../../../core/theme/app_theme.dart'; import '../../../core/widgets/status_badge.dart'; import 'finbert_sentiment_tab.dart'; class ArticleSentimentDialog extends StatefulWidget { final NewsArticleModel articleData; const ArticleSentimentDialog({ super.key, required this.articleData, }); @override State createState() => _ArticleSentimentDialogState(); } class _ArticleSentimentDialogState extends State with SingleTickerProviderStateMixin { late TabController _tabController; @override void initState() { super.initState(); _tabController = TabController(length: 2, vsync: this); } @override void dispose() { _tabController.dispose(); super.dispose(); } void _openOriginalSource() async { final urlStr = widget.articleData.sourceUrl; if (urlStr.isNotEmpty) { final uri = Uri.parse(urlStr); if (await canLaunchUrl(uri)) { await launchUrl(uri, mode: LaunchMode.externalApplication); } } } @override Widget build(BuildContext context) { final article = widget.articleData; final title = article.title.isNotEmpty ? article.title : 'Nachrichtenartikel'; final author = article.author.isNotEmpty ? article.author : 'Finlytic News'; final summary = article.summary; final sourceUrl = article.sourceUrl; final contentRaw = article.contentRaw; final publishedAt = "${article.publishedAt.day}.${article.publishedAt.month}.${article.publishedAt.year}"; final status = article.status.isNotEmpty ? article.status : 'Completed'; final rawSentiment = article.sentiment; final compoundScore = article.finbertResult?.score ?? article.sentimentScore; final Widget listBadge = rawSentiment.isNotEmpty ? StatusBadge.sentiment(rawSentiment.toUpperCase(), score: compoundScore) : StatusBadge( label: status.toUpperCase(), color: status.toLowerCase().contains('analyz') ? AppTheme.primaryEmerald : AppTheme.accentCyan, ); return Dialog( backgroundColor: AppTheme.cardSurface, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), side: BorderSide(color: AppTheme.glassBorder), ), child: Container( width: 650, height: 600, padding: const EdgeInsets.all(20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 16, color: Colors.white), maxLines: 2, overflow: TextOverflow.ellipsis, ), const SizedBox(height: 4), Text( 'Quelle: $author • $publishedAt', style: TextStyle(color: AppTheme.textMuted, fontSize: 12), ), ], ), ), const SizedBox(width: 8), listBadge, IconButton( onPressed: () => Navigator.pop(context), icon: const Icon(Icons.close, color: Colors.white70), ), ], ), const SizedBox(height: 12), Container( decoration: BoxDecoration( color: AppTheme.glassSurface, borderRadius: BorderRadius.circular(10), border: Border.all(color: AppTheme.glassBorder), ), child: TabBar( controller: _tabController, indicatorColor: AppTheme.primaryEmerald, labelColor: AppTheme.primaryEmerald, unselectedLabelColor: AppTheme.textMuted, indicatorSize: TabBarIndicatorSize.tab, tabs: const [ Tab(icon: Icon(Icons.article_outlined, size: 18), text: 'Artikel-Inhalt'), Tab(icon: Icon(Icons.psychology_outlined, size: 18), text: 'FinBERT Sentiment'), ], ), ), const SizedBox(height: 12), Expanded( child: TabBarView( controller: _tabController, children: [ SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (summary.isNotEmpty) ...[ const Text('Zusammenfassung:', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 13, color: Colors.white)), const SizedBox(height: 4), Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: AppTheme.glassSurface, borderRadius: BorderRadius.circular(8), ), child: Text(summary, style: const TextStyle(color: Colors.white70, fontSize: 13)), ), const SizedBox(height: 12), ], if (article.matchedAssets.isNotEmpty) ...[ const Text('Zugeordnete Assets:', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 13, color: Colors.white)), const SizedBox(height: 6), Wrap( spacing: 6, children: article.matchedAssets.map((asset) { return Chip( label: Text('${asset.symbol} (${asset.isin})', style: const TextStyle(fontSize: 11, color: Colors.white)), backgroundColor: AppTheme.glassSurface, side: BorderSide(color: AppTheme.glassBorder), ); }).toList(), ), const SizedBox(height: 12), ], const Text('Vollständiger Artikeltext:', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 13, color: Colors.white)), const SizedBox(height: 6), Text( contentRaw.isNotEmpty ? contentRaw : 'Kein vollständiger Text verfügbar.', style: const TextStyle(color: Colors.white70, fontSize: 13, height: 1.4), ), ], ), ), FinbertSentimentTab(article: article), ], ), ), const SizedBox(height: 12), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ if (sourceUrl.isNotEmpty) TextButton.icon( onPressed: _openOriginalSource, icon: const Icon(Icons.open_in_new, size: 16), label: const Text('Originalquelle im Browser öffnen'), style: TextButton.styleFrom(foregroundColor: AppTheme.accentCyan), ) else const SizedBox.shrink(), ElevatedButton( onPressed: () => Navigator.pop(context), style: ElevatedButton.styleFrom(backgroundColor: AppTheme.primaryEmerald, foregroundColor: Colors.black), child: const Text('Schließen'), ), ], ), ], ), ), ); } }