diff --git a/lib/screens/posts/comment_editor.dart b/lib/screens/posts/comment_editor.dart index 9c40e5f..e13a7e9 100644 --- a/lib/screens/posts/comment_editor.dart +++ b/lib/screens/posts/comment_editor.dart @@ -12,14 +12,14 @@ import 'package:solian/widgets/indent_wrapper.dart'; import 'package:solian/widgets/posts/attachment_editor.dart'; class CommentPostArguments { - final Post related; + final Post? related; final Post? editing; - CommentPostArguments({required this.related, this.editing}); + CommentPostArguments({this.related, this.editing}); } class CommentEditorScreen extends StatefulWidget { - final Post related; + final Post? related; final Post? editing; const CommentEditorScreen({super.key, required this.related, this.editing}); @@ -50,9 +50,10 @@ class _CommentEditorScreenState extends State { final auth = context.read(); if (!await auth.isAuthorized()) return; - final relatedDataset = '${widget.related.modelType}s'; + final alias = widget.related?.alias ?? 'not-found'; + final relatedDataset = '${widget.related?.modelType ?? 'comment'}s'; final uri = widget.editing == null - ? getRequestUri('interactive', '/api/p/$relatedDataset/${widget.related.alias}/comments') + ? getRequestUri('interactive', '/api/p/$relatedDataset/$alias/comments') : getRequestUri('interactive', '/api/p/comments/${widget.editing!.id}'); final req = Request(widget.editing == null ? "POST" : "PUT", uri); diff --git a/lib/widgets/common_wrapper.dart b/lib/widgets/common_wrapper.dart index 7dd12dc..024ce5f 100644 --- a/lib/widgets/common_wrapper.dart +++ b/lib/widgets/common_wrapper.dart @@ -3,18 +3,29 @@ import 'package:solian/widgets/navigation_drawer.dart'; class LayoutWrapper extends StatelessWidget { final Widget? child; + final Widget? floatingActionButton; + final List? appBarActions; + final bool? noSafeArea; final String title; - const LayoutWrapper({super.key, this.child, required this.title}); + const LayoutWrapper({ + super.key, + this.child, + required this.title, + this.floatingActionButton, + this.appBarActions, + this.noSafeArea, + }); @override Widget build(BuildContext context) { + final content = child ?? Container(); + return Scaffold( + appBar: AppBar(title: Text(title), actions: appBarActions), + floatingActionButton: floatingActionButton, drawer: const SolianNavigationDrawer(), - appBar: AppBar(title: Text(title)), - body: SafeArea( - child: child ?? Container(), - ), + body: (noSafeArea ?? false) ? content : SafeArea(child: content), ); } } diff --git a/lib/widgets/indent_wrapper.dart b/lib/widgets/indent_wrapper.dart index 4029f2e..8bc44b5 100644 --- a/lib/widgets/indent_wrapper.dart +++ b/lib/widgets/indent_wrapper.dart @@ -1,15 +1,19 @@ import 'package:flutter/material.dart'; +import 'package:solian/widgets/common_wrapper.dart'; import 'package:solian/widgets/navigation_drawer.dart'; -class IndentWrapper extends StatelessWidget { - final Widget? child; - final Widget? floatingActionButton; - final List? appBarActions; +class IndentWrapper extends LayoutWrapper { final bool? hideDrawer; - final bool? noSafeArea; - final String title; - const IndentWrapper({super.key, this.child, required this.title, this.floatingActionButton, this.appBarActions, this.hideDrawer, this.noSafeArea}); + const IndentWrapper({ + super.key, + super.child, + required super.title, + super.floatingActionButton, + super.appBarActions, + this.hideDrawer, + super.noSafeArea, + }) : super(); @override Widget build(BuildContext context) { diff --git a/lib/widgets/posts/item.dart b/lib/widgets/posts/item.dart index d2b7242..4339fb0 100644 --- a/lib/widgets/posts/item.dart +++ b/lib/widgets/posts/item.dart @@ -1,5 +1,10 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/painting.dart'; +import 'package:flutter/widgets.dart'; +import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; import 'package:solian/models/post.dart'; +import 'package:solian/widgets/posts/comment_list.dart'; import 'package:solian/widgets/posts/content/article.dart'; import 'package:solian/widgets/posts/content/attachment.dart'; import 'package:solian/widgets/posts/content/moment.dart'; @@ -38,6 +43,36 @@ class _PostItemState extends State { ); } + void viewComments(BuildContext context) { + final PagingController commentPaging = + PagingController(firstPageKey: 0); + + showModalBottomSheet( + context: context, + builder: (context) { + return Column( + children: [ + CommentListHeader( + related: widget.item, + paging: commentPaging, + ), + Expanded( + child: CustomScrollView( + slivers: [ + CommentList( + related: widget.item, + dataset: '${widget.item.modelType}s', + paging: commentPaging, + ), + ], + ), + ), + ], + ); + }, + ); + } + Widget renderContent() { switch (widget.item.modelType) { case 'article': @@ -62,20 +97,36 @@ class _PostItemState extends State { } Widget renderReactions() { + const density = VisualDensity(horizontal: -4, vertical: -2); + return Container( height: 48, padding: const EdgeInsets.only(top: 8, left: 4, right: 4), - child: ReactionList( - item: widget.item, - reactionList: reactionList, - onReact: (symbol, changes) { - setState(() { - if (!reactionList!.containsKey(symbol)) { - reactionList![symbol] = 0; - } - reactionList![symbol] += changes; - }); - }, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + ActionChip( + avatar: const Icon(Icons.comment), + label: Text(widget.item.commentCount.toString()), + tooltip: 'Comment', + onPressed: () => viewComments(context), + ), + const VerticalDivider(thickness: 0.3, indent: 8, endIndent: 8), + Expanded( + child: ReactionList( + item: widget.item, + reactionList: reactionList, + onReact: (symbol, changes) { + setState(() { + if (!reactionList!.containsKey(symbol)) { + reactionList![symbol] = 0; + } + reactionList![symbol] += changes; + }); + }, + ), + ), + ], ), ); } diff --git a/lib/widgets/posts/item_action.dart b/lib/widgets/posts/item_action.dart index 5530ba0..31e2e74 100644 --- a/lib/widgets/posts/item_action.dart +++ b/lib/widgets/posts/item_action.dart @@ -4,6 +4,7 @@ import 'package:solian/models/post.dart'; import 'package:solian/providers/auth.dart'; import 'package:solian/router.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:solian/screens/posts/comment_editor.dart'; import 'package:solian/widgets/posts/item_deletion.dart'; class PostItemAction extends StatelessWidget { @@ -18,6 +19,31 @@ class PostItemAction extends StatelessWidget { this.onDelete, }); + void viewEditor() async { + bool ok = false; + switch (item.modelType) { + case 'article': + ok = await router.pushNamed( + 'posts.articles.editor', + extra: item, + ) as bool; + case 'moment': + ok = await router.pushNamed( + 'posts.moments.editor', + extra: item, + ) as bool; + case 'comment': + ok = await router.pushNamed( + 'posts.comments.editor', + extra: CommentPostArguments(editing: item), + ) as bool; + } + + if (ok == true && onUpdate != null) { + onUpdate!(); + } + } + @override Widget build(BuildContext context) { final auth = context.read(); @@ -43,15 +69,7 @@ class PostItemAction extends StatelessWidget { ListTile( leading: const Icon(Icons.edit), title: Text(AppLocalizations.of(context)!.edit), - onTap: () { - router - .pushNamed('posts.moments.editor', extra: item) - .then((did) { - if (did == true && onUpdate != null) { - onUpdate!(); - } - }); - }, + onTap: () => viewEditor(), ), ListTile( leading: const Icon(Icons.delete),