mirror of
https://github.com/krawieck/lemmur/
synced 2024-12-23 14:28:03 +01:00
transition comment section to use mobx
This commit is contained in:
parent
cca679d6ef
commit
46a2f48e3a
@ -39,6 +39,15 @@ extension on CommentSortType {
|
||||
}
|
||||
}
|
||||
|
||||
extension SortCommentTreeList on List<CommentTree> {
|
||||
void sortBy(CommentSortType sortType) {
|
||||
sort(sortType.sortFunction);
|
||||
for (final el in this) {
|
||||
el._sort(sortType.sortFunction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CommentTree {
|
||||
CommentView comment;
|
||||
List<CommentTree> children = [];
|
||||
@ -71,14 +80,4 @@ class CommentTree {
|
||||
el._sort(compare);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sorts in-place a list of CommentTrees according to a given sortType
|
||||
static List<CommentTree> sortList(
|
||||
CommentSortType sortType, List<CommentTree> comms) {
|
||||
comms.sort(sortType.sortFunction);
|
||||
for (final el in comms) {
|
||||
el._sort(sortType.sortFunction);
|
||||
}
|
||||
return comms;
|
||||
}
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ class _FullPostPage extends HookWidget {
|
||||
children: [
|
||||
const SizedBox(height: 15),
|
||||
PostTile.fromPostStore(store.postStore!),
|
||||
const _Comments(),
|
||||
const CommentSection(),
|
||||
],
|
||||
),
|
||||
));
|
||||
@ -179,40 +179,6 @@ class _FullPostPage extends HookWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class _Comments extends StatelessWidget {
|
||||
const _Comments();
|
||||
|
||||
// TODO: comments rebuild every refresh, even when they don't change. FIX THAT!
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ObserverBuilder<FullPostStore>(
|
||||
builder: (context, store) {
|
||||
final fullPost = store.fullPostView;
|
||||
if (fullPost != null) {
|
||||
return CommentSection(store.comments!,
|
||||
postCreatorId: fullPost.postView.creator.id);
|
||||
} else if (store.fullPostState.errorTerm != null) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 30),
|
||||
child: FailedToLoad(
|
||||
message: 'Comments failed to load',
|
||||
refresh: () => store.refresh(context
|
||||
.read<AccountsStore>()
|
||||
.defaultUserDataFor(store.instanceHost)
|
||||
?.jwt)),
|
||||
);
|
||||
} else {
|
||||
return const Padding(
|
||||
padding: EdgeInsets.only(top: 40),
|
||||
child: Center(child: CircularProgressIndicator()),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FailedToLoad extends StatelessWidget {
|
||||
final String message;
|
||||
final VoidCallback refresh;
|
||||
|
@ -1,20 +1,18 @@
|
||||
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 '../comment_tree.dart';
|
||||
import '../l10n/l10n.dart';
|
||||
import '../pages/full_post/full_post.dart';
|
||||
import '../stores/accounts_store.dart';
|
||||
import '../util/observer_consumers.dart';
|
||||
import 'bottom_modal.dart';
|
||||
import 'bottom_safe.dart';
|
||||
import 'comment/comment.dart';
|
||||
import 'post/full_post_store.dart';
|
||||
|
||||
/// Manages comments section, sorts them
|
||||
class CommentSection extends HookWidget {
|
||||
final List<CommentView> rawComments;
|
||||
final List<CommentTree> comments;
|
||||
final int postCreatorId;
|
||||
final CommentSortType sortType;
|
||||
|
||||
class CommentSection extends StatelessWidget {
|
||||
static const sortPairs = {
|
||||
CommentSortType.hot: [Icons.whatshot, L10nStrings.hot],
|
||||
CommentSortType.new_: [Icons.new_releases, L10nStrings.new_],
|
||||
@ -23,89 +21,108 @@ class CommentSection extends HookWidget {
|
||||
CommentSortType.chat: [Icons.chat, L10nStrings.chat],
|
||||
};
|
||||
|
||||
CommentSection(
|
||||
List<CommentView> rawComments, {
|
||||
required this.postCreatorId,
|
||||
this.sortType = CommentSortType.hot,
|
||||
}) : comments =
|
||||
CommentTree.sortList(sortType, CommentTree.fromList(rawComments)),
|
||||
rawComments = rawComments
|
||||
..sort((b, a) => a.comment.published.compareTo(b.comment.published));
|
||||
const CommentSection({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final sorting = useState(sortType);
|
||||
return ObserverBuilder<FullPostStore>(
|
||||
builder: (context, store) {
|
||||
// error & spinner handling
|
||||
if (store.fullPostView == null) {
|
||||
if (store.fullPostState.errorTerm != null) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 30),
|
||||
child: FailedToLoad(
|
||||
message: 'Comments failed to load',
|
||||
refresh: () => store.refresh(context
|
||||
.read<AccountsStore>()
|
||||
.defaultUserDataFor(store.instanceHost)
|
||||
?.jwt)),
|
||||
);
|
||||
} else {
|
||||
return const Padding(
|
||||
padding: EdgeInsets.only(top: 40),
|
||||
child: Center(child: CircularProgressIndicator()),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void sortComments(CommentSortType sort) {
|
||||
if (sort != sorting.value && sort != CommentSortType.chat) {
|
||||
CommentTree.sortList(sort, comments);
|
||||
}
|
||||
|
||||
sorting.value = sort;
|
||||
}
|
||||
|
||||
return Column(children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
|
||||
child: Row(
|
||||
return Column(
|
||||
children: [
|
||||
OutlinedButton(
|
||||
onPressed: () {
|
||||
showBottomModal(
|
||||
title: 'sort by',
|
||||
context: context,
|
||||
builder: (context) => Column(
|
||||
children: [
|
||||
for (final e in sortPairs.entries)
|
||||
ListTile(
|
||||
leading: Icon(e.value[0] as IconData),
|
||||
title: Text((e.value[1] as String).tr(context)),
|
||||
trailing: sorting.value == e.key
|
||||
? const Icon(Icons.check)
|
||||
: null,
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
sortComments(e.key);
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
|
||||
child: Row(
|
||||
children: [
|
||||
Text((sortPairs[sorting.value]![1] as String).tr(context)),
|
||||
const Icon(Icons.arrow_drop_down),
|
||||
OutlinedButton(
|
||||
onPressed: () {
|
||||
showBottomModal(
|
||||
title: 'sort by',
|
||||
context: context,
|
||||
builder: (context) => Column(
|
||||
children: [
|
||||
for (final e in sortPairs.entries)
|
||||
ListTile(
|
||||
leading: Icon(e.value[0] as IconData),
|
||||
title: Text((e.value[1] as String).tr(context)),
|
||||
trailing: store.sorting == e.key
|
||||
? const Icon(Icons.check)
|
||||
: null,
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
store.updateSorting(e.key);
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Row(
|
||||
children: [
|
||||
Text((sortPairs[store.sorting]![1] as String)
|
||||
.tr(context)),
|
||||
const Icon(Icons.arrow_drop_down),
|
||||
],
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
],
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
// sorting menu goes here
|
||||
if (store.fullPostView!.comments.isEmpty)
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 50),
|
||||
child: Text(
|
||||
'no comments yet',
|
||||
style: TextStyle(fontStyle: FontStyle.italic),
|
||||
),
|
||||
)
|
||||
else ...[
|
||||
for (final com in store.newComments)
|
||||
CommentWidget.fromCommentView(
|
||||
com,
|
||||
detached: false,
|
||||
key: ValueKey(com),
|
||||
),
|
||||
if (store.sorting == CommentSortType.chat)
|
||||
for (final com in store.fullPostView!.comments)
|
||||
CommentWidget.fromCommentView(
|
||||
com,
|
||||
detached: false,
|
||||
key: ValueKey(com),
|
||||
)
|
||||
else
|
||||
for (final com in store.sortedCommentTree!)
|
||||
CommentWidget(
|
||||
com,
|
||||
key: ValueKey(com),
|
||||
),
|
||||
const BottomSafe(
|
||||
kMinInteractiveDimension + kFloatingActionButtonMargin),
|
||||
]
|
||||
],
|
||||
),
|
||||
),
|
||||
// sorting menu goes here
|
||||
if (comments.isEmpty)
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(vertical: 50),
|
||||
child: Text(
|
||||
'no comments yet',
|
||||
style: TextStyle(fontStyle: FontStyle.italic),
|
||||
),
|
||||
)
|
||||
else if (sorting.value == CommentSortType.chat)
|
||||
for (final com in rawComments)
|
||||
CommentWidget.fromCommentView(
|
||||
com,
|
||||
detached: false,
|
||||
key: ValueKey(com),
|
||||
)
|
||||
else
|
||||
for (final com in comments)
|
||||
CommentWidget(
|
||||
com,
|
||||
key: ValueKey(com),
|
||||
),
|
||||
const BottomSafe(kMinInteractiveDimension + kFloatingActionButtonMargin),
|
||||
]);
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
import 'package:lemmy_api_client/v3.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
import '../../comment_tree.dart';
|
||||
import '../../util/async_store.dart';
|
||||
import 'post_store.dart';
|
||||
|
||||
@ -16,7 +17,27 @@ abstract class _FullPostStore with Store {
|
||||
FullPostView? fullPostView;
|
||||
|
||||
@observable
|
||||
List<CommentView> newComments = [];
|
||||
ObservableList<CommentView> newComments = ObservableList<CommentView>();
|
||||
|
||||
@observable
|
||||
CommentSortType sorting = CommentSortType.hot;
|
||||
|
||||
@action
|
||||
// ignore: use_setters_to_change_properties
|
||||
void updateSorting(CommentSortType sort) {
|
||||
sorting = sort;
|
||||
}
|
||||
|
||||
@computed
|
||||
List<CommentTree>? get commentTree {
|
||||
if (fullPostView == null) return null;
|
||||
return CommentTree.fromList(fullPostView!.comments);
|
||||
}
|
||||
|
||||
@computed
|
||||
List<CommentTree>? get sortedCommentTree {
|
||||
return commentTree?..sortBy(sorting);
|
||||
}
|
||||
|
||||
@observable
|
||||
PostStore? postStore;
|
||||
@ -68,12 +89,14 @@ abstract class _FullPostStore with Store {
|
||||
required this.instanceHost,
|
||||
});
|
||||
|
||||
// ignore: unused_element
|
||||
_FullPostStore.fromPostView(PostView postView)
|
||||
: postId = postView.post.id,
|
||||
instanceHost = postView.instanceHost,
|
||||
postStore = PostStore(postView);
|
||||
|
||||
_FullPostStore.fromPostStore(this.postStore)
|
||||
: postId = postStore!.postView.post.id,
|
||||
// ignore: unused_element
|
||||
_FullPostStore.fromPostStore(PostStore this.postStore)
|
||||
: postId = postStore.postView.post.id,
|
||||
instanceHost = postStore.postView.instanceHost;
|
||||
}
|
||||
|
@ -9,6 +9,20 @@ part of 'full_post_store.dart';
|
||||
// ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic
|
||||
|
||||
mixin _$FullPostStore on _FullPostStore, Store {
|
||||
Computed<List<CommentTree>?>? _$commentTreeComputed;
|
||||
|
||||
@override
|
||||
List<CommentTree>? get commentTree => (_$commentTreeComputed ??=
|
||||
Computed<List<CommentTree>?>(() => super.commentTree,
|
||||
name: '_FullPostStore.commentTree'))
|
||||
.value;
|
||||
Computed<List<CommentTree>?>? _$sortedCommentTreeComputed;
|
||||
|
||||
@override
|
||||
List<CommentTree>? get sortedCommentTree => (_$sortedCommentTreeComputed ??=
|
||||
Computed<List<CommentTree>?>(() => super.sortedCommentTree,
|
||||
name: '_FullPostStore.sortedCommentTree'))
|
||||
.value;
|
||||
Computed<PostView?>? _$postViewComputed;
|
||||
|
||||
@override
|
||||
@ -42,18 +56,33 @@ mixin _$FullPostStore on _FullPostStore, Store {
|
||||
final _$newCommentsAtom = Atom(name: '_FullPostStore.newComments');
|
||||
|
||||
@override
|
||||
List<CommentView> get newComments {
|
||||
ObservableList<CommentView> get newComments {
|
||||
_$newCommentsAtom.reportRead();
|
||||
return super.newComments;
|
||||
}
|
||||
|
||||
@override
|
||||
set newComments(List<CommentView> value) {
|
||||
set newComments(ObservableList<CommentView> value) {
|
||||
_$newCommentsAtom.reportWrite(value, super.newComments, () {
|
||||
super.newComments = value;
|
||||
});
|
||||
}
|
||||
|
||||
final _$sortingAtom = Atom(name: '_FullPostStore.sorting');
|
||||
|
||||
@override
|
||||
CommentSortType get sorting {
|
||||
_$sortingAtom.reportRead();
|
||||
return super.sorting;
|
||||
}
|
||||
|
||||
@override
|
||||
set sorting(CommentSortType value) {
|
||||
_$sortingAtom.reportWrite(value, super.sorting, () {
|
||||
super.sorting = value;
|
||||
});
|
||||
}
|
||||
|
||||
final _$postStoreAtom = Atom(name: '_FullPostStore.postStore');
|
||||
|
||||
@override
|
||||
@ -87,6 +116,17 @@ mixin _$FullPostStore on _FullPostStore, Store {
|
||||
final _$_FullPostStoreActionController =
|
||||
ActionController(name: '_FullPostStore');
|
||||
|
||||
@override
|
||||
void updateSorting(CommentSortType sort) {
|
||||
final _$actionInfo = _$_FullPostStoreActionController.startAction(
|
||||
name: '_FullPostStore.updateSorting');
|
||||
try {
|
||||
return super.updateSorting(sort);
|
||||
} finally {
|
||||
_$_FullPostStoreActionController.endAction(_$actionInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void addComment(CommentView commentView) {
|
||||
final _$actionInfo = _$_FullPostStoreActionController.startAction(
|
||||
@ -103,7 +143,10 @@ mixin _$FullPostStore on _FullPostStore, Store {
|
||||
return '''
|
||||
fullPostView: ${fullPostView},
|
||||
newComments: ${newComments},
|
||||
sorting: ${sorting},
|
||||
postStore: ${postStore},
|
||||
commentTree: ${commentTree},
|
||||
sortedCommentTree: ${sortedCommentTree},
|
||||
postView: ${postView},
|
||||
comments: ${comments}
|
||||
''';
|
||||
|
@ -9,6 +9,7 @@ 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';
|
||||
import 'post_link_preview.dart';
|
||||
import 'post_media.dart';
|
||||
@ -84,6 +85,7 @@ class _Post extends HookWidget {
|
||||
PostTitle(),
|
||||
PostMedia(),
|
||||
PostLinkPreview(),
|
||||
PostBody(),
|
||||
PostActions(),
|
||||
],
|
||||
),
|
||||
|
Loading…
Reference in New Issue
Block a user