Refactor post display to be cleaner

codemagic-setup
Hank Grabowski 2023-03-19 22:16:30 -04:00
rodzic 5ffa37d9be
commit 942f6f0ec5
4 zmienionych plików z 161 dodań i 157 usunięć

Wyświetl plik

@ -1,9 +1,14 @@
import 'package:flutter/material.dart';
import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart';
import 'package:go_router/go_router.dart';
import 'package:logging/logging.dart';
import '../../globals.dart';
import '../../models/flattened_tree_item.dart';
import '../../models/timeline_entry.dart';
import '../../services/timeline_manager.dart';
import '../../utils/active_profile_selector.dart';
import '../../utils/clipboard_utils.dart';
import '../../utils/url_opening_utils.dart';
import '../media_attachment_viewer_control.dart';
import '../padding.dart';
@ -43,6 +48,8 @@ class _StatusControlState extends State<FlattenedTreeEntryControl> {
bool get hasComments => entry.engagementSummary.repliesCount > 0;
bool isProcessing = false;
@override
void initState() {
showContent = entry.spoilerText.isEmpty;
@ -78,8 +85,15 @@ class _StatusControlState extends State<FlattenedTreeEntryControl> {
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
StatusHeaderControl(
entry: entry,
Row(
children: [
Expanded(
child: StatusHeaderControl(
entry: entry,
),
),
buildMenuControl(context),
],
),
const VerticalPadding(
height: 5,
@ -108,7 +122,6 @@ class _StatusControlState extends State<FlattenedTreeEntryControl> {
InteractionsBarControl(
entry: entry,
isMine: item.isMine,
openRemote: widget.openRemote,
showOpenControl: widget.showStatusOpenButton,
),
const VerticalPadding(
@ -158,4 +171,88 @@ class _StatusControlState extends State<FlattenedTreeEntryControl> {
},
itemCount: items.length));
}
Widget buildMenuControl(BuildContext context) {
const editStatus = 'Edit';
const deleteStatus = 'Delete';
const goToPost = 'Open Post';
const copyText = 'Copy Post Text';
const copyUrl = 'Copy URL';
const openExternal = 'Open In Browser';
final options = [
if (widget.showStatusOpenButton && !widget.openRemote) goToPost,
if (item.isMine && !item.timelineEntry.youReshared) editStatus,
if (item.isMine) deleteStatus,
copyText,
openExternal,
copyUrl,
];
return PopupMenuButton<String>(onSelected: (menuOption) async {
if (!mounted) {
return;
}
switch (menuOption) {
case goToPost:
context.push(
'/post/view/${item.timelineEntry.id}/${item.timelineEntry.id}');
break;
case editStatus:
if (item.timelineEntry.parentId.isEmpty) {
context.push('/post/edit/${item.timelineEntry.id}');
} else {
context.push('/comment/edit/${item.timelineEntry.id}');
}
break;
case deleteStatus:
deleteEntry();
break;
case openExternal:
await openUrlStringInSystembrowser(
context,
item.timelineEntry.externalLink,
'Post',
);
break;
case copyUrl:
await copyToClipboard(
context: context,
text: item.timelineEntry.externalLink,
message: 'Post link copied to clipboard',
);
break;
case copyText:
await copyToClipboard(
context: context,
text: item.timelineEntry.body,
message: 'Post link copied to clipboard',
);
break;
default:
//do nothing
}
}, itemBuilder: (context) {
return options
.map((o) => PopupMenuItem(value: o, child: Text(o)))
.toList();
});
}
Future<void> deleteEntry() async {
setState(() {
isProcessing = true;
});
final confirm =
await showYesNoDialog(context, 'Delete ${isPost ? "Post" : "Comment"}');
if (confirm == true) {
await getIt<ActiveProfileSelector<TimelineManager>>()
.activeEntry
.andThenAsync(
(tm) async => await tm.deleteEntryById(item.timelineEntry.id));
}
setState(() {
isProcessing = false;
});
}
}

Wyświetl plik

@ -6,13 +6,10 @@ import '../../globals.dart';
import '../../models/timeline_entry.dart';
import '../../services/timeline_manager.dart';
import '../../utils/active_profile_selector.dart';
import '../../utils/clipboard_utils.dart';
import '../../utils/snackbar_builder.dart';
import '../../utils/url_opening_utils.dart';
class InteractionsBarControl extends StatefulWidget {
final TimelineEntry entry;
final bool openRemote;
final bool showOpenControl;
final bool isMine;
@ -21,7 +18,6 @@ class InteractionsBarControl extends StatefulWidget {
required this.entry,
required this.isMine,
required this.showOpenControl,
required this.openRemote,
});
@override
@ -94,23 +90,6 @@ class _InteractionsBarControlState extends State<InteractionsBarControl> {
context.push('/comment/new?parent_id=${widget.entry.id}');
}
Future<void> deleteEntry() async {
setState(() {
isProcessing = true;
});
final confirm =
await showYesNoDialog(context, 'Delete ${isPost ? "Post" : "Comment"}');
if (confirm == true) {
await getIt<ActiveProfileSelector<TimelineManager>>()
.activeEntry
.andThenAsync(
(tm) async => await tm.deleteEntryById(widget.entry.id));
}
setState(() {
isProcessing = false;
});
}
Future<void> unResharePost() async {
setState(() {
isProcessing = true;
@ -133,55 +112,6 @@ class _InteractionsBarControlState extends State<InteractionsBarControl> {
});
}
Future<void> openAction(BuildContext context) async {
const editStatus = 'Edit Post';
const goToPost = 'Go to Post';
const copyUrl = 'Copy URL';
const openExternal = 'Open In Browser';
final options = [
if (widget.showOpenControl && !widget.openRemote) goToPost,
if (widget.isMine && !widget.entry.youReshared) editStatus,
openExternal,
copyUrl,
'Cancel'
];
final result =
await showChooseOptions(context, 'Would you like to', options);
if (!mounted) {
return;
}
switch (result) {
case goToPost:
context.push('/post/view/${widget.entry.id}/${widget.entry.id}');
break;
case editStatus:
if (widget.entry.parentId.isEmpty) {
context.push('/post/edit/${widget.entry.id}');
} else {
context.push('/comment/edit/${widget.entry.id}');
}
break;
case openExternal:
await openUrlStringInSystembrowser(
context,
widget.entry.externalLink,
'Post',
);
break;
case copyUrl:
await copyToClipboard(
context: context,
text: widget.entry.externalLink,
message: 'Post link copied to clipboard',
);
break;
default:
//do nothing
}
}
@override
Widget build(BuildContext context) {
_logger.finest('Building: ${widget.entry.toShortString()}');
@ -197,7 +127,7 @@ class _InteractionsBarControlState extends State<InteractionsBarControl> {
: () {
context.push('/likes/${widget.entry.id}');
},
child: Text('$likes likes'),
child: Text('$likes Likes'),
),
TextButton(
onPressed: reshares == 0
@ -205,7 +135,7 @@ class _InteractionsBarControlState extends State<InteractionsBarControl> {
: () {
context.push('/reshares/${widget.entry.id}');
},
child: Text('$reshares reshares'),
child: Text('$reshares Reshares'),
),
widget.showOpenControl
? TextButton(
@ -215,9 +145,9 @@ class _InteractionsBarControlState extends State<InteractionsBarControl> {
context.push(
'/post/view/${widget.entry.id}/${widget.entry.id}');
},
child: Text('$comments comments'),
child: Text('$comments Comments'),
)
: Text('$comments comments'),
: Text('$comments Comments'),
],
),
Row(children: [
@ -244,36 +174,6 @@ class _InteractionsBarControlState extends State<InteractionsBarControl> {
IconButton(
onPressed: isProcessing ? null : addComment,
icon: Icon(Icons.add_comment)),
if (widget.isMine &&
!widget.entry
.youReshared) //TODO Figure out why reshares show up as mine sometimes but not others
IconButton(
onPressed:
isProcessing ? null : () async => await deleteEntry(),
icon: Icon(Icons.delete)),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
IconButton(
onPressed: () async {
await copyToClipboard(
context: context,
text: widget.entry.body,
message: 'Post text copied to clipboard',
);
},
icon: const Icon(Icons.copy),
),
IconButton(
onPressed: () async {
await openAction(context);
},
icon: const Icon(Icons.launch),
),
],
),
),
]),
],
);

Wyświetl plik

@ -45,66 +45,73 @@ class StatusHeaderControl extends StatelessWidget {
},
);
return Wrap(
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ImageControl(
imageUrl: author.avatarUrl.toString(),
iconOverride: Icon(Icons.person),
width: 32.0,
onTap: () => goToProfile(context, author.id),
),
const HorizontalPadding(),
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
Wrap(
crossAxisAlignment: WrapCrossAlignment.end,
runSpacing: 5.0,
children: [
GestureDetector(
ImageControl(
imageUrl: author.avatarUrl.toString(),
iconOverride: Icon(Icons.person),
width: 32.0,
onTap: () => goToProfile(context, author.id),
child: Text(
author.name,
style: Theme.of(context).textTheme.bodyText1,
),
),
Row(
mainAxisSize: MainAxisSize.min,
const HorizontalPadding(),
Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
ElapsedDateUtils.epochSecondsToString(
entry.backdatedTimestamp),
style: Theme.of(context).textTheme.caption,
),
const HorizontalPadding(),
Icon(
entry.isPublic ? Icons.public : Icons.lock,
color: Theme.of(context).hintColor,
size: Theme.of(context).textTheme.caption?.fontSize,
GestureDetector(
onTap: () => goToProfile(context, author.id),
child: Text(
author.name,
style: Theme.of(context).textTheme.bodyText1,
),
),
],
),
// Text(
// entry.id,
// ),
if (reshareAuthor.isNotEmpty) ...[
const HorizontalPadding(width: 3.0),
const Text('reshared post by: '),
const HorizontalPadding(width: 3.0),
Row(
mainAxisSize: MainAxisSize.min,
children: [
ImageControl(
imageUrl: reshareAuthor.avatarUrl.toString(),
iconOverride: Icon(Icons.person),
width: 32.0,
onTap: () => goToProfile(context, reshareAuthor.id),
),
const HorizontalPadding(width: 3.0),
GestureDetector(
onTap: () => goToProfile(context, reshareAuthor.id),
child: Text(
reshareAuthor.name,
style: Theme.of(context).textTheme.bodyText1,
),
),
],
),
],
],
),
if (reshareAuthor.isNotEmpty) ...[
const HorizontalPadding(width: 3.0),
const Icon(Icons.repeat),
const HorizontalPadding(width: 3.0),
ImageControl(
imageUrl: reshareAuthor.avatarUrl.toString(),
iconOverride: Icon(Icons.person),
width: 32.0,
onTap: () => goToProfile(context, reshareAuthor.id),
),
const HorizontalPadding(width: 3.0),
GestureDetector(
onTap: () => goToProfile(context, reshareAuthor.id),
child: Text(
reshareAuthor.name,
style: Theme.of(context).textTheme.bodyText1,
Row(
children: [
Text(
ElapsedDateUtils.epochSecondsToString(entry.backdatedTimestamp),
style: Theme.of(context).textTheme.caption,
),
),
],
const HorizontalPadding(),
Icon(
entry.isPublic ? Icons.public : Icons.lock,
color: Theme.of(context).hintColor,
size: Theme.of(context).textTheme.caption?.fontSize,
),
],
),
],
);
}

Wyświetl plik

@ -53,7 +53,7 @@ class _PostScreenState extends State<PostScreen> {
originalItem: post,
scrollToId: widget.goToId,
openRemote: true,
showStatusOpenButton: true,
showStatusOpenButton: false,
isRoot: true,
),
),