import 'package:flutter/material.dart'; import 'package:flutter_widget_from_html_core/flutter_widget_from_html_core.dart'; import 'package:logging/logging.dart'; import 'package:provider/provider.dart'; import 'package:url_launcher/url_launcher.dart'; import '../../models/attachment_media_type_enum.dart'; import '../../models/entry_tree_item.dart'; import '../../models/timeline_entry.dart'; import '../../screens/image_viewer_screen.dart'; import '../../services/timeline_manager.dart'; import '../../utils/snackbar_builder.dart'; import '../../utils/url_opening_utils.dart'; import '../image_control.dart'; import '../padding.dart'; import 'interactions_bar_control.dart'; import 'status_header_control.dart'; class StatusControl extends StatefulWidget { final EntryTreeItem originalItem; final bool openRemote; final bool showStatusOpenButton; const StatusControl( {super.key, required this.originalItem, required this.openRemote, required this.showStatusOpenButton}); @override State createState() => _StatusControlState(); } class _StatusControlState extends State { static final _logger = Logger('$StatusControl'); var showContent = true; var showComments = false; EntryTreeItem get item => widget.originalItem; TimelineEntry get entry => item.entry; bool get isPublic => item.entry.isPublic; bool get isPost => item.entry.parentId.isEmpty; bool get hasComments => entry.engagementSummary.repliesCount > 0; @override void initState() { showContent = entry.spoilerText.isEmpty; showComments = isPost ? false : true; } @override Widget build(BuildContext context) { final manager = context.watch(); _logger.finest('Building ${item.entry.toShortString()}'); final padding = isPost ? 8.0 : 8.0; final body = Padding( padding: EdgeInsets.all(padding), child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ StatusHeaderControl( entry: entry, openRemote: widget.openRemote, showOpenControl: widget.showStatusOpenButton, ), const VerticalPadding( height: 5, ), if (entry.spoilerText.isNotEmpty) TextButton( onPressed: () { setState(() { showContent = !showContent; }); }, child: Text( 'Content Summary: ${entry.spoilerText} (Click to ${showContent ? "Hide" : "Show"}}')), if (showContent) ...[ buildBody(context), const VerticalPadding( height: 5, ), buildMediaBar(context), ], const VerticalPadding( height: 5, ), InteractionsBarControl( entry: entry, isMine: item.isMine, ), const VerticalPadding( height: 5, ), if (isPost && hasComments) TextButton( onPressed: () async { setState(() { showComments = !showComments; }); if (showComments) { await manager.refreshStatusChain(item.id); } }, child: Text(showComments ? 'Hide Comments' : 'Load & Show Comments'), ), if (item.totalChildren > 0 && showComments) buildChildComments(context), ], ), ); return isPost ? body : Card(color: Theme.of(context).splashColor, child: body); } Widget buildBody(BuildContext context) { return HtmlWidget( entry.body, onTapUrl: (url) async { return await openUrlStringInSystembrowser(context, url, 'video'); }, ); } Widget buildMediaBar(BuildContext context) { final items = entry.mediaAttachments; if (items.isEmpty) { return const SizedBox(); } return SizedBox( 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 ImageControl( width: 250.0, height: 250.0, imageUrl: item.thumbnailUri.toString(), altText: item.description, onTap: () async { Navigator.push(context, MaterialPageRoute(builder: (context) { return ImageViewerScreen(attachment: item); })); }, ); // return Text(item.toString()); }, separatorBuilder: (context, index) { return HorizontalPadding(); }, itemCount: items.length)); } Widget buildChildComments(BuildContext context) { final comments = widget.originalItem.children; if (comments.isEmpty) { return Text('No comments'); } return Padding( padding: EdgeInsets.only(left: 5.0, top: 5.0), child: Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Column( children: comments .map((c) => StatusControl( originalItem: c, openRemote: false, showStatusOpenButton: false, )) .toList(), ), ), ], )); } }