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