This commit is contained in:
Deven Joshi
2021-05-05 17:47:58 +05:30
parent dca6b10c41
commit 09c6799af8
4 changed files with 81 additions and 69 deletions
@@ -2,7 +2,10 @@ import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/src/user_avatar.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
/// Displays a list of users who reacted
class UserReactionDisplay extends StatelessWidget {
/// Constructor for creating a [UserReactionDisplay]
const UserReactionDisplay({
Key? key,
required this.reactionToEmoji,
@@ -10,13 +13,17 @@ class UserReactionDisplay extends StatelessWidget {
this.size = 30,
}) : super(key: key);
/// Reaction map
final Map<String, String> reactionToEmoji;
/// Message which is reacted to
final Message message;
/// Size of Icon
final double size;
@override
Widget build(BuildContext context) {
return Container(
Widget build(BuildContext context) => Container(
color: Colors.black87,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -25,9 +32,8 @@ class UserReactionDisplay extends StatelessWidget {
children: reactionToEmoji.keys.map((reactionType) {
final firstUserReaction = message.latestReactions!
.firstWhere((element) => element.type == reactionType,
orElse: () {
return null;
} as Reaction Function()?);
//ignore: unnecessary_parenthesis
orElse: (() => null) as Reaction Function()?);
if (firstUserReaction.user == null) {
return IconButton(
@@ -52,5 +58,4 @@ class UserReactionDisplay extends StatelessWidget {
}).toList(),
),
);
}
}
+20 -25
View File
@@ -13,7 +13,7 @@ Future<void> launchURL(BuildContext context, String? url) async {
} else {
// ignore: deprecated_member_use
Scaffold.of(context).showSnackBar(
SnackBar(
const SnackBar(
content: Text('Cannot launch the url'),
),
);
@@ -27,11 +27,10 @@ Future<bool?> showConfirmationDialog(
Widget? icon,
String? question,
String? cancelText,
}) {
return showModalBottomSheet(
}) => showModalBottomSheet(
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
context: context,
shape: RoundedRectangleBorder(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16),
@@ -42,20 +41,20 @@ Future<bool?> showConfirmationDialog(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(height: 26),
const SizedBox(height: 26),
if (icon != null) icon,
SizedBox(height: 26),
const SizedBox(height: 26),
Text(
title,
style: StreamChatTheme.of(context).textTheme.headlineBold,
),
SizedBox(height: 7),
const SizedBox(height: 7),
if (question != null)
Text(
question,
textAlign: TextAlign.center,
),
SizedBox(height: 36),
const SizedBox(height: 36),
Container(
color: effect.color!.withOpacity(effect.alpha ?? 1),
height: 1,
@@ -110,8 +109,8 @@ Future<bool?> showConfirmationDialog(
),
);
});
}
/// Shows info dialog
Future<bool?> showInfoDialog(
BuildContext context, {
required String title,
@@ -119,26 +118,24 @@ Future<bool?> showInfoDialog(
Widget? icon,
String? details,
StreamChatThemeData? theme,
}) {
return showModalBottomSheet(
}) => showModalBottomSheet(
backgroundColor:
theme?.colorTheme.white ?? StreamChatTheme.of(context).colorTheme.white,
context: context,
shape: RoundedRectangleBorder(
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16),
)),
builder: (context) {
return SafeArea(
builder: (context) => SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
const SizedBox(
height: 26,
),
if (icon != null) icon,
SizedBox(
const SizedBox(
height: 26,
),
Text(
@@ -146,11 +143,11 @@ Future<bool?> showInfoDialog(
style: theme?.textTheme.headlineBold ??
StreamChatTheme.of(context).textTheme.headlineBold,
),
SizedBox(
const SizedBox(
height: 7,
),
if (details != null) Text(details),
SizedBox(
const SizedBox(
height: 36,
),
Container(
@@ -175,10 +172,8 @@ Future<bool?> showInfoDialog(
),
],
),
);
},
),
);
}
/// Get random png with initials
String getRandomPicUrl(User user) =>
@@ -335,15 +330,16 @@ StreamSvgIcon getFileTypeImage(String? type) {
}
}
/// Wraps attachment widget with custom shape
Widget wrapAttachmentWidget(
BuildContext context,
Widget attachmentWidget,
ShapeBorder attachmentShape,
// ignore: avoid_positional_boolean_parameters
bool reverse,
BorderRadius borderRadius,
) {
return ClipRRect(
borderRadius: borderRadius,
) => ClipRRect(
borderRadius: borderRadius,
child: Material(
clipBehavior: Clip.antiAlias,
shape: attachmentShape,
@@ -355,4 +351,3 @@ Widget wrapAttachmentWidget(
),
),
);
}
@@ -5,12 +5,14 @@ import 'package:synchronized/synchronized.dart';
import 'package:video_compress/video_compress.dart';
import 'package:video_thumbnail/video_thumbnail.dart';
///
class IVideoService {
IVideoService._();
/// Singleton instance of [IVideoService]
static final IVideoService instance = IVideoService._();
final _lock = Lock();
IVideoService._();
/// compress video from [path]
/// compress video from [path] return [Future<MediaInfo>]
///
@@ -26,18 +28,20 @@ class IVideoService {
/// );
/// debugPrint(info.toJson());
/// ```
Future<MediaInfo?> compressVideo(String? path) async {
return _lock.synchronized(() {
return VideoCompress.compressVideo(
path!,
Future<MediaInfo?> compressVideo(String? path) async => _lock.synchronized(
() => VideoCompress.compressVideo(
path!,
),
);
});
}
/// Generates a thumbnail image data in memory as UInt8List, it can be easily used by Image.memory(...).
/// The video can be a local video file, or an URL repreents iOS or Android native supported video format.
/// Speicify the maximum height or width for the thumbnail or 0 for same resolution as the original video.
/// The lower quality value creates lower quality of the thumbnail image, but it gets ignored for PNG format.
/// Generates a thumbnail image data in memory as UInt8List,
/// it can be easily used by Image.memory(...).
/// The video can be a local video file, or an URL repreents iOS or
/// Android native supported video format.
/// Speicify the maximum height or width for the thumbnail or 0 for
/// same resolution as the original video.
/// The lower quality value creates lower quality of the thumbnail image,
/// but it gets ignored for PNG format.
Future<Uint8List?> generateVideoThumbnail({
required String video,
ImageFormat imageFormat = ImageFormat.PNG,
@@ -45,17 +49,17 @@ class IVideoService {
int maxWidth = 0,
int timeMs = 0,
int quality = 10,
}) {
return VideoThumbnail.thumbnailData(
video: video,
imageFormat: imageFormat,
maxHeight: maxHeight,
maxWidth: maxWidth,
timeMs: timeMs,
quality: quality,
);
}
}) =>
VideoThumbnail.thumbnailData(
video: video,
imageFormat: imageFormat,
maxHeight: maxHeight,
maxWidth: maxWidth,
timeMs: timeMs,
quality: quality,
);
}
// ignore: non_constant_identifier_names
/// Get instance of [IVideoService]
IVideoService get VideoService => IVideoService.instance;
@@ -9,14 +9,7 @@ import 'stream_svg_icon.dart';
import 'video_service.dart';
class VideoThumbnailImage extends StatefulWidget {
final String video;
final double? width;
final double? height;
final BoxFit? fit;
final ImageFormat format;
final Widget Function(BuildContext, Object?)? errorBuilder;
final WidgetBuilder? placeholderBuilder;
/// Constructor for creating [VideoThumbnailImage]
const VideoThumbnailImage({
Key? key,
required this.video,
@@ -28,6 +21,25 @@ class VideoThumbnailImage extends StatefulWidget {
this.placeholderBuilder,
}) : super(key: key);
/// Video path
final String video;
/// Width of widget
final double? width;
/// Height of widget
final double? height;
/// Fit of iamge
final BoxFit? fit;
/// Image format
final ImageFormat format;
/// Builds widget on error
final Widget Function(BuildContext, Object?)? errorBuilder;
final WidgetBuilder? placeholderBuilder;
@override
_VideoThumbnailImageState createState() => _VideoThumbnailImageState();
}
@@ -56,11 +68,9 @@ class _VideoThumbnailImageState extends State<VideoThumbnailImage> {
}
@override
Widget build(BuildContext context) {
return FutureBuilder<Uint8List?>(
Widget build(BuildContext context) => FutureBuilder<Uint8List?>(
future: thumbnailFuture,
builder: (context, snapshot) {
return AnimatedSwitcher(
builder: (context, snapshot) => AnimatedSwitcher(
duration: const Duration(milliseconds: 350),
child: Builder(
key: ValueKey<AsyncSnapshot<Uint8List?>>(snapshot),
@@ -73,7 +83,7 @@ class _VideoThumbnailImageState extends State<VideoThumbnailImage> {
}
if (!snapshot.hasData) {
return Container(
constraints: BoxConstraints.expand(),
constraints: const BoxConstraints.expand(),
child: widget.placeholderBuilder?.call(context) ??
Shimmer.fromColors(
baseColor: StreamChatTheme.of(context)
@@ -97,8 +107,6 @@ class _VideoThumbnailImageState extends State<VideoThumbnailImage> {
);
},
),
);
},
),
);
}
}