Redesign comment views to make it cleaner and easier to follow

This commit is contained in:
John Wesley 2024-01-11 11:29:40 -05:00
parent 134a89e193
commit 89b35d7852
12 changed files with 388 additions and 331 deletions

View File

@ -16,7 +16,7 @@ Future<PostCommentListModel> fetchComments(
final response = await client.get(Uri.https(
instanceHost,
'/api/posts/$postId/comments',
removeNulls({'p': page?.toString(), 'sortBy': sort?.name})));
removeNulls({'p': page?.toString(), 'sort': sort?.name})));
httpErrorHandler(response, message: 'Failed to load comments');

View File

@ -75,7 +75,7 @@ class _EntriesListViewState extends State<EntriesListView> {
),
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.all(8.0),
padding: const EdgeInsets.all(12),
child: Row(
children: [
DropdownButton<ContentSort>(
@ -122,9 +122,8 @@ class _EntriesListViewState extends State<EntriesListView> {
PagedSliverList<int, EntryModel>(
pagingController: _pagingController,
builderDelegate: PagedChildBuilderDelegate<EntryModel>(
itemBuilder: (context, item, index) => Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
itemBuilder: (context, item, index) => Card(
margin: const EdgeInsets.all(12),
clipBehavior: Clip.antiAlias,
child: InkWell(
onTap: () {
@ -154,7 +153,6 @@ class _EntriesListViewState extends State<EntriesListView> {
),
),
),
),
)
],
),

View File

@ -17,9 +17,14 @@ class EntryComment extends StatefulWidget {
}
class _EntryCommentState extends State<EntryComment> {
bool _isCollapsed = false;
@override
Widget build(BuildContext context) {
return Card(
return Column(
children: [
Card(
margin: const EdgeInsets.only(top: 8),
child: ContentItem(
body: widget.comment.body ?? '_comment deleted_',
createdAt: widget.comment.createdAt,
@ -67,7 +72,6 @@ class _EntryCommentState extends State<EntryComment> {
children: widget.comment.children,
));
}),
showCollapse: true,
onReply: (body) async {
var newSubComment = await api_comments.postComment(
context.read<SettingsController>().httpClient,
@ -113,8 +117,27 @@ class _EntryCommentState extends State<EntryComment> {
));
}, matchesUsername: widget.comment.user.username)
: null,
child: widget.comment.childCount > 0
? Column(
isCollapsed: _isCollapsed,
onCollapse: widget.comment.childCount > 0
? () => setState(() {
_isCollapsed = !_isCollapsed;
})
: null,
),
),
if (widget.comment.childCount > 0 && !_isCollapsed)
Container(
margin: const EdgeInsets.only(left: 1),
padding: const EdgeInsets.only(left: 10),
decoration: BoxDecoration(
border: Border(
left: BorderSide(
color: Theme.of(context).colorScheme.outlineVariant,
width: 1,
),
),
),
child: Column(
children: widget.comment.children!
.asMap()
.entries
@ -127,9 +150,9 @@ class _EntryCommentState extends State<EntryComment> {
));
}))
.toList(),
)
: null,
),
),
],
);
}
}

View File

@ -148,7 +148,7 @@ class _EntryPageState extends State<EntryPage> {
),
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.all(8.0),
padding: const EdgeInsets.all(12),
child: Row(
children: [
DropdownButton<api_comments.CommentsSort>(
@ -192,7 +192,10 @@ class _EntryPageState extends State<EntryPage> {
pagingController: _pagingController,
builderDelegate: PagedChildBuilderDelegate<EntryCommentModel>(
itemBuilder: (context, item, index) => Padding(
padding: const EdgeInsets.all(8),
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 4,
),
child: EntryComment(item, (newValue) {
var newList = _pagingController.itemList;
newList![index] = newValue;

View File

@ -63,7 +63,7 @@ class _DomainsScreenState extends State<DomainsScreen> {
slivers: [
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.all(12.0),
padding: const EdgeInsets.all(12),
child: Row(
children: [
SizedBox(
@ -106,7 +106,7 @@ class _DomainsScreenState extends State<DomainsScreen> {
);
},
child: Padding(
padding: const EdgeInsets.all(12.0),
padding: const EdgeInsets.all(12),
child: Row(children: [
Expanded(
child:

View File

@ -66,7 +66,7 @@ class _MagazinesScreenState extends State<MagazinesScreen> {
slivers: [
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.all(12.0),
padding: const EdgeInsets.all(12),
child: Row(
children: [
DropdownButton<api_magazines.MagazinesSort>(
@ -135,7 +135,7 @@ class _MagazinesScreenState extends State<MagazinesScreen> {
);
},
child: Padding(
padding: const EdgeInsets.all(12.0),
padding: const EdgeInsets.all(12),
child: Row(children: [
if (item.icon?.storageUrl != null)
Avatar(item.icon!.storageUrl, radius: 16),

View File

@ -82,7 +82,7 @@ class _UsersScreenState extends State<UsersScreen> {
);
},
child: Padding(
padding: const EdgeInsets.all(12.0),
padding: const EdgeInsets.all(12),
child: Row(children: [
if (item.avatar?.storageUrl != null)
Avatar(

View File

@ -17,9 +17,14 @@ class PostComment extends StatefulWidget {
}
class _EntryCommentState extends State<PostComment> {
bool _isCollapsed = false;
@override
Widget build(BuildContext context) {
return Card(
return Column(
children: [
Card(
margin: const EdgeInsets.only(top: 8),
child: ContentItem(
body: widget.comment.body ?? '_comment deleted_',
createdAt: widget.comment.createdAt,
@ -67,7 +72,6 @@ class _EntryCommentState extends State<PostComment> {
children: widget.comment.children,
));
}),
showCollapse: true,
onReply: (body) async {
var newSubComment = await api_comments.postComment(
context.read<SettingsController>().httpClient,
@ -113,8 +117,27 @@ class _EntryCommentState extends State<PostComment> {
));
})
: null,
child: widget.comment.childCount > 0
? Column(
isCollapsed: _isCollapsed,
onCollapse: widget.comment.childCount > 0
? () => setState(() {
_isCollapsed = !_isCollapsed;
})
: null,
),
),
if (widget.comment.childCount > 0 && !_isCollapsed)
Container(
margin: const EdgeInsets.only(left: 1),
padding: const EdgeInsets.only(left: 10),
decoration: BoxDecoration(
border: Border(
left: BorderSide(
color: Theme.of(context).colorScheme.outlineVariant,
width: 1,
),
),
),
child: Column(
children: widget.comment.children!
.asMap()
.entries
@ -127,9 +150,9 @@ class _EntryCommentState extends State<PostComment> {
));
}))
.toList(),
)
: null,
),
),
],
);
}
}

View File

@ -144,7 +144,7 @@ class _PostPageState extends State<PostPage> {
),
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.all(8.0),
padding: const EdgeInsets.all(12),
child: Row(
children: [
DropdownButton<api_comments.CommentsSort>(
@ -188,7 +188,10 @@ class _PostPageState extends State<PostPage> {
pagingController: _pagingController,
builderDelegate: PagedChildBuilderDelegate<PostCommentModel>(
itemBuilder: (context, item, index) => Padding(
padding: const EdgeInsets.all(8),
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 4,
),
child: PostComment(item, (newValue) {
var newList = _pagingController.itemList;
newList![index] = newValue;

View File

@ -75,7 +75,7 @@ class _PostsListViewState extends State<PostsListView> {
),
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.all(8.0),
padding: const EdgeInsets.all(12),
child: Row(
children: [
DropdownButton<ContentSort>(
@ -122,9 +122,8 @@ class _PostsListViewState extends State<PostsListView> {
PagedSliverList<int, PostModel>(
pagingController: _pagingController,
builderDelegate: PagedChildBuilderDelegate<PostModel>(
itemBuilder: (context, item, index) => Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
itemBuilder: (context, item, index) => Card(
margin: const EdgeInsets.all(12),
clipBehavior: Clip.antiAlias,
child: InkWell(
onTap: () {
@ -154,7 +153,6 @@ class _PostsListViewState extends State<PostsListView> {
),
),
),
),
)
],
),

View File

@ -8,6 +8,7 @@ import 'package:interstellar/src/widgets/markdown.dart';
import 'package:interstellar/src/widgets/markdown_editor.dart';
import 'package:interstellar/src/widgets/open_webpage.dart';
import 'package:interstellar/src/widgets/video.dart';
import 'package:interstellar/src/widgets/wrapper.dart';
class ContentItem extends StatefulWidget {
final String? title;
@ -18,7 +19,6 @@ class ContentItem extends StatefulWidget {
final DateTime? createdAt;
final bool isPreview;
final bool showCollapse;
final bool showMagazineFirst;
final String? user;
@ -49,7 +49,8 @@ class ContentItem extends StatefulWidget {
final Future<void> Function(String)? onEdit;
final Future<void> Function()? onDelete;
final Widget? child;
final bool isCollapsed;
final void Function()? onCollapse;
const ContentItem(
{this.title,
@ -59,7 +60,6 @@ class ContentItem extends StatefulWidget {
this.body,
this.createdAt,
this.isPreview = false,
this.showCollapse = false,
this.showMagazineFirst = false,
this.user,
this.userIcon,
@ -82,7 +82,8 @@ class ContentItem extends StatefulWidget {
this.onReply,
this.onEdit,
this.onDelete,
this.child,
this.isCollapsed = false,
this.onCollapse,
super.key});
@override
@ -90,7 +91,6 @@ class ContentItem extends StatefulWidget {
}
class _ContentItemState extends State<ContentItem> {
bool _isCollapsed = false;
TextEditingController? _replyTextController;
TextEditingController? _editTextController;
final MenuController _menuController = MenuController();
@ -161,35 +161,32 @@ class _ContentItemState extends State<ContentItem> {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
if (!widget.isPreview && widget.video != null)
VideoPlayer(widget.video!),
if (widget.image != null &&
!(!widget.isPreview && widget.video != null))
widget.isPreview
? (widget.video != null
if (widget.image != null || (!widget.isPreview && widget.video != null))
Wrapper(
shouldWrap: !widget.isPreview,
parentBuilder: (child) => Container(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height / 2,
),
child: child),
child: (!widget.isPreview && widget.video != null)
? VideoPlayer(widget.video!)
: Wrapper(
shouldWrap: widget.video == null,
parentBuilder: (child) => InkWell(
onTap: () => _onImageClick(context),
child: child,
),
child: widget.isPreview
? Image.network(
widget.image!,
height: 160,
width: double.infinity,
fit: BoxFit.cover,
)
: InkWell(
onTap: () => _onImageClick(context),
child: Image.network(
widget.image!,
height: 160,
width: double.infinity,
fit: BoxFit.cover,
: Image.network(widget.image!),
),
))
: Container(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height / 2,
),
child: InkWell(
onTap: () => _onImageClick(context),
child: Image.network(widget.image!),
)),
Container(
padding: const EdgeInsets.all(12),
child: Column(
@ -290,13 +287,11 @@ class _ContentItemState extends State<ContentItem> {
}),
),
),
if (widget.showCollapse && widget.child != null)
if (widget.onCollapse != null)
IconButton(
tooltip: _isCollapsed ? 'Expand' : 'Collapse',
onPressed: () => setState(() {
_isCollapsed = !_isCollapsed;
}),
icon: _isCollapsed
tooltip: widget.isCollapsed ? 'Expand' : 'Collapse',
onPressed: widget.onCollapse,
icon: widget.isCollapsed
? const Icon(Icons.expand_more)
: const Icon(Icons.expand_less)),
const Spacer(),
@ -450,11 +445,6 @@ class _ContentItemState extends State<ContentItem> {
],
),
),
if (widget.child != null && !_isCollapsed)
Padding(
padding: const EdgeInsets.only(top: 10),
child: widget.child,
)
],
),
),

View File

@ -0,0 +1,19 @@
import 'package:flutter/material.dart';
class Wrapper extends StatelessWidget {
final bool shouldWrap;
final Widget Function(Widget child) parentBuilder;
final Widget child;
const Wrapper({
super.key,
required this.shouldWrap,
required this.parentBuilder,
required this.child,
});
@override
Widget build(BuildContext context) {
return shouldWrap ? parentBuilder(child) : child;
}
}