batch of changes adressing CR

comment_section.dart
* _SortSelection: text -> term
* assign fullPostView at the beggining of builder for later ease of use

full_post.dart
* use Providers in route methods since it makes the most sense
* merge _FPP & FPP to one widget
* assign postView earlier for ease of use
* Provider -> Provider.value

goto.dart
* switch goToPost to use Navigator with route instead of goTo

post_actions.dart
* padding fromLTRB -> symmetric

post_more_menu.dart
* turn showPostMoreMenu into a static method
* Provider -> Provider.value
* Hook -> Stateless
* goTo -> Navigator.push
This commit is contained in:
Filip Krawczyk 2021-10-18 01:11:04 +02:00
parent d223d71c59
commit a884f07860
6 changed files with 168 additions and 144 deletions

View File

@ -13,9 +13,9 @@ import 'full_post_store.dart';
class _SortSelection { class _SortSelection {
final IconData icon; 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 /// Manages comments section, sorts them
@ -34,8 +34,10 @@ class CommentSection extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ObserverBuilder<FullPostStore>( return ObserverBuilder<FullPostStore>(
builder: (context, store) { builder: (context, store) {
final fullPostView = store.fullPostView;
// error & spinner handling // error & spinner handling
if (store.fullPostView == null) { if (fullPostView == null) {
if (store.fullPostState.errorTerm != null) { if (store.fullPostState.errorTerm != null) {
return Padding( return Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 30), padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 30),
@ -49,7 +51,7 @@ class CommentSection extends StatelessWidget {
} else { } else {
return const Padding( return const Padding(
padding: EdgeInsets.only(top: 40), 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) for (final e in sortPairs.entries)
ListTile( ListTile(
leading: Icon(e.value.icon), leading: Icon(e.value.icon),
title: Text((e.value.text).tr(context)), title: Text((e.value.term).tr(context)),
trailing: store.sorting == e.key trailing: store.sorting == e.key
? const Icon(Icons.check) ? const Icon(Icons.check)
: null, : null,
@ -85,7 +87,7 @@ class CommentSection extends StatelessWidget {
}, },
child: Row( child: Row(
children: [ children: [
Text((sortPairs[store.sorting]!.text).tr(context)), Text((sortPairs[store.sorting]!.term).tr(context)),
const Icon(Icons.arrow_drop_down), const Icon(Icons.arrow_drop_down),
], ],
), ),
@ -95,7 +97,7 @@ class CommentSection extends StatelessWidget {
), ),
), ),
// sorting menu goes here // sorting menu goes here
if (store.fullPostView!.comments.isEmpty) if (fullPostView.comments.isEmpty)
const Padding( const Padding(
padding: EdgeInsets.symmetric(vertical: 50), padding: EdgeInsets.symmetric(vertical: 50),
child: Text( child: Text(
@ -111,7 +113,7 @@ class CommentSection extends StatelessWidget {
key: ValueKey(com), key: ValueKey(com),
), ),
if (store.sorting == CommentSortType.chat) if (store.sorting == CommentSortType.chat)
for (final com in store.fullPostView!.comments) for (final com in fullPostView.comments)
CommentWidget.fromCommentView( CommentWidget.fromCommentView(
com, com,
detached: false, detached: false,

View File

@ -29,8 +29,10 @@ class FullPostPage extends StatelessWidget {
final PostView? postView; final PostView? postView;
final PostStore? postStore; final PostStore? postStore;
const FullPostPage({required int this.id, required String this.instanceHost}) const FullPostPage({
: postView = null, required int this.id,
required String this.instanceHost,
}) : postView = null,
postStore = null; postStore = null;
const FullPostPage.fromPostView(PostView this.postView) const FullPostPage.fromPostView(PostView this.postView)
: id = null, : id = null,
@ -43,29 +45,52 @@ class FullPostPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Provider( return AsyncStoreListener(
create: (context) { asyncStore: context.read<FullPostStore>().fullPostState,
if (postStore != null) { child: AsyncStoreListener<BlockedCommunity>(
return FullPostStore.fromPostStore(postStore!); asyncStore: context.read<FullPostStore>().communityBlockingState,
} else if (postView != null) { successMessageBuilder: (context, data) {
return FullPostStore.fromPostView(postView!); final name = data.communityView.community.originPreferredName;
} else { return '${data.blocked ? 'Blocked' : 'Unblocked'} $name';
return FullPostStore(instanceHost: instanceHost!, postId: id!); },
} child: const _FullPostPage(),
},
builder: (context, store) => AsyncStoreListener(
asyncStore: context.read<FullPostStore>().fullPostState,
child: AsyncStoreListener<BlockedCommunity>(
asyncStore: context.read<FullPostStore>().communityBlockingState,
successMessageBuilder: (context, asyncStore) {
final name = asyncStore.communityView.community.originPreferredName;
return '${asyncStore.blocked ? 'Blocked' : 'Unblocked'} $name';
},
child: const _FullPostPage(),
),
), ),
); );
} }
static Jwt? _tryGetJwt(BuildContext context) {
final store = context.read<FullPostStore>();
return context
.read<AccountsStore>()
.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 /// Displays a post with its comment section
@ -76,102 +101,103 @@ class _FullPostPage extends HookWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final scrollController = useScrollController(); final scrollController = useScrollController();
useMemoized(() {
final store = context.read<FullPostStore>();
final token = context
.read<AccountsStore>()
.defaultUserDataFor(store.instanceHost)
?.jwt;
store.refresh(token);
}, []);
final loggedInAction = final loggedInAction =
useLoggedInAction(context.read<FullPostStore>().instanceHost); useLoggedInAction(context.read<FullPostStore>().instanceHost);
return ObserverBuilder<FullPostStore>( return AsyncStoreListener(
builder: (context, store) { asyncStore: context.read<FullPostStore>().fullPostState,
Future<void> refresh() async { child: AsyncStoreListener<BlockedCommunity>(
unawaited(HapticFeedback.mediumImpact()); asyncStore: context.read<FullPostStore>().communityBlockingState,
await store.refresh(context successMessageBuilder: (context, data) {
.read<AccountsStore>() final name = data.communityView.community.originPreferredName;
.defaultUserDataFor(store.instanceHost) return '${data.blocked ? 'Blocked' : 'Unblocked'} $name';
?.jwt); },
} child: ObserverBuilder<FullPostStore>(
builder: (context, store) {
Future<void> refresh() async {
unawaited(HapticFeedback.mediumImpact());
await store.refresh(context
.read<AccountsStore>()
.defaultUserDataFor(store.instanceHost)
?.jwt);
}
if (store.postView == null) { final post = store.postView;
return Scaffold(
appBar: AppBar(),
body: Center(
child: (store.fullPostState.isLoading)
? const CircularProgressIndicator.adaptive()
: FailedToLoad(
message: 'Post failed to load', refresh: refresh),
),
);
}
// VARIABLES if (post == null) {
return Scaffold(
final post = store.postView!; appBar: AppBar(),
body: Center(
sharePost() => share(post.post.apId, context: context); child: (store.fullPostState.isLoading)
? const CircularProgressIndicator.adaptive()
comment() async { : FailedToLoad(
final newComment = await Navigator.of(context).push( message: 'Post failed to load', refresh: refresh),
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<PostStore>( // VARIABLES
create: (context) => store.postStore!,
child: const SavePostButton(), sharePost() => share(post.post.apId, context: context);
),
IconButton( comment() async {
icon: Icon(moreIcon), final newComment = await Navigator.of(context).push(
onPressed: () => showPostMoreMenu( WriteComment.toPostRoute(post.post),
context: context, );
postStore: store.postStore!,
fullPostStore: store, 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: post.post.locked : FloatingActionButton(
? null onPressed: loggedInAction((_) => comment()),
: FloatingActionButton( child: const Icon(Icons.comment),
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(),
],
),
));
},
); );
} }
} }

View File

@ -62,8 +62,8 @@ abstract class goToUser {
goToUser.byId(context, personSafe.instanceHost, personSafe.id); goToUser.byId(context, personSafe.instanceHost, personSafe.id);
} }
void goToPost(BuildContext context, String instanceHost, int postId) => goTo( void goToPost(BuildContext context, String instanceHost, int postId) =>
context, (context) => FullPostPage(instanceHost: instanceHost, id: postId)); Navigator.of(context).push(FullPostPage.route(postId, instanceHost));
void goToMedia(BuildContext context, String url) => Navigator.push( void goToMedia(BuildContext context, String url) => Navigator.push(
context, context,

View File

@ -1,13 +1,11 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:lemmy_api_client/v3.dart'; import 'package:lemmy_api_client/v3.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import '../../pages/full_post/full_post.dart'; import '../../pages/full_post/full_post.dart';
import '../../util/async_store_listener.dart'; import '../../util/async_store_listener.dart';
import '../../util/extensions/api.dart'; import '../../util/extensions/api.dart';
import '../../util/goto.dart';
import 'post_actions.dart'; import 'post_actions.dart';
import 'post_body.dart'; import 'post_body.dart';
import 'post_info_section.dart'; import 'post_info_section.dart';
@ -29,8 +27,8 @@ class PostTile extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MultiProvider( return MultiProvider(
providers: [ providers: [
Provider<PostStore>(create: (_) => postStore), Provider.value(value: postStore),
Provider<IsFullPost>(create: (_) => fullPost), Provider.value(value: fullPost),
], ],
builder: (context, child) { builder: (context, child) {
return AsyncStoreListener( return AsyncStoreListener(
@ -53,7 +51,7 @@ class PostTile extends StatelessWidget {
} }
/// A post overview card /// A post overview card
class _Post extends HookWidget { class _Post extends StatelessWidget {
const _Post(); const _Post();
@override @override
@ -72,10 +70,8 @@ class _Post extends HookWidget {
? null ? null
: () { : () {
final postStore = context.read<PostStore>(); final postStore = context.read<PostStore>();
goTo( Navigator.of(context)
context, .push(FullPostPage.fromPostStoreRoute(postStore));
(context) => FullPostPage.fromPostStore(postStore),
);
}, },
child: Material( child: Material(
type: MaterialType.transparency, type: MaterialType.transparency,

View File

@ -22,7 +22,7 @@ class PostActions extends HookWidget {
// assemble actions section // assemble actions section
return ObserverBuilder<PostStore>(builder: (context, store) { return ObserverBuilder<PostStore>(builder: (context, store) {
return Padding( return Padding(
padding: const EdgeInsets.fromLTRB(10, 5, 10, 5), padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
child: Row( child: Row(
children: [ children: [
const Icon(Icons.comment), const Icon(Icons.comment),

View File

@ -17,18 +17,31 @@ import 'post_store.dart';
class PostMoreMenuButton extends StatelessWidget { class PostMoreMenuButton extends StatelessWidget {
const PostMoreMenuButton(); 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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column( return Column(
children: [ children: [
IconButton( IconButton(
onPressed: () => showPostMoreMenu( onPressed: () => show(
context: context, context: context,
postStore: context.read<PostStore>(), postStore: context.read<PostStore>(),
fullPostStore: null, fullPostStore: null,
), ),
icon: Icon(moreIcon), icon: Icon(moreIcon),
padding: const EdgeInsets.all(0), padding: EdgeInsets.zero,
visualDensity: VisualDensity.compact, 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 { class PostMoreMenu extends HookWidget {
final PostStore postStore; final PostStore postStore;
final FullPostStore? fullPostStore; final FullPostStore? fullPostStore;