✨ Comment view
This commit is contained in:
		| @@ -48,13 +48,13 @@ class _ExploreScreenState extends State<ExploreScreen> { | |||||||
|       final result = |       final result = | ||||||
|           PaginationResult.fromJson(jsonDecode(utf8.decode(res.bodyBytes))); |           PaginationResult.fromJson(jsonDecode(utf8.decode(res.bodyBytes))); | ||||||
|       final isLastPage = (result.count - pageKey) < pageSize; |       final isLastPage = (result.count - pageKey) < pageSize; | ||||||
|  |       final items = | ||||||
|  |           result.data?.map((x) => Feed.fromJson(x)).toList() ?? List.empty(); | ||||||
|       if (isLastPage || result.data == null) { |       if (isLastPage || result.data == null) { | ||||||
|         paginationController.appendLastPage(feed); |         paginationController.appendLastPage(items); | ||||||
|       } else { |       } else { | ||||||
|         final feed = |         final nextPageKey = pageKey + items.length; | ||||||
|             result.data?.map((x) => Feed.fromJson(x)).toList() ?? List.empty(); |         paginationController.appendPage(items, nextPageKey); | ||||||
|         final nextPageKey = pageKey + feed.length; |  | ||||||
|         paginationController.appendPage(feed, nextPageKey); |  | ||||||
|       } |       } | ||||||
|     } else { |     } else { | ||||||
|       paginationController.error = utf8.decode(res.bodyBytes); |       paginationController.error = utf8.decode(res.bodyBytes); | ||||||
|   | |||||||
| @@ -3,12 +3,21 @@ import 'package:flutter_carousel_widget/flutter_carousel_widget.dart'; | |||||||
| import 'package:flutter_markdown/flutter_markdown.dart'; | import 'package:flutter_markdown/flutter_markdown.dart'; | ||||||
| import 'package:solaragent/models/feed.dart'; | import 'package:solaragent/models/feed.dart'; | ||||||
| import 'package:solaragent/widgets/image.dart'; | import 'package:solaragent/widgets/image.dart'; | ||||||
|  | import 'package:solaragent/widgets/posts/comments.dart'; | ||||||
|  |  | ||||||
| class FeedItem extends StatelessWidget { | class FeedItem extends StatelessWidget { | ||||||
|   final Feed item; |   final Feed item; | ||||||
|  |  | ||||||
|   const FeedItem({super.key, required this.item}); |   const FeedItem({super.key, required this.item}); | ||||||
|  |  | ||||||
|  |   void viewComments(BuildContext context) { | ||||||
|  |     showModalBottomSheet( | ||||||
|  |       context: context, | ||||||
|  |       isScrollControlled: true, | ||||||
|  |       builder: (context) => CommentListWidget(parent: item), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   bool hasAttachments() => |   bool hasAttachments() => | ||||||
|       item.attachments != null && item.attachments!.isNotEmpty; |       item.attachments != null && item.attachments!.isNotEmpty; | ||||||
|  |  | ||||||
| @@ -22,6 +31,7 @@ class FeedItem extends StatelessWidget { | |||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     return Column( |     return Column( | ||||||
|       children: [ |       children: [ | ||||||
|  |         // Author info | ||||||
|         Container( |         Container( | ||||||
|           color: Colors.grey[50], |           color: Colors.grey[50], | ||||||
|           child: ListTile( |           child: ListTile( | ||||||
| @@ -37,11 +47,13 @@ class FeedItem extends StatelessWidget { | |||||||
|             ), |             ), | ||||||
|           ), |           ), | ||||||
|         ), |         ), | ||||||
|  |         // Content | ||||||
|         Markdown( |         Markdown( | ||||||
|           data: item.content, |           data: item.content, | ||||||
|           shrinkWrap: true, |           shrinkWrap: true, | ||||||
|           physics: const NeverScrollableScrollPhysics(), |           physics: const NeverScrollableScrollPhysics(), | ||||||
|         ), |         ), | ||||||
|  |         // Attachments view | ||||||
|         hasAttachments() |         hasAttachments() | ||||||
|             ? Container( |             ? Container( | ||||||
|                 decoration: const BoxDecoration( |                 decoration: const BoxDecoration( | ||||||
| @@ -81,6 +93,23 @@ class FeedItem extends StatelessWidget { | |||||||
|                 ), |                 ), | ||||||
|               ) |               ) | ||||||
|             : Container(), |             : Container(), | ||||||
|  |         // Actions | ||||||
|  |         Container( | ||||||
|  |           padding: const EdgeInsets.symmetric(horizontal: 8), | ||||||
|  |           decoration: const BoxDecoration( | ||||||
|  |             border: | ||||||
|  |                 Border(top: BorderSide(width: 0.3, color: Color(0xffdedede))), | ||||||
|  |           ), | ||||||
|  |           child: Row( | ||||||
|  |             children: [ | ||||||
|  |               TextButton.icon( | ||||||
|  |                 icon: const Icon(Icons.comment), | ||||||
|  |                 label: Text(item.commentCount.toString()), | ||||||
|  |                 onPressed: () => viewComments(context), | ||||||
|  |               ) | ||||||
|  |             ], | ||||||
|  |           ), | ||||||
|  |         ), | ||||||
|       ], |       ], | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|   | |||||||
							
								
								
									
										98
									
								
								lib/widgets/posts/comments.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								lib/widgets/posts/comments.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,98 @@ | |||||||
|  | import 'dart:convert'; | ||||||
|  |  | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:http/http.dart'; | ||||||
|  | import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; | ||||||
|  | import 'package:solaragent/models/feed.dart'; | ||||||
|  | import 'package:solaragent/models/pagination.dart'; | ||||||
|  | import 'package:solaragent/widgets/feed.dart'; | ||||||
|  |  | ||||||
|  | class CommentListWidget extends StatefulWidget { | ||||||
|  |   final Feed parent; | ||||||
|  |  | ||||||
|  |   const CommentListWidget({super.key, required this.parent}); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   State<CommentListWidget> createState() => _CommentListWidgetState(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class _CommentListWidgetState extends State<CommentListWidget> { | ||||||
|  |   static const pageSize = 5; | ||||||
|  |  | ||||||
|  |   final client = Client(); | ||||||
|  |  | ||||||
|  |   final PagingController<int, Feed> paginationController = | ||||||
|  |       PagingController(firstPageKey: 0); | ||||||
|  |  | ||||||
|  |   List<Feed> feed = List.empty(); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   void initState() { | ||||||
|  |     super.initState(); | ||||||
|  |     paginationController.addPageRequestListener((pageKey) { | ||||||
|  |       pullFeed(pageKey); | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Future<void> pullFeed(int pageKey) async { | ||||||
|  |     var offset = pageKey; | ||||||
|  |     var take = pageSize; | ||||||
|  |  | ||||||
|  |     var dataset = "${widget.parent.modelType}s"; | ||||||
|  |     var alias = widget.parent.alias; | ||||||
|  |  | ||||||
|  |     var uri = Uri.parse( | ||||||
|  |       'https://co.solsynth.dev/api/p/$dataset/$alias/comments?take=$take&offset=$offset', | ||||||
|  |     ); | ||||||
|  |  | ||||||
|  |     var res = await client.get(uri); | ||||||
|  |     if (res.statusCode == 200) { | ||||||
|  |       final result = | ||||||
|  |           PaginationResult.fromJson(jsonDecode(utf8.decode(res.bodyBytes))); | ||||||
|  |       final isLastPage = (result.count - pageKey) < pageSize; | ||||||
|  |       final items = | ||||||
|  |           result.data?.map((x) => Feed.fromJson(x)).toList() ?? List.empty(); | ||||||
|  |       if (isLastPage || result.data == null) { | ||||||
|  |         paginationController.appendLastPage(items); | ||||||
|  |       } else { | ||||||
|  |         final nextPageKey = pageKey + items.length; | ||||||
|  |         paginationController.appendPage(items, nextPageKey); | ||||||
|  |       } | ||||||
|  |     } else { | ||||||
|  |       paginationController.error = utf8.decode(res.bodyBytes); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return Column( | ||||||
|  |       children: [ | ||||||
|  |         Container( | ||||||
|  |           padding: const EdgeInsets.only(left: 10, right: 10, top: 20), | ||||||
|  |           child: ListTile( | ||||||
|  |             title: Text( | ||||||
|  |               'Comments', | ||||||
|  |               style: Theme.of(context).textTheme.headlineSmall, | ||||||
|  |             ), | ||||||
|  |           ), | ||||||
|  |         ), | ||||||
|  |         Expanded( | ||||||
|  |           child: PagedListView<int, Feed>( | ||||||
|  |             pagingController: paginationController, | ||||||
|  |             builderDelegate: PagedChildBuilderDelegate<Feed>( | ||||||
|  |               itemBuilder: (context, item, index) => FeedItem( | ||||||
|  |                 item: item, | ||||||
|  |               ), | ||||||
|  |             ), | ||||||
|  |           ), | ||||||
|  |         ), | ||||||
|  |       ], | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   void dispose() { | ||||||
|  |     paginationController.dispose(); | ||||||
|  |     super.dispose(); | ||||||
|  |   } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user