diff --git a/lib/pages/full_post/comment_section.dart b/lib/pages/full_post/comment_section.dart index fb8a566..378da9a 100644 --- a/lib/pages/full_post/comment_section.dart +++ b/lib/pages/full_post/comment_section.dart @@ -13,9 +13,9 @@ import 'full_post_store.dart'; class _SortSelection { final IconData icon; - final String text; + final String term; - const _SortSelection(this.icon, this.text); + const _SortSelection(this.icon, this.term); } /// Manages comments section, sorts them @@ -34,8 +34,10 @@ class CommentSection extends StatelessWidget { Widget build(BuildContext context) { return ObserverBuilder( builder: (context, store) { + final fullPostView = store.fullPostView; + // error & spinner handling - if (store.fullPostView == null) { + if (fullPostView == null) { if (store.fullPostState.errorTerm != null) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 30), @@ -49,7 +51,7 @@ class CommentSection extends StatelessWidget { } else { return const Padding( padding: EdgeInsets.only(top: 40), - child: Center(child: CircularProgressIndicator()), + child: Center(child: CircularProgressIndicator.adaptive()), ); } } @@ -70,7 +72,7 @@ class CommentSection extends StatelessWidget { for (final e in sortPairs.entries) ListTile( leading: Icon(e.value.icon), - title: Text((e.value.text).tr(context)), + title: Text((e.value.term).tr(context)), trailing: store.sorting == e.key ? const Icon(Icons.check) : null, @@ -85,7 +87,7 @@ class CommentSection extends StatelessWidget { }, child: Row( children: [ - Text((sortPairs[store.sorting]!.text).tr(context)), + Text((sortPairs[store.sorting]!.term).tr(context)), const Icon(Icons.arrow_drop_down), ], ), @@ -95,7 +97,7 @@ class CommentSection extends StatelessWidget { ), ), // sorting menu goes here - if (store.fullPostView!.comments.isEmpty) + if (fullPostView.comments.isEmpty) const Padding( padding: EdgeInsets.symmetric(vertical: 50), child: Text( @@ -111,7 +113,7 @@ class CommentSection extends StatelessWidget { key: ValueKey(com), ), if (store.sorting == CommentSortType.chat) - for (final com in store.fullPostView!.comments) + for (final com in fullPostView.comments) CommentWidget.fromCommentView( com, detached: false, diff --git a/lib/pages/full_post/full_post.dart b/lib/pages/full_post/full_post.dart index 84ea5b9..3fa19f6 100644 --- a/lib/pages/full_post/full_post.dart +++ b/lib/pages/full_post/full_post.dart @@ -29,8 +29,10 @@ class FullPostPage extends StatelessWidget { final PostView? postView; final PostStore? postStore; - const FullPostPage({required int this.id, required String this.instanceHost}) - : postView = null, + const FullPostPage({ + required int this.id, + required String this.instanceHost, + }) : postView = null, postStore = null; const FullPostPage.fromPostView(PostView this.postView) : id = null, @@ -43,29 +45,52 @@ class FullPostPage extends StatelessWidget { @override Widget build(BuildContext context) { - return Provider( - create: (context) { - if (postStore != null) { - return FullPostStore.fromPostStore(postStore!); - } else if (postView != null) { - return FullPostStore.fromPostView(postView!); - } else { - return FullPostStore(instanceHost: instanceHost!, postId: id!); - } - }, - builder: (context, store) => AsyncStoreListener( - asyncStore: context.read().fullPostState, - child: AsyncStoreListener( - asyncStore: context.read().communityBlockingState, - successMessageBuilder: (context, asyncStore) { - final name = asyncStore.communityView.community.originPreferredName; - return '${asyncStore.blocked ? 'Blocked' : 'Unblocked'} $name'; - }, - child: const _FullPostPage(), - ), + return AsyncStoreListener( + asyncStore: context.read().fullPostState, + child: AsyncStoreListener( + asyncStore: context.read().communityBlockingState, + successMessageBuilder: (context, data) { + final name = data.communityView.community.originPreferredName; + return '${data.blocked ? 'Blocked' : 'Unblocked'} $name'; + }, + child: const _FullPostPage(), ), ); } + + static Jwt? _tryGetJwt(BuildContext context) { + final store = context.read(); + return context + .read() + .defaultUserDataFor(store.instanceHost) + ?.jwt; + } + + static Route route(int id, String instanceHost) => MaterialPageRoute( + builder: (context) => Provider( + create: (context) => + FullPostStore(instanceHost: instanceHost, postId: id) + ..refresh(_tryGetJwt(context)), + child: FullPostPage( + id: id, + instanceHost: instanceHost, + ), + ), + ); + + static Route fromPostViewRoute(PostView postView) => MaterialPageRoute( + builder: (context) => Provider( + create: (context) => FullPostStore.fromPostView(postView) + ..refresh(_tryGetJwt(context)), + child: FullPostPage.fromPostView(postView), + ), + ); + static Route fromPostStoreRoute(PostStore postStore) => MaterialPageRoute( + builder: (context) => Provider( + create: (context) => FullPostStore.fromPostStore(postStore) + ..refresh(_tryGetJwt(context)), + child: FullPostPage.fromPostStore(postStore)), + ); } /// Displays a post with its comment section @@ -76,102 +101,103 @@ class _FullPostPage extends HookWidget { Widget build(BuildContext context) { final scrollController = useScrollController(); - useMemoized(() { - final store = context.read(); - final token = context - .read() - .defaultUserDataFor(store.instanceHost) - ?.jwt; - store.refresh(token); - }, []); - final loggedInAction = useLoggedInAction(context.read().instanceHost); - return ObserverBuilder( - builder: (context, store) { - Future refresh() async { - unawaited(HapticFeedback.mediumImpact()); - await store.refresh(context - .read() - .defaultUserDataFor(store.instanceHost) - ?.jwt); - } + return AsyncStoreListener( + asyncStore: context.read().fullPostState, + child: AsyncStoreListener( + asyncStore: context.read().communityBlockingState, + successMessageBuilder: (context, data) { + final name = data.communityView.community.originPreferredName; + return '${data.blocked ? 'Blocked' : 'Unblocked'} $name'; + }, + child: ObserverBuilder( + builder: (context, store) { + Future refresh() async { + unawaited(HapticFeedback.mediumImpact()); + await store.refresh(context + .read() + .defaultUserDataFor(store.instanceHost) + ?.jwt); + } - if (store.postView == null) { - return Scaffold( - appBar: AppBar(), - body: Center( - child: (store.fullPostState.isLoading) - ? const CircularProgressIndicator.adaptive() - : FailedToLoad( - message: 'Post failed to load', refresh: refresh), - ), - ); - } + final post = store.postView; - // VARIABLES - - final post = store.postView!; - - sharePost() => share(post.post.apId, context: context); - - comment() async { - final newComment = await Navigator.of(context).push( - WriteComment.toPostRoute(post.post), - ); - - if (newComment != null) { - store.addComment(newComment); - } - } - - return Scaffold( - appBar: AppBar( - centerTitle: false, - title: RevealAfterScroll( - scrollController: scrollController, - after: 65, - child: Text( - post.community.originPreferredName, - overflow: TextOverflow.fade, + if (post == null) { + return Scaffold( + appBar: AppBar(), + body: Center( + child: (store.fullPostState.isLoading) + ? const CircularProgressIndicator.adaptive() + : FailedToLoad( + message: 'Post failed to load', refresh: refresh), ), - ), - actions: [ - IconButton(icon: Icon(shareIcon), onPressed: sharePost), - Provider( - create: (context) => store.postStore!, - child: const SavePostButton(), - ), - IconButton( - icon: Icon(moreIcon), - onPressed: () => showPostMoreMenu( - context: context, - postStore: store.postStore!, - fullPostStore: store, + ); + } + + // VARIABLES + + sharePost() => share(post.post.apId, context: context); + + comment() async { + final newComment = await Navigator.of(context).push( + WriteComment.toPostRoute(post.post), + ); + + if (newComment != null) { + store.addComment(newComment); + } + } + + return Scaffold( + appBar: AppBar( + centerTitle: false, + title: RevealAfterScroll( + scrollController: scrollController, + after: 65, + child: Text( + post.community.originPreferredName, + overflow: TextOverflow.fade, + ), ), + actions: [ + IconButton(icon: Icon(shareIcon), onPressed: sharePost), + Provider.value( + value: store.postStore!, + child: const SavePostButton(), + ), + IconButton( + icon: Icon(moreIcon), + onPressed: () => PostMoreMenuButton.show( + context: context, + postStore: store.postStore!, + fullPostStore: store, + ), + ), + ], ), - ], - ), - floatingActionButton: post.post.locked - ? null - : FloatingActionButton( - onPressed: loggedInAction((_) => comment()), - child: const Icon(Icons.comment), + floatingActionButton: post.post.locked + ? null + : FloatingActionButton( + onPressed: loggedInAction((_) => comment()), + child: const Icon(Icons.comment), + ), + body: RefreshIndicator( + onRefresh: refresh, + child: ListView( + controller: scrollController, + physics: const AlwaysScrollableScrollPhysics(), + children: [ + const SizedBox(height: 15), + PostTile.fromPostStore(store.postStore!), + const CommentSection(), + ], ), - body: RefreshIndicator( - onRefresh: refresh, - child: ListView( - controller: scrollController, - physics: const AlwaysScrollableScrollPhysics(), - children: [ - const SizedBox(height: 15), - PostTile.fromPostStore(store.postStore!), - const CommentSection(), - ], - ), - )); - }, + )); + }, + ), + ), ); } } diff --git a/lib/util/goto.dart b/lib/util/goto.dart index 5d735e0..72f6338 100644 --- a/lib/util/goto.dart +++ b/lib/util/goto.dart @@ -62,8 +62,8 @@ abstract class goToUser { goToUser.byId(context, personSafe.instanceHost, personSafe.id); } -void goToPost(BuildContext context, String instanceHost, int postId) => goTo( - context, (context) => FullPostPage(instanceHost: instanceHost, id: postId)); +void goToPost(BuildContext context, String instanceHost, int postId) => + Navigator.of(context).push(FullPostPage.route(postId, instanceHost)); void goToMedia(BuildContext context, String url) => Navigator.push( context, diff --git a/lib/widgets/post/post.dart b/lib/widgets/post/post.dart index 5483bfc..442fd77 100644 --- a/lib/widgets/post/post.dart +++ b/lib/widgets/post/post.dart @@ -1,13 +1,11 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:lemmy_api_client/v3.dart'; import 'package:provider/provider.dart'; import '../../pages/full_post/full_post.dart'; import '../../util/async_store_listener.dart'; import '../../util/extensions/api.dart'; -import '../../util/goto.dart'; import 'post_actions.dart'; import 'post_body.dart'; import 'post_info_section.dart'; @@ -29,8 +27,8 @@ class PostTile extends StatelessWidget { Widget build(BuildContext context) { return MultiProvider( providers: [ - Provider(create: (_) => postStore), - Provider(create: (_) => fullPost), + Provider.value(value: postStore), + Provider.value(value: fullPost), ], builder: (context, child) { return AsyncStoreListener( @@ -53,7 +51,7 @@ class PostTile extends StatelessWidget { } /// A post overview card -class _Post extends HookWidget { +class _Post extends StatelessWidget { const _Post(); @override @@ -72,10 +70,8 @@ class _Post extends HookWidget { ? null : () { final postStore = context.read(); - goTo( - context, - (context) => FullPostPage.fromPostStore(postStore), - ); + Navigator.of(context) + .push(FullPostPage.fromPostStoreRoute(postStore)); }, child: Material( type: MaterialType.transparency, diff --git a/lib/widgets/post/post_actions.dart b/lib/widgets/post/post_actions.dart index aaa23f3..91c70a2 100644 --- a/lib/widgets/post/post_actions.dart +++ b/lib/widgets/post/post_actions.dart @@ -22,7 +22,7 @@ class PostActions extends HookWidget { // assemble actions section return ObserverBuilder(builder: (context, store) { return Padding( - padding: const EdgeInsets.fromLTRB(10, 5, 10, 5), + padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), child: Row( children: [ const Icon(Icons.comment), diff --git a/lib/widgets/post/post_more_menu.dart b/lib/widgets/post/post_more_menu.dart index 85f0c8b..e19c836 100644 --- a/lib/widgets/post/post_more_menu.dart +++ b/lib/widgets/post/post_more_menu.dart @@ -17,18 +17,31 @@ import 'post_store.dart'; class PostMoreMenuButton extends StatelessWidget { const PostMoreMenuButton(); + static void show({ + required BuildContext context, + required PostStore postStore, + required FullPostStore? fullPostStore, + }) { + // TODO: add blocking! + showBottomModal( + context: context, + builder: (context) => + PostMoreMenu(postStore: postStore, fullPostStore: fullPostStore), + ); + } + @override Widget build(BuildContext context) { return Column( children: [ IconButton( - onPressed: () => showPostMoreMenu( + onPressed: () => show( context: context, postStore: context.read(), fullPostStore: null, ), icon: Icon(moreIcon), - padding: const EdgeInsets.all(0), + padding: EdgeInsets.zero, visualDensity: VisualDensity.compact, ) ], @@ -36,19 +49,6 @@ class PostMoreMenuButton extends StatelessWidget { } } -void showPostMoreMenu({ - required BuildContext context, - required PostStore postStore, - required FullPostStore? fullPostStore, -}) { - // TODO: add blocking! - showBottomModal( - context: context, - builder: (context) => - PostMoreMenu(postStore: postStore, fullPostStore: fullPostStore), - ); -} - class PostMoreMenu extends HookWidget { final PostStore postStore; final FullPostStore? fullPostStore;