2022-11-18 21:50:15 +00:00
|
|
|
import 'package:cached_network_image/cached_network_image.dart';
|
|
|
|
import 'package:flutter/material.dart';
|
|
|
|
import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart';
|
2022-11-21 21:21:45 +00:00
|
|
|
import 'package:logging/logging.dart';
|
2022-11-22 14:53:35 +00:00
|
|
|
import 'package:provider/provider.dart';
|
2022-11-18 21:50:15 +00:00
|
|
|
import 'package:url_launcher/url_launcher.dart';
|
|
|
|
|
|
|
|
import '../../globals.dart';
|
|
|
|
import '../../models/attachment_media_type_enum.dart';
|
|
|
|
import '../../models/connection.dart';
|
|
|
|
import '../../models/entry_tree_item.dart';
|
|
|
|
import '../../models/timeline_entry.dart';
|
|
|
|
import '../../screens/image_viewer_screen.dart';
|
|
|
|
import '../../services/connections_manager.dart';
|
2022-11-21 21:21:45 +00:00
|
|
|
import '../../services/timeline_manager.dart';
|
2022-11-18 21:50:15 +00:00
|
|
|
import '../../utils/dateutils.dart';
|
|
|
|
import '../../utils/snackbar_builder.dart';
|
|
|
|
import '../padding.dart';
|
|
|
|
import 'interactions_bar_control.dart';
|
|
|
|
|
2022-11-18 23:31:28 +00:00
|
|
|
class StatusControl extends StatefulWidget {
|
|
|
|
final EntryTreeItem originalItem;
|
2022-11-18 21:50:15 +00:00
|
|
|
|
2022-11-18 23:31:28 +00:00
|
|
|
const StatusControl({super.key, required this.originalItem});
|
|
|
|
|
|
|
|
@override
|
|
|
|
State<StatusControl> createState() => _StatusControlState();
|
|
|
|
}
|
|
|
|
|
|
|
|
class _StatusControlState extends State<StatusControl> {
|
2022-11-21 21:21:45 +00:00
|
|
|
static final _logger = Logger('$StatusControl');
|
2022-11-18 21:50:15 +00:00
|
|
|
|
2022-11-21 21:21:45 +00:00
|
|
|
EntryTreeItem get item => widget.originalItem;
|
|
|
|
|
|
|
|
TimelineEntry get entry => item.entry;
|
2022-11-18 21:50:15 +00:00
|
|
|
|
2022-11-22 16:43:16 +00:00
|
|
|
bool get isPost => item.entry.parentId.isEmpty;
|
|
|
|
|
|
|
|
bool get hasComments => entry.engagementSummary.repliesCount > 0;
|
|
|
|
|
2022-11-18 21:50:15 +00:00
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
2022-11-22 14:53:35 +00:00
|
|
|
final manager = context.watch<TimelineManager>();
|
2022-11-21 21:21:45 +00:00
|
|
|
_logger.finest('Building ${item.entry.toShortString()}');
|
2022-11-18 21:50:15 +00:00
|
|
|
return Padding(
|
|
|
|
padding: const EdgeInsets.all(8.0),
|
|
|
|
child: Column(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.start,
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
children: [
|
|
|
|
buildHeader(context),
|
|
|
|
const VerticalPadding(
|
|
|
|
height: 5,
|
|
|
|
),
|
|
|
|
buildBody(context),
|
|
|
|
const VerticalPadding(
|
|
|
|
height: 5,
|
|
|
|
),
|
|
|
|
buildMediaBar(context),
|
|
|
|
const VerticalPadding(
|
|
|
|
height: 5,
|
|
|
|
),
|
|
|
|
InteractionsBarControl(entry: entry),
|
|
|
|
const VerticalPadding(
|
|
|
|
height: 5,
|
|
|
|
),
|
2022-11-22 16:43:16 +00:00
|
|
|
if (isPost && hasComments)
|
2022-11-22 14:53:35 +00:00
|
|
|
TextButton(
|
|
|
|
onPressed: () async => await manager.refreshPost(item.id),
|
|
|
|
child: Text('Load Comments'),
|
|
|
|
),
|
|
|
|
if (item.totalChildren > 0) buildChildComments(context),
|
2022-11-18 21:50:15 +00:00
|
|
|
],
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget buildHeader(BuildContext context) {
|
|
|
|
final author = getIt<ConnectionsManager>()
|
|
|
|
.getById(entry.authorId)
|
|
|
|
.getValueOrElse(() => Connection());
|
|
|
|
return Row(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.start,
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
children: [
|
|
|
|
CachedNetworkImage(
|
|
|
|
imageUrl: author.avatarUrl.toString(),
|
|
|
|
width: 32.0,
|
|
|
|
),
|
|
|
|
const HorizontalPadding(),
|
|
|
|
Column(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
children: [
|
|
|
|
Text(
|
|
|
|
author.name,
|
2022-11-22 16:43:16 +00:00
|
|
|
style: Theme
|
|
|
|
.of(context)
|
|
|
|
.textTheme
|
|
|
|
.bodyText1,
|
2022-11-18 21:50:15 +00:00
|
|
|
),
|
|
|
|
Text(
|
|
|
|
ElapsedDateUtils.epochSecondsToString(entry.backdatedTimestamp),
|
2022-11-22 16:43:16 +00:00
|
|
|
style: Theme
|
|
|
|
.of(context)
|
|
|
|
.textTheme
|
|
|
|
.caption,
|
2022-11-18 21:50:15 +00:00
|
|
|
),
|
2022-11-22 14:53:35 +00:00
|
|
|
// Text(
|
|
|
|
// item.id,
|
|
|
|
// ),
|
2022-11-18 21:50:15 +00:00
|
|
|
],
|
|
|
|
),
|
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget buildBody(BuildContext context) {
|
|
|
|
return HtmlWidget(
|
|
|
|
entry.body,
|
|
|
|
onTapUrl: (url) async {
|
|
|
|
final uri = Uri.tryParse(url);
|
|
|
|
if (uri == null) {
|
|
|
|
buildSnackbar(context, 'Bad link: $url');
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (await canLaunchUrl(uri)) {
|
|
|
|
buildSnackbar(
|
|
|
|
context,
|
|
|
|
'Attempting to launch video: $url',
|
|
|
|
);
|
|
|
|
await launchUrl(uri);
|
|
|
|
} else {
|
|
|
|
buildSnackbar(context, 'Unable to launch video: $url');
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
onTapImage: (imageMetadata) {
|
|
|
|
print(imageMetadata);
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget buildMediaBar(BuildContext context) {
|
|
|
|
final items = entry.mediaAttachments;
|
|
|
|
if (items.isEmpty) {
|
|
|
|
return const SizedBox();
|
|
|
|
}
|
|
|
|
return SizedBox(
|
|
|
|
width: 250.0,
|
|
|
|
height: 250.0,
|
|
|
|
child: ListView.separated(
|
|
|
|
scrollDirection: Axis.horizontal,
|
|
|
|
itemBuilder: (context, index) {
|
|
|
|
final item = items[index];
|
|
|
|
|
|
|
|
if (item.explicitType == AttachmentMediaType.video) {
|
|
|
|
return ElevatedButton(
|
|
|
|
onPressed: () async {
|
|
|
|
if (await canLaunchUrl(item.uri)) {
|
|
|
|
buildSnackbar(
|
|
|
|
context,
|
|
|
|
'Attempting to launch video: ${item.uri}',
|
|
|
|
);
|
|
|
|
await launchUrl(item.uri);
|
|
|
|
} else {
|
|
|
|
buildSnackbar(
|
|
|
|
context, 'Unable to launch video: ${item.uri}');
|
|
|
|
}
|
|
|
|
},
|
|
|
|
child: Text(item.description.isNotEmpty
|
|
|
|
? item.description
|
|
|
|
: 'Video'));
|
|
|
|
}
|
|
|
|
if (item.explicitType != AttachmentMediaType.image) {
|
|
|
|
return Text('${item.explicitType}: ${item.uri}');
|
|
|
|
}
|
|
|
|
|
|
|
|
return InkWell(
|
|
|
|
onTap: () async {
|
|
|
|
Navigator.push(context, MaterialPageRoute(builder: (context) {
|
|
|
|
return ImageViewerScreen(attachment: item);
|
|
|
|
}));
|
|
|
|
},
|
|
|
|
child: CachedNetworkImage(
|
|
|
|
width: 250.0,
|
|
|
|
height: 250.0,
|
|
|
|
imageUrl: item.thumbnailUri.toString(),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
// return Text(item.toString());
|
|
|
|
},
|
|
|
|
separatorBuilder: (context, index) {
|
|
|
|
return HorizontalPadding();
|
|
|
|
},
|
|
|
|
itemCount: items.length));
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget buildChildComments(BuildContext context) {
|
2022-11-18 23:31:28 +00:00
|
|
|
final comments = widget.originalItem.children;
|
2022-11-18 21:50:15 +00:00
|
|
|
if (comments.isEmpty) {
|
|
|
|
return Text('No comments');
|
|
|
|
}
|
|
|
|
return Padding(
|
|
|
|
padding: EdgeInsets.only(left: 20.0, top: 5.0),
|
|
|
|
child: Row(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.start,
|
|
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
|
|
children: [
|
|
|
|
Icon(Icons.subdirectory_arrow_right),
|
|
|
|
Expanded(
|
|
|
|
child: Column(
|
2022-11-18 23:31:28 +00:00
|
|
|
children: comments
|
|
|
|
.map((c) => StatusControl(originalItem: c))
|
|
|
|
.toList(),
|
2022-11-18 21:50:15 +00:00
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|