diff --git a/lib/widgets/attachments/attachment_item.dart b/lib/widgets/attachments/attachment_item.dart index 0818f47..44b988c 100644 --- a/lib/widgets/attachments/attachment_item.dart +++ b/lib/widgets/attachments/attachment_item.dart @@ -33,102 +33,21 @@ class AttachmentItem extends StatefulWidget { } class _AttachmentItemState extends State { - VideoPlayerController? _videoPlayerController; - ChewieController? _chewieController; - - void ensureInitVideo() { - if (_videoPlayerController != null) return; - - _videoPlayerController = VideoPlayerController.networkUrl(Uri.parse( - '${ServiceFinder.services['paperclip']}/api/attachments/${widget.item.id}', - )); - _videoPlayerController!.initialize(); - _chewieController = ChewieController( - aspectRatio: widget.item.metadata?['ratio'] ?? 16 / 9, - videoPlayerController: _videoPlayerController!, - customControls: PlatformInfo.isMobile - ? const MaterialControls() - : const MaterialDesktopControls(), - materialProgressColors: ChewieProgressColors( - playedColor: Theme.of(context).colorScheme.primary, - handleColor: Theme.of(context).colorScheme.primary, - ), - ); - } - @override Widget build(BuildContext context) { switch (widget.item.mimetype.split('/').first) { case 'image': - return Hero( - tag: Key('a${widget.item.uuid}p${widget.parentId}'), - child: Stack( - fit: StackFit.expand, - children: [ - if (PlatformInfo.canCacheImage) - CachedNetworkImage( - fit: widget.fit, - imageUrl: - '${ServiceFinder.services['paperclip']}/api/attachments/${widget.item.id}', - progressIndicatorBuilder: (context, url, downloadProgress) => - Center( - child: CircularProgressIndicator( - value: downloadProgress.progress, - ), - ), - ) - else - Image.network( - '${ServiceFinder.services['paperclip']}/api/attachments/${widget.item.id}', - fit: widget.fit, - loadingBuilder: (BuildContext context, Widget child, - ImageChunkEvent? loadingProgress) { - if (loadingProgress == null) return child; - return Center( - child: CircularProgressIndicator( - value: loadingProgress.expectedTotalBytes != null - ? loadingProgress.cumulativeBytesLoaded / - loadingProgress.expectedTotalBytes! - : null, - ), - ); - }, - ), - if (widget.showBadge && widget.badge != null) - Positioned( - right: 12, - bottom: 8, - child: Material( - color: Colors.transparent, - child: Chip(label: Text(widget.badge!)), - ), - ), - if (widget.showHideButton && widget.item.isMature) - Positioned( - top: 8, - left: 12, - child: Material( - color: Colors.transparent, - child: ActionChip( - visualDensity: - const VisualDensity(vertical: -4, horizontal: -4), - avatar: Icon( - Icons.visibility_off, - color: Theme.of(context).colorScheme.onSurfaceVariant, - ), - label: Text('hide'.tr), - onPressed: () { - if (widget.onHide != null) widget.onHide!(); - }, - ), - ), - ), - ], - ), + return _AttachmentItemImage( + parentId: widget.parentId, + item: widget.item, + badge: widget.badge, + fit: widget.fit, + showBadge: widget.showBadge, + showHideButton: widget.showHideButton, + onHide: widget.onHide, ); case 'video': - ensureInitVideo(); - return Chewie(controller: _chewieController!); + return _AttachmentItemVideo(item: widget.item); default: return Center( child: Container( @@ -173,6 +92,136 @@ class _AttachmentItemState extends State { ); } } +} + +class _AttachmentItemImage extends StatelessWidget { + final String parentId; + final Attachment item; + final bool showBadge; + final bool showHideButton; + final BoxFit fit; + final String? badge; + final Function? onHide; + + const _AttachmentItemImage({ + super.key, + required this.parentId, + required this.item, + required this.showBadge, + required this.showHideButton, + required this.fit, + this.badge, + this.onHide, + }); + + @override + Widget build(BuildContext context) { + return Hero( + tag: Key('a${item.uuid}p${parentId}'), + child: Stack( + fit: StackFit.expand, + children: [ + if (PlatformInfo.canCacheImage) + CachedNetworkImage( + fit: fit, + imageUrl: + '${ServiceFinder.services['paperclip']}/api/attachments/${item.id}', + progressIndicatorBuilder: (context, url, downloadProgress) => + Center( + child: CircularProgressIndicator( + value: downloadProgress.progress, + ), + ), + ) + else + Image.network( + '${ServiceFinder.services['paperclip']}/api/attachments/${item.id}', + fit: fit, + loadingBuilder: (BuildContext context, Widget child, + ImageChunkEvent? loadingProgress) { + if (loadingProgress == null) return child; + return Center( + child: CircularProgressIndicator( + value: loadingProgress.expectedTotalBytes != null + ? loadingProgress.cumulativeBytesLoaded / + loadingProgress.expectedTotalBytes! + : null, + ), + ); + }, + ), + if (showBadge && badge != null) + Positioned( + right: 12, + bottom: 8, + child: Material( + color: Colors.transparent, + child: Chip(label: Text(badge!)), + ), + ), + if (showHideButton && item.isMature) + Positioned( + top: 8, + left: 12, + child: Material( + color: Colors.transparent, + child: ActionChip( + visualDensity: + const VisualDensity(vertical: -4, horizontal: -4), + avatar: Icon( + Icons.visibility_off, + color: Theme.of(context).colorScheme.onSurfaceVariant, + ), + label: Text('hide'.tr), + onPressed: () { + if (onHide != null) onHide!(); + }, + ), + ), + ), + ], + ), + ); + } +} + +class _AttachmentItemVideo extends StatefulWidget { + final Attachment item; + + const _AttachmentItemVideo({super.key, required this.item}); + + @override + State<_AttachmentItemVideo> createState() => _AttachmentItemVideoState(); +} + +class _AttachmentItemVideoState extends State<_AttachmentItemVideo> { + VideoPlayerController? _videoPlayerController; + ChewieController? _chewieController; + + void ensureInitVideo() { + if (_videoPlayerController != null) return; + _videoPlayerController = VideoPlayerController.networkUrl(Uri.parse( + '${ServiceFinder.services['paperclip']}/api/attachments/${widget.item.id}', + )); + _videoPlayerController!.initialize(); + _chewieController = ChewieController( + aspectRatio: widget.item.metadata?['ratio'] ?? 16 / 9, + videoPlayerController: _videoPlayerController!, + customControls: PlatformInfo.isMobile + ? const MaterialControls() + : const MaterialDesktopControls(), + materialProgressColors: ChewieProgressColors( + playedColor: Theme.of(context).colorScheme.primary, + handleColor: Theme.of(context).colorScheme.primary, + ), + ); + } + + @override + Widget build(BuildContext context) { + ensureInitVideo(); + return Chewie(controller: _chewieController!); + } @override void dispose() {