import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:http/http.dart' as http; import 'package:news/ui/styles/colors.dart'; import 'package:news/ui/widgets/customTextLabel.dart'; import 'package:news/ui/widgets/errorContainerWidget.dart'; import 'package:news/ui/widgets/networkImage.dart'; import 'package:news/utils/ErrorMessageKeys.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:xml2json/xml2json.dart'; import 'dart:convert'; class RSSFeedDetailsScreen extends StatefulWidget { String feedUrl; RSSFeedDetailsScreen({Key? key, required this.feedUrl}) : super(key: key); @override _RSSFeedDetailsScreenState createState() => _RSSFeedDetailsScreenState(); static Route route(RouteSettings routeSettings) { final arguments = routeSettings.arguments as Map; return CupertinoPageRoute(builder: (_) => RSSFeedDetailsScreen(feedUrl: arguments['feedUrl'])); } } class _RSSFeedDetailsScreenState extends State { List _feedItems = []; bool isFeedLoaded = false; @override void initState() { super.initState(); fetchFeed(); } Widget buildFeedItem(Map item) { return GestureDetector( onTap: () => _launchURL(item['link'] ?? ''), child: Card( shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), margin: EdgeInsets.all(8.0), child: Padding( padding: EdgeInsets.all(16.0), child: Row( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.start, children: [ ((item.containsKey('image') && item['image'] != null) || (item.containsKey('url') && item['image']['url'] != null)) ? Padding( padding: const EdgeInsetsDirectional.only(end: 10.0), child: CustomNetworkImage( networkImageUrl: (item['image'] != null) ? item['image'] : item['image']['url'], height: MediaQuery.of(context).size.height * 0.13, width: MediaQuery.of(context).size.width * 0.23, fit: BoxFit.cover), ) : SizedBox.shrink(), Expanded( flex: 1, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ CustomTextLabel(text: item['title'] ?? 'No Title', maxLines: 2, textStyle: TextStyle(fontWeight: FontWeight.bold, fontSize: 16)), SizedBox(height: 8), CustomTextLabel(text: item['description'] ?? 'No Description', maxLines: 3, textStyle: TextStyle(color: borderColor)), SizedBox(height: 8), CustomTextLabel(text: item['pubDate'] ?? 'Unknown Date', textStyle: TextStyle(fontSize: 12, color: Colors.grey[500])) ], ), ), ], ), ), ), ); } Future _launchURL(String url) async { if (await canLaunch(url)) { await launch(url); } else { throw 'Could not launch $url'; } } Future fetchFeed() async { final url = widget.feedUrl; try { final response = await http.get(Uri.parse(url)); if (response.statusCode == 200) { final xml2json = Xml2Json(); xml2json.parse(response.body); final jsonString = xml2json.toParker(); final jsonData = jsonDecode(jsonString); _feedItems = jsonData['rss']['channel']['item'] ?? []; } else { throw Exception('Failed to load feed'); } } catch (e) {} isFeedLoaded = true; setState(() {}); } @override Widget build(BuildContext context) { return Scaffold( body: RefreshIndicator( onRefresh: fetchFeed, child: !isFeedLoaded ? Center(child: CircularProgressIndicator()) : _feedItems.isEmpty ? ErrorContainerWidget(errorMsg: ErrorMessageKeys.noDataMessage, onRetry: fetchFeed) : ListView.builder( itemCount: _feedItems.length, itemBuilder: (context, index) { return buildFeedItem(_feedItems[index]); }, )), ); } }