refactor: improve fullscreen_media, minor changes.
Signed-off-by: xsahil03x <[email protected]>
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
export 'attachment_error.dart';
|
|
||||||
export 'attachment_upload_state_builder.dart';
|
export 'attachment_upload_state_builder.dart';
|
||||||
export 'file_attachment.dart';
|
export 'file_attachment.dart';
|
||||||
|
export 'gallery_attachment.dart';
|
||||||
export 'giphy_attachment.dart';
|
export 'giphy_attachment.dart';
|
||||||
export 'image_attachment.dart';
|
export 'image_attachment.dart';
|
||||||
|
export 'url_attachment.dart';
|
||||||
export 'video_attachment.dart';
|
export 'video_attachment.dart';
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|
||||||
|
|
||||||
/// {@template attachmentError}
|
|
||||||
/// Widget for building in case of error
|
|
||||||
/// {@endtemplate}
|
|
||||||
class AttachmentError extends StatelessWidget {
|
|
||||||
/// {@macro attachmentError}
|
|
||||||
const AttachmentError({
|
|
||||||
super.key,
|
|
||||||
this.constraints,
|
|
||||||
});
|
|
||||||
|
|
||||||
/// constraints of error
|
|
||||||
final BoxConstraints? constraints;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Center(
|
|
||||||
child: Container(
|
|
||||||
constraints: constraints ?? const BoxConstraints.expand(),
|
|
||||||
color:
|
|
||||||
StreamChatTheme.of(context).colorTheme.accentError.withOpacity(0.1),
|
|
||||||
child: Center(
|
|
||||||
child: Icon(
|
|
||||||
Icons.error_outline,
|
|
||||||
color: StreamChatTheme.of(context).colorTheme.textHighEmphasis,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|
||||||
|
|
||||||
/// {@template attachmentTitle}
|
|
||||||
/// Title for attachments
|
|
||||||
/// {@endtemplate}
|
|
||||||
class StreamAttachmentTitle extends StatelessWidget {
|
|
||||||
/// {@macro attachmentTitle}
|
|
||||||
const StreamAttachmentTitle({
|
|
||||||
super.key,
|
|
||||||
required this.attachment,
|
|
||||||
required this.messageTheme,
|
|
||||||
});
|
|
||||||
|
|
||||||
/// Theme to apply to text
|
|
||||||
final StreamMessageThemeData messageTheme;
|
|
||||||
|
|
||||||
/// Attachment data to display
|
|
||||||
final Attachment attachment;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
final ogScrapeUrl = attachment.ogScrapeUrl;
|
|
||||||
return GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
final ogScrapeUrl = attachment.ogScrapeUrl;
|
|
||||||
if (ogScrapeUrl != null) launchURL(context, ogScrapeUrl);
|
|
||||||
},
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(8),
|
|
||||||
child: Column(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: <Widget>[
|
|
||||||
if (attachment.title != null)
|
|
||||||
Text(
|
|
||||||
attachment.title!,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: messageTheme.messageTextStyle?.copyWith(
|
|
||||||
color: StreamChatTheme.of(context).colorTheme.accentPrimary,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (ogScrapeUrl != null)
|
|
||||||
Text(ogScrapeUrl, style: messageTheme.messageTextStyle),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -68,67 +68,39 @@ class StreamGiphyAttachment extends StatelessWidget {
|
|||||||
borderRadius: BorderRadius.circular(14),
|
borderRadius: BorderRadius.circular(14),
|
||||||
);
|
);
|
||||||
|
|
||||||
return Hero(
|
return Container(
|
||||||
tag: giphy.id,
|
constraints: constraints,
|
||||||
child: Container(
|
clipBehavior: Clip.hardEdge,
|
||||||
constraints: constraints,
|
decoration: ShapeDecoration(shape: shape),
|
||||||
clipBehavior: Clip.hardEdge,
|
child: AspectRatio(
|
||||||
decoration: ShapeDecoration(shape: shape),
|
aspectRatio: giphySize?.aspectRatio ?? 1,
|
||||||
child: AspectRatio(
|
child: Stack(
|
||||||
aspectRatio: giphySize?.aspectRatio ?? 1,
|
alignment: Alignment.center,
|
||||||
child: Stack(
|
children: [
|
||||||
alignment: Alignment.center,
|
StreamGiphyAttachmentThumbnail(
|
||||||
children: [
|
type: type,
|
||||||
StreamGiphyAttachmentThumbnail(
|
giphy: giphy,
|
||||||
type: type,
|
fit: fit,
|
||||||
giphy: giphy,
|
width: double.infinity,
|
||||||
fit: fit,
|
height: double.infinity,
|
||||||
width: double.infinity,
|
),
|
||||||
height: double.infinity,
|
if (giphy.uploadState.isSuccess)
|
||||||
),
|
const Positioned(
|
||||||
if (giphy.uploadState.isSuccess)
|
bottom: 8,
|
||||||
const Positioned(
|
left: 8,
|
||||||
bottom: 8,
|
child: GiphyChip(),
|
||||||
left: 8,
|
)
|
||||||
child: GiphyChip(),
|
else
|
||||||
)
|
Padding(
|
||||||
else
|
padding: const EdgeInsets.all(8),
|
||||||
Padding(
|
child: StreamAttachmentUploadStateBuilder(
|
||||||
padding: const EdgeInsets.all(8),
|
message: message,
|
||||||
child: StreamAttachmentUploadStateBuilder(
|
attachment: giphy,
|
||||||
message: message,
|
|
||||||
attachment: giphy,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Future<void> _onTap(BuildContext context) async {
|
|
||||||
// if (onAttachmentTap != null) {
|
|
||||||
// return onAttachmentTap!();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// await Navigator.of(context).push(
|
|
||||||
// MaterialPageRoute(
|
|
||||||
// builder: (_) {
|
|
||||||
// final channel = StreamChannel.of(context).channel;
|
|
||||||
// return StreamChannel(
|
|
||||||
// channel: channel,
|
|
||||||
// child: StreamFullScreenMediaBuilder(
|
|
||||||
// mediaAttachmentPackages: message.getAttachmentPackageList(),
|
|
||||||
// startIndex: message.attachments.indexOf(giphy),
|
|
||||||
// userName: message.user!.name,
|
|
||||||
// onShowMessage: onShowMessage,
|
|
||||||
// onReplyMessage: onReplyMessage,
|
|
||||||
// attachmentActionsModalBuilder: attachmentActionsModalBuilder,
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,31 +103,3 @@ class StreamImageAttachment extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Future<void> _onTap(
|
|
||||||
// BuildContext context,
|
|
||||||
// int index,
|
|
||||||
// ) async {
|
|
||||||
// if (onAttachmentTap != null) {
|
|
||||||
// return onAttachmentTap!();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// final channel = StreamChannel.of(context).channel;
|
|
||||||
//
|
|
||||||
// Navigator.of(context).push(
|
|
||||||
// MaterialPageRoute(
|
|
||||||
// builder: (context) => StreamChannel(
|
|
||||||
// channel: channel,
|
|
||||||
// child: StreamFullScreenMediaBuilder(
|
|
||||||
// mediaAttachmentPackages: message.getAttachmentPackageList(),
|
|
||||||
// startIndex: index,
|
|
||||||
// userName: message.user!.name,
|
|
||||||
// onShowMessage: onShowMessage,
|
|
||||||
// onReplyMessage: onReplyMessage,
|
|
||||||
// attachmentActionsModalBuilder: attachmentActionsModalBuilder,
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|||||||
@@ -2,14 +2,11 @@ import 'dart:async';
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:chewie/chewie.dart';
|
import 'package:chewie/chewie.dart';
|
||||||
import 'package:contextmenu/contextmenu.dart';
|
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:photo_view/photo_view.dart';
|
import 'package:photo_view/photo_view.dart';
|
||||||
import 'package:stream_chat_flutter/platform_widget_builder/platform_widget_builder.dart';
|
|
||||||
import 'package:stream_chat_flutter/src/attachment/thumbnail/media_attachment_thumbnail.dart';
|
import 'package:stream_chat_flutter/src/attachment/thumbnail/media_attachment_thumbnail.dart';
|
||||||
import 'package:stream_chat_flutter/src/context_menu_items/download_menu_item.dart';
|
|
||||||
import 'package:stream_chat_flutter/src/fullscreen_media/full_screen_media_widget.dart';
|
import 'package:stream_chat_flutter/src/fullscreen_media/full_screen_media_widget.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/fullscreen_media/gallery_navigation_item.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
import 'package:video_player/video_player.dart';
|
import 'package:video_player/video_player.dart';
|
||||||
|
|
||||||
@@ -291,22 +288,16 @@ class _FullScreenMediaState extends State<StreamFullScreenMedia> {
|
|||||||
? StreamChannelHeaderTheme.of(context).color
|
? StreamChannelHeaderTheme.of(context).color
|
||||||
: Colors.black,
|
: Colors.black,
|
||||||
duration: kThemeAnimationDuration,
|
duration: kThemeAnimationDuration,
|
||||||
child: ContextMenuArea(
|
child: PhotoView.customChild(
|
||||||
verticalPadding: 0,
|
maxScale: PhotoViewComputedScale.covered,
|
||||||
builder: (_) => [
|
minScale: PhotoViewComputedScale.contained,
|
||||||
DownloadMenuItem(attachment: attachment),
|
backgroundDecoration: const BoxDecoration(
|
||||||
],
|
color: Colors.transparent,
|
||||||
child: PhotoView.customChild(
|
),
|
||||||
maxScale: PhotoViewComputedScale.covered,
|
child: StreamMediaAttachmentThumbnail(
|
||||||
minScale: PhotoViewComputedScale.contained,
|
media: attachment,
|
||||||
backgroundDecoration: const BoxDecoration(
|
width: double.infinity,
|
||||||
color: Colors.transparent,
|
height: double.infinity,
|
||||||
),
|
|
||||||
child: StreamMediaAttachmentThumbnail(
|
|
||||||
media: attachment,
|
|
||||||
width: double.infinity,
|
|
||||||
height: double.infinity,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -318,19 +309,11 @@ class _FullScreenMediaState extends State<StreamFullScreenMedia> {
|
|||||||
child: CircularProgressIndicator.adaptive(),
|
child: CircularProgressIndicator.adaptive(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: switchDisplayingDetail,
|
onTap: switchDisplayingDetail,
|
||||||
child: Padding(
|
child: Chewie(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 50),
|
controller: controller.chewieController!,
|
||||||
child: ContextMenuArea(
|
|
||||||
verticalPadding: 0,
|
|
||||||
builder: (_) => [
|
|
||||||
DownloadMenuItem(attachment: attachment),
|
|
||||||
],
|
|
||||||
child: Chewie(
|
|
||||||
controller: controller.chewieController!,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -344,74 +327,6 @@ class _FullScreenMediaState extends State<StreamFullScreenMedia> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A widget for desktop and web users to be able to navigate left and right
|
|
||||||
/// through a gallery of images.
|
|
||||||
class GalleryNavigationItem extends StatelessWidget {
|
|
||||||
/// Builds a [GalleryNavigationItem].
|
|
||||||
const GalleryNavigationItem({
|
|
||||||
super.key,
|
|
||||||
required this.icon,
|
|
||||||
this.iconSize = 48,
|
|
||||||
required this.onPressed,
|
|
||||||
required this.opacityAnimation,
|
|
||||||
this.left,
|
|
||||||
this.right,
|
|
||||||
});
|
|
||||||
|
|
||||||
/// The icon to display.
|
|
||||||
final Widget icon;
|
|
||||||
|
|
||||||
/// The size of the icon.
|
|
||||||
///
|
|
||||||
/// Defaults to 48.
|
|
||||||
final double iconSize;
|
|
||||||
|
|
||||||
/// The callback to perform when the button is clicked.
|
|
||||||
final VoidCallback onPressed;
|
|
||||||
|
|
||||||
/// The animation for showing & hiding this widget.
|
|
||||||
final ValueListenable<bool> opacityAnimation;
|
|
||||||
|
|
||||||
/// The left-hand placement of the button.
|
|
||||||
final double? left;
|
|
||||||
|
|
||||||
/// The right-hand placement of the button.
|
|
||||||
final double? right;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return PlatformWidgetBuilder(
|
|
||||||
desktop: (_, child) => child,
|
|
||||||
web: (_, child) => child,
|
|
||||||
child: Positioned(
|
|
||||||
left: left,
|
|
||||||
right: right,
|
|
||||||
top: MediaQuery.of(context).size.height / 2,
|
|
||||||
child: ValueListenableBuilder<bool>(
|
|
||||||
valueListenable: opacityAnimation,
|
|
||||||
builder: (context, shouldShow, child) {
|
|
||||||
return AnimatedOpacity(
|
|
||||||
opacity: shouldShow ? 1 : 0,
|
|
||||||
duration: kThemeAnimationDuration,
|
|
||||||
child: child,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
type: MaterialType.circle,
|
|
||||||
clipBehavior: Clip.antiAlias,
|
|
||||||
child: IconButton(
|
|
||||||
icon: icon,
|
|
||||||
iconSize: iconSize,
|
|
||||||
onPressed: onPressed,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Class for packaging up things required for videos
|
/// Class for packaging up things required for videos
|
||||||
class VideoPackage {
|
class VideoPackage {
|
||||||
/// Constructor for creating [VideoPackage]
|
/// Constructor for creating [VideoPackage]
|
||||||
|
|||||||
+16
-118
@@ -1,13 +1,13 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
|
||||||
import 'package:contextmenu/contextmenu.dart';
|
import 'package:contextmenu/contextmenu.dart';
|
||||||
import 'package:dart_vlc/dart_vlc.dart';
|
import 'package:dart_vlc/dart_vlc.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:photo_view/photo_view.dart';
|
import 'package:photo_view/photo_view.dart';
|
||||||
import 'package:shimmer/shimmer.dart';
|
|
||||||
import 'package:stream_chat_flutter/platform_widget_builder/platform_widget_builder.dart';
|
import 'package:stream_chat_flutter/platform_widget_builder/platform_widget_builder.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/attachment/thumbnail/media_attachment_thumbnail.dart';
|
||||||
import 'package:stream_chat_flutter/src/context_menu_items/download_menu_item.dart';
|
import 'package:stream_chat_flutter/src/context_menu_items/download_menu_item.dart';
|
||||||
import 'package:stream_chat_flutter/src/fullscreen_media/full_screen_media_widget.dart';
|
import 'package:stream_chat_flutter/src/fullscreen_media/full_screen_media_widget.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/fullscreen_media/gallery_navigation_item.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
/// Returns an instance of [FullScreenMediaDesktop].
|
/// Returns an instance of [FullScreenMediaDesktop].
|
||||||
@@ -310,9 +310,6 @@ class _FullScreenMediaDesktopState extends State<FullScreenMediaDesktop> {
|
|||||||
final attachment = currentAttachmentPackage.attachment;
|
final attachment = currentAttachmentPackage.attachment;
|
||||||
if (attachment.type == AttachmentType.image ||
|
if (attachment.type == AttachmentType.image ||
|
||||||
attachment.type == AttachmentType.giphy) {
|
attachment.type == AttachmentType.giphy) {
|
||||||
final imageUrl = attachment.imageUrl ??
|
|
||||||
attachment.assetUrl ??
|
|
||||||
attachment.thumbUrl;
|
|
||||||
return ValueListenableBuilder<bool>(
|
return ValueListenableBuilder<bool>(
|
||||||
valueListenable: _isDisplayingDetail,
|
valueListenable: _isDisplayingDetail,
|
||||||
builder: (context, isDisplayingDetail, _) =>
|
builder: (context, isDisplayingDetail, _) =>
|
||||||
@@ -324,39 +321,19 @@ class _FullScreenMediaDesktopState extends State<FullScreenMediaDesktop> {
|
|||||||
child: ContextMenuArea(
|
child: ContextMenuArea(
|
||||||
verticalPadding: 0,
|
verticalPadding: 0,
|
||||||
builder: (_) => [
|
builder: (_) => [
|
||||||
DownloadMenuItem(
|
DownloadMenuItem(attachment: attachment),
|
||||||
attachment: attachment,
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
child: PhotoView(
|
child: PhotoView.customChild(
|
||||||
imageProvider: (imageUrl == null &&
|
|
||||||
attachment.localUri != null &&
|
|
||||||
attachment.file?.bytes != null)
|
|
||||||
? Image.memory(attachment.file!.bytes!).image
|
|
||||||
: CachedNetworkImageProvider(imageUrl!),
|
|
||||||
errorBuilder: (_, __, ___) => const AttachmentError(),
|
|
||||||
loadingBuilder: (context, _) {
|
|
||||||
final image = Image.asset(
|
|
||||||
'images/placeholder.png',
|
|
||||||
fit: BoxFit.cover,
|
|
||||||
package: 'stream_chat_flutter',
|
|
||||||
);
|
|
||||||
final colorTheme =
|
|
||||||
StreamChatTheme.of(context).colorTheme;
|
|
||||||
return Shimmer.fromColors(
|
|
||||||
baseColor: colorTheme.disabled,
|
|
||||||
highlightColor: colorTheme.inputBg,
|
|
||||||
child: image,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
maxScale: PhotoViewComputedScale.covered,
|
maxScale: PhotoViewComputedScale.covered,
|
||||||
minScale: PhotoViewComputedScale.contained,
|
minScale: PhotoViewComputedScale.contained,
|
||||||
heroAttributes: PhotoViewHeroAttributes(
|
|
||||||
tag: widget.mediaAttachmentPackages,
|
|
||||||
),
|
|
||||||
backgroundDecoration: const BoxDecoration(
|
backgroundDecoration: const BoxDecoration(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
),
|
),
|
||||||
|
child: StreamMediaAttachmentThumbnail(
|
||||||
|
media: attachment,
|
||||||
|
width: double.infinity,
|
||||||
|
height: double.infinity,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -364,29 +341,18 @@ class _FullScreenMediaDesktopState extends State<FullScreenMediaDesktop> {
|
|||||||
} else if (attachment.type == AttachmentType.video) {
|
} else if (attachment.type == AttachmentType.video) {
|
||||||
final package = videoPackages[attachment.id]!;
|
final package = videoPackages[attachment.id]!;
|
||||||
package.player.open(
|
package.player.open(
|
||||||
Playlist(
|
Media.network(package.attachment.assetUrl),
|
||||||
medias: [
|
|
||||||
Media.network(package.attachment.assetUrl),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
autoStart: widget.autoplayVideos,
|
autoStart: widget.autoplayVideos,
|
||||||
);
|
);
|
||||||
|
|
||||||
return InkWell(
|
return InkWell(
|
||||||
onTap: switchDisplayingDetail,
|
onTap: switchDisplayingDetail,
|
||||||
child: Padding(
|
child: ContextMenuArea(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 50),
|
verticalPadding: 0,
|
||||||
child: ContextMenuArea(
|
builder: (_) => [
|
||||||
verticalPadding: 0,
|
DownloadMenuItem(attachment: attachment),
|
||||||
builder: (_) => [
|
],
|
||||||
DownloadMenuItem(
|
child: Video(player: package.player),
|
||||||
attachment: attachment,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
child: Video(
|
|
||||||
player: package.player,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -399,74 +365,6 @@ class _FullScreenMediaDesktopState extends State<FullScreenMediaDesktop> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A widget for desktop and web users to be able to navigate left and right
|
|
||||||
/// through a gallery of images.
|
|
||||||
class GalleryNavigationItem extends StatelessWidget {
|
|
||||||
/// Builds a [GalleryNavigationItem].
|
|
||||||
const GalleryNavigationItem({
|
|
||||||
super.key,
|
|
||||||
required this.icon,
|
|
||||||
this.iconSize = 48,
|
|
||||||
required this.onPressed,
|
|
||||||
required this.opacityAnimation,
|
|
||||||
this.left,
|
|
||||||
this.right,
|
|
||||||
});
|
|
||||||
|
|
||||||
/// The icon to display.
|
|
||||||
final Widget icon;
|
|
||||||
|
|
||||||
/// The size of the icon.
|
|
||||||
///
|
|
||||||
/// Defaults to 48.
|
|
||||||
final double iconSize;
|
|
||||||
|
|
||||||
/// The callback to perform when the button is clicked.
|
|
||||||
final VoidCallback onPressed;
|
|
||||||
|
|
||||||
/// The animation for showing & hiding this widget.
|
|
||||||
final ValueListenable<bool> opacityAnimation;
|
|
||||||
|
|
||||||
/// The left-hand placement of the button.
|
|
||||||
final double? left;
|
|
||||||
|
|
||||||
/// The right-hand placement of the button.
|
|
||||||
final double? right;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return PlatformWidgetBuilder(
|
|
||||||
desktop: (_, child) => child,
|
|
||||||
web: (_, child) => child,
|
|
||||||
child: Positioned(
|
|
||||||
left: left,
|
|
||||||
right: right,
|
|
||||||
top: MediaQuery.of(context).size.height / 2,
|
|
||||||
child: ValueListenableBuilder<bool>(
|
|
||||||
valueListenable: opacityAnimation,
|
|
||||||
builder: (context, shouldShow, child) {
|
|
||||||
return AnimatedOpacity(
|
|
||||||
opacity: shouldShow ? 1 : 0,
|
|
||||||
duration: kThemeAnimationDuration,
|
|
||||||
child: child,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
child: Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
type: MaterialType.circle,
|
|
||||||
clipBehavior: Clip.antiAlias,
|
|
||||||
child: IconButton(
|
|
||||||
icon: icon,
|
|
||||||
iconSize: iconSize,
|
|
||||||
onPressed: onPressed,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Class for packaging up things required for videos
|
/// Class for packaging up things required for videos
|
||||||
class DesktopVideoPackage {
|
class DesktopVideoPackage {
|
||||||
/// Constructor for creating [VideoPackage]
|
/// Constructor for creating [VideoPackage]
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:stream_chat_flutter/platform_widget_builder/src/platform_widget_builder.dart';
|
||||||
|
|
||||||
|
/// A widget for desktop and web users to be able to navigate left and right
|
||||||
|
/// through a gallery of images.
|
||||||
|
class GalleryNavigationItem extends StatelessWidget {
|
||||||
|
/// Builds a [GalleryNavigationItem].
|
||||||
|
const GalleryNavigationItem({
|
||||||
|
super.key,
|
||||||
|
required this.icon,
|
||||||
|
this.iconSize = 48,
|
||||||
|
required this.onPressed,
|
||||||
|
required this.opacityAnimation,
|
||||||
|
this.left,
|
||||||
|
this.right,
|
||||||
|
});
|
||||||
|
|
||||||
|
/// The icon to display.
|
||||||
|
final Widget icon;
|
||||||
|
|
||||||
|
/// The size of the icon.
|
||||||
|
///
|
||||||
|
/// Defaults to 48.
|
||||||
|
final double iconSize;
|
||||||
|
|
||||||
|
/// The callback to perform when the button is clicked.
|
||||||
|
final VoidCallback onPressed;
|
||||||
|
|
||||||
|
/// The animation for showing & hiding this widget.
|
||||||
|
final ValueListenable<bool> opacityAnimation;
|
||||||
|
|
||||||
|
/// The left-hand placement of the button.
|
||||||
|
final double? left;
|
||||||
|
|
||||||
|
/// The right-hand placement of the button.
|
||||||
|
final double? right;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return PlatformWidgetBuilder(
|
||||||
|
desktop: (_, child) => child,
|
||||||
|
web: (_, child) => child,
|
||||||
|
child: Positioned(
|
||||||
|
left: left,
|
||||||
|
right: right,
|
||||||
|
top: MediaQuery.of(context).size.height / 2,
|
||||||
|
child: ValueListenableBuilder<bool>(
|
||||||
|
valueListenable: opacityAnimation,
|
||||||
|
builder: (context, shouldShow, child) {
|
||||||
|
return AnimatedOpacity(
|
||||||
|
opacity: shouldShow ? 1 : 0,
|
||||||
|
duration: kThemeAnimationDuration,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
type: MaterialType.circle,
|
||||||
|
clipBehavior: Clip.antiAlias,
|
||||||
|
child: IconButton(
|
||||||
|
icon: icon,
|
||||||
|
iconSize: iconSize,
|
||||||
|
onPressed: onPressed,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/platform_widget_builder/platform_widget_builder.dart';
|
|
||||||
import 'package:stream_chat_flutter/src/attachment/thumbnail/file_attachment_thumbnail.dart';
|
import 'package:stream_chat_flutter/src/attachment/thumbnail/file_attachment_thumbnail.dart';
|
||||||
import 'package:stream_chat_flutter/src/attachment/thumbnail/image_attachment_thumbnail.dart';
|
import 'package:stream_chat_flutter/src/attachment/thumbnail/image_attachment_thumbnail.dart';
|
||||||
import 'package:stream_chat_flutter/src/message_input/clear_input_item_button.dart';
|
import 'package:stream_chat_flutter/src/message_input/clear_input_item_button.dart';
|
||||||
@@ -178,16 +177,10 @@ class _QuotedMessage extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add clear button if needed.
|
// Add clear button if needed.
|
||||||
if (onQuotedMessageClear != null) {
|
if (isDesktopDeviceOrWeb && onQuotedMessageClear != null) {
|
||||||
children.insert(
|
children.insert(
|
||||||
0,
|
0,
|
||||||
PlatformWidgetBuilder(
|
ClearInputItemButton(onTap: onQuotedMessageClear),
|
||||||
web: (context, child) => child,
|
|
||||||
desktop: (context, child) => child,
|
|
||||||
child: ClearInputItemButton(
|
|
||||||
onTap: onQuotedMessageClear,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ export 'package:stream_chat_flutter/src/message_widget/quoted_message.dart';
|
|||||||
export 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
export 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
|
||||||
export 'src/attachment/attachment.dart';
|
export 'src/attachment/attachment.dart';
|
||||||
export 'src/attachment/attachment_title.dart';
|
|
||||||
export 'src/attachment/gallery_attachment.dart';
|
export 'src/attachment/gallery_attachment.dart';
|
||||||
export 'src/attachment/handler/stream_attachment_handler.dart';
|
export 'src/attachment/handler/stream_attachment_handler.dart';
|
||||||
export 'src/attachment/image_attachment.dart';
|
export 'src/attachment/image_attachment.dart';
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|
||||||
|
|
||||||
import '../mocks.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
testWidgets('AttachmentError test', (tester) async {
|
|
||||||
await tester.pumpWidget(
|
|
||||||
MaterialApp(
|
|
||||||
builder: (context, child) => StreamChat(
|
|
||||||
client: MockClient(),
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
home: const Scaffold(
|
|
||||||
body: Center(
|
|
||||||
child: AttachmentError(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(find.byType(Icon), findsOneWidget);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|
||||||
|
|
||||||
import '../mocks.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
testWidgets('AttachmentTitle renders properly', (tester) async {
|
|
||||||
final mockClient = MockClient();
|
|
||||||
await tester.pumpWidget(
|
|
||||||
MaterialApp(
|
|
||||||
builder: (context, child) => StreamChat(
|
|
||||||
client: mockClient,
|
|
||||||
streamChatThemeData: StreamChatThemeData.light(),
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
home: Scaffold(
|
|
||||||
body: Builder(
|
|
||||||
builder: (context) {
|
|
||||||
return Center(
|
|
||||||
child: StreamAttachmentTitle(
|
|
||||||
attachment: Attachment(
|
|
||||||
title: 'Test Attachment',
|
|
||||||
type: 'video',
|
|
||||||
titleLink: 'https://www.youtube.com/watch?v=lytQi-slT5Y',
|
|
||||||
ogScrapeUrl: 'https://www.youtube.com/watch?v=lytQi-slT5Y',
|
|
||||||
),
|
|
||||||
messageTheme: StreamChatTheme.of(context).ownMessageTheme,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(find.byType(StreamAttachmentTitle), findsOneWidget);
|
|
||||||
expect(find.text('Test Attachment'), findsOneWidget);
|
|
||||||
expect(find.text('https://www.youtube.com/watch?v=lytQi-slT5Y'),
|
|
||||||
findsOneWidget);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user