chore(repo): fix lints

Signed-off-by: xsahil03x <[email protected]>
This commit is contained in:
Sahil Kumar
2021-10-01 16:45:16 +05:30
committed by xsahil03x
parent 6e48f9754d
commit ca7cf541a7
76 changed files with 1004 additions and 969 deletions
@@ -141,7 +141,7 @@ class _PreparingState extends StatelessWidget {
uploaded: 0,
total: double.maxFinite.toInt(),
),
)
),
],
);
}
@@ -181,7 +181,7 @@ class _InProgressState extends StatelessWidget {
uploaded: sent,
total: total,
),
)
),
],
);
}
@@ -234,7 +234,7 @@ class _FailedState extends StatelessWidget {
),
),
),
)
),
],
);
}
@@ -78,7 +78,7 @@ class AttachmentError extends StatelessWidget {
color: StreamChatTheme.of(context)
.colorTheme
.accentError
.withOpacity(.1),
.withOpacity(0.1),
child: Center(
child: Icon(
Icons.error_outline,
@@ -253,7 +253,8 @@ class FileAttachment extends AttachmentWidget {
if (message.status == MessageSendingStatus.sent) {
trailingWidget = IconButton(
icon: StreamSvgIcon.cloudDownload(
color: theme.colorTheme.textHighEmphasis),
color: theme.colorTheme.textHighEmphasis,
),
visualDensity: VisualDensity.compact,
splashRadius: 16,
onPressed: () {
@@ -297,7 +297,7 @@ class GiphyAttachment extends AttachmentWidget {
color: StreamChatTheme.of(context)
.colorTheme
.textHighEmphasis
.withOpacity(.5),
.withOpacity(0.5),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
@@ -54,136 +54,134 @@ class AttachmentActionsModal extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.end,
children: [
const SizedBox(height: kToolbarHeight),
Padding(
Container(
padding: const EdgeInsets.only(right: 8),
child: Container(
width: MediaQuery.of(context).size.width * 0.5,
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
),
child: SizedBox(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
children: [
_buildButton(
context,
context.translations.replyLabel,
StreamSvgIcon.iconCurveLineLeftUp(
size: 24,
color: theme.colorTheme.textLowEmphasis,
),
() {
Navigator.pop(context, ReturnActionType.reply);
},
width: MediaQuery.of(context).size.width * 0.5,
clipBehavior: Clip.hardEdge,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
),
child: SizedBox(
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisSize: MainAxisSize.min,
children: [
_buildButton(
context,
context.translations.replyLabel,
StreamSvgIcon.iconCurveLineLeftUp(
size: 24,
color: theme.colorTheme.textLowEmphasis,
),
_buildButton(
context,
context.translations.showInChatLabel,
StreamSvgIcon.eye(
size: 24,
color: theme.colorTheme.textHighEmphasis,
),
onShowMessage,
() {
Navigator.pop(context, ReturnActionType.reply);
},
),
_buildButton(
context,
context.translations.showInChatLabel,
StreamSvgIcon.eye(
size: 24,
color: theme.colorTheme.textHighEmphasis,
),
_buildButton(
context,
message.attachments[currentIndex].type == 'video'
? context.translations.saveVideoLabel
: context.translations.saveImageLabel,
StreamSvgIcon.iconSave(
size: 24,
color: theme.colorTheme.textLowEmphasis,
),
() {
final attachment = message.attachments[currentIndex];
final isImage = attachment.type == 'image';
final Future<String?> Function(Attachment,
{void Function(int, int) progressCallback})
saveFile = fileDownloader ?? _downloadAttachment;
final Future<String?> Function(Attachment,
{void Function(int, int) progressCallback})
saveImage = imageDownloader ?? _downloadAttachment;
final downloader = isImage ? saveImage : saveFile;
final progressNotifier =
ValueNotifier<_DownloadProgress?>(
_DownloadProgress.initial(),
);
downloader(
attachment,
progressCallback: (received, total) {
progressNotifier.value = _DownloadProgress(
total,
received,
);
},
).catchError((e, stk) {
progressNotifier.value = null;
});
// Closing attachment actions modal before opening
// attachment download dialog
Navigator.pop(context);
showDialog(
barrierDismissible: false,
context: context,
barrierColor: theme.colorTheme.overlay,
builder: (context) => _buildDownloadProgressDialog(
context,
progressNotifier,
),
);
},
onShowMessage,
),
_buildButton(
context,
message.attachments[currentIndex].type == 'video'
? context.translations.saveVideoLabel
: context.translations.saveImageLabel,
StreamSvgIcon.iconSave(
size: 24,
color: theme.colorTheme.textLowEmphasis,
),
if (StreamChat.of(context).currentUser?.id ==
message.user?.id)
_buildButton(
context,
context.translations.deleteLabel.capitalize(),
StreamSvgIcon.delete(
size: 24,
color: theme.colorTheme.accentError,
),
() {
final channel = StreamChannel.of(context).channel;
if (message.attachments.length > 1 ||
message.text?.isNotEmpty == true) {
final remainingAttachments = [...message.attachments]
..removeAt(currentIndex);
channel.updateMessage(message.copyWith(
attachments: remainingAttachments,
));
Navigator.of(context)
..pop()
..maybePop();
} else {
channel.deleteMessage(message);
Navigator.of(context)
..pop()
..maybePop();
}
() {
final attachment = message.attachments[currentIndex];
final isImage = attachment.type == 'image';
final Future<String?> Function(
Attachment, {
void Function(int, int) progressCallback,
}) saveFile = fileDownloader ?? _downloadAttachment;
final Future<String?> Function(
Attachment, {
void Function(int, int) progressCallback,
}) saveImage = imageDownloader ?? _downloadAttachment;
final downloader = isImage ? saveImage : saveFile;
final progressNotifier = ValueNotifier<_DownloadProgress?>(
_DownloadProgress.initial(),
);
downloader(
attachment,
progressCallback: (received, total) {
progressNotifier.value = _DownloadProgress(
total,
received,
);
},
).catchError((e, stk) {
progressNotifier.value = null;
});
// Closing attachment actions modal before opening
// attachment download dialog
Navigator.pop(context);
showDialog(
barrierDismissible: false,
context: context,
barrierColor: theme.colorTheme.overlay,
builder: (context) => _buildDownloadProgressDialog(
context,
progressNotifier,
),
);
},
),
if (StreamChat.of(context).currentUser?.id == message.user?.id)
_buildButton(
context,
context.translations.deleteLabel.capitalize(),
StreamSvgIcon.delete(
size: 24,
color: theme.colorTheme.accentError,
),
]
.map<Widget>((e) => Align(
alignment: Alignment.centerRight,
child: e,
))
.insertBetween(
Container(
height: 1,
color: theme.colorTheme.borders,
),
() {
final channel = StreamChannel.of(context).channel;
if (message.attachments.length > 1 ||
message.text?.isNotEmpty == true) {
final remainingAttachments = [...message.attachments]
..removeAt(currentIndex);
channel.updateMessage(message.copyWith(
attachments: remainingAttachments,
));
Navigator.of(context)
..pop()
..maybePop();
} else {
channel.deleteMessage(message);
Navigator.of(context)
..pop()
..maybePop();
}
},
color: theme.colorTheme.accentError,
),
]
.map<Widget>((e) => Align(
alignment: Alignment.centerRight,
child: e,
))
.insertBetween(
Container(
height: 1,
color: theme.colorTheme.borders,
),
),
),
),
),
)
),
],
);
}
@@ -4,6 +4,7 @@ import 'package:stream_chat_flutter/src/unread_indicator.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// Back button implementation
// ignore: prefer-match-file-name
class StreamBackButton extends StatelessWidget {
/// Constructor for creating back button
const StreamBackButton({
@@ -77,7 +77,8 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
UserAvatar(
user: members
.firstWhere(
(e) => e.user?.id != userAsMember.user?.id)
(e) => e.user?.id != userAsMember.user?.id,
)
.user!,
constraints: const BoxConstraints(
maxHeight: 64,
@@ -93,7 +94,8 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
Text(
members
.firstWhere(
(e) => e.user?.id != userAsMember.user?.id)
(e) => e.user?.id != userAsMember.user?.id,
)
.user
?.name ??
'',
@@ -185,7 +185,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
),
onPressed: onNewChatButtonTap,
),
)
),
],
title: Column(
children: [
@@ -565,7 +565,8 @@ class _ChannelListViewState extends State<ChannelListView> {
'owner',
].contains(channel.state!.members
.firstWhereOrNull(
(m) => m.userId == channel.client.state.currentUser?.id)
(m) => m.userId == channel.client.state.currentUser?.id,
)
?.role))
IconSlideAction(
color: backgroundColor,
@@ -72,85 +72,82 @@ class ChannelPreview extends StatelessWidget {
final channelPreviewTheme = ChannelPreviewTheme.of(context);
final streamChatState = StreamChat.of(context);
return BetterStreamBuilder<bool>(
stream: channel.isMutedStream,
initialData: channel.isMuted,
builder: (context, data) => AnimatedOpacity(
opacity: data ? 0.5 : 1,
duration: const Duration(milliseconds: 300),
child: ListTile(
visualDensity: VisualDensity.compact,
contentPadding: const EdgeInsets.symmetric(
horizontal: 8,
),
onTap: () => onTap?.call(channel),
onLongPress: () => onLongPress?.call(channel),
leading: leading ?? ChannelAvatar(onTap: onImageTap),
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Flexible(
child: title ??
ChannelName(
textStyle: channelPreviewTheme.titleStyle,
),
stream: channel.isMutedStream,
initialData: channel.isMuted,
builder: (context, data) => AnimatedOpacity(
opacity: data ? 0.5 : 1,
duration: const Duration(milliseconds: 300),
child: ListTile(
visualDensity: VisualDensity.compact,
contentPadding: const EdgeInsets.symmetric(
horizontal: 8,
),
onTap: () => onTap?.call(channel),
onLongPress: () => onLongPress?.call(channel),
leading: leading ?? ChannelAvatar(onTap: onImageTap),
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Flexible(
child: title ??
ChannelName(
textStyle: channelPreviewTheme.titleStyle,
),
BetterStreamBuilder<List<Member>>(
stream: channel.state?.membersStream,
initialData: channel.state?.members,
comparator: const ListEquality().equals,
builder: (context, members) {
if (members.isEmpty ||
members.any((Member e) =>
e.user!.id ==
channel.client.state.currentUser?.id) !=
true) {
return const SizedBox();
}
return UnreadIndicator(
cid: channel.cid,
);
},
),
],
),
subtitle: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Flexible(child: subtitle ?? _buildSubtitle(context)),
sendingIndicator ??
Builder(
builder: (context) {
final lastMessage =
channel.state?.messages.lastWhereOrNull(
(m) => !m.isDeleted && m.shadowed != true,
);
if (lastMessage?.user?.id ==
streamChatState.currentUser?.id) {
return Padding(
padding: const EdgeInsets.only(right: 4),
child: SendingIndicator(
message: lastMessage!,
size: channelPreviewTheme.indicatorIconSize,
isMessageRead: channel.state!.read
.where((element) =>
element.user.id !=
channel
.client.state.currentUser!.id)
.where((element) => element.lastRead
.isAfter(lastMessage.createdAt))
.isNotEmpty ==
true,
),
);
}
return const SizedBox();
},
),
trailing ?? _buildDate(context),
],
),
),
));
BetterStreamBuilder<List<Member>>(
stream: channel.state?.membersStream,
initialData: channel.state?.members,
comparator: const ListEquality().equals,
builder: (context, members) {
if (members.isEmpty ||
!members.any((Member e) =>
e.user!.id == channel.client.state.currentUser?.id)) {
return const SizedBox();
}
return UnreadIndicator(
cid: channel.cid,
);
},
),
],
),
subtitle: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Flexible(child: subtitle ?? _buildSubtitle(context)),
sendingIndicator ??
Builder(
builder: (context) {
final lastMessage =
channel.state?.messages.lastWhereOrNull(
(m) => !m.isDeleted && !m.shadowed,
);
if (lastMessage?.user?.id ==
streamChatState.currentUser?.id) {
return Padding(
padding: const EdgeInsets.only(right: 4),
child: SendingIndicator(
message: lastMessage!,
size: channelPreviewTheme.indicatorIconSize,
isMessageRead: channel.state!.read
.where((element) =>
element.user.id !=
channel.client.state.currentUser!.id)
.where((element) => element.lastRead
.isAfter(lastMessage.createdAt))
.isNotEmpty,
),
);
}
return const SizedBox();
},
),
trailing ?? _buildDate(context),
],
),
),
),
);
}
Widget _buildDate(BuildContext context) => BetterStreamBuilder<DateTime>(
@@ -246,10 +243,11 @@ class ChannelPreview extends StatelessWidget {
lastMessage.mentionedUsers,
lastMessage.attachments,
channelPreviewTheme.subtitleStyle?.copyWith(
color: channelPreviewTheme.subtitleStyle?.color,
fontStyle: (lastMessage.isSystem || lastMessage.isDeleted)
? FontStyle.italic
: FontStyle.normal),
color: channelPreviewTheme.subtitleStyle?.color,
fontStyle: (lastMessage.isSystem || lastMessage.isDeleted)
? FontStyle.italic
: FontStyle.normal,
),
channelPreviewTheme.subtitleStyle?.copyWith(
color: channelPreviewTheme.subtitleStyle?.color,
fontStyle: (lastMessage.isSystem || lastMessage.isDeleted)
@@ -21,25 +21,16 @@ class DateDivider extends StatelessWidget {
@override
Widget build(BuildContext context) {
final createdAt = Jiffy(dateTime);
final now = DateTime.now();
final now = Jiffy(DateTime.now());
String dayInfo;
if (Jiffy(createdAt).isSame(now, Units.DAY)) {
var dayInfo = createdAt.MMMd;
if (createdAt.isSame(now, Units.DAY)) {
dayInfo = context.translations.todayLabel;
} else if (Jiffy(createdAt)
.isSame(now.subtract(const Duration(days: 1)), Units.DAY)) {
} else if (createdAt.isSame(now.subtract(days: 1), Units.DAY)) {
dayInfo = context.translations.yesterdayLabel;
} else if (Jiffy(createdAt).isAfter(
now.subtract(const Duration(days: 7)),
Units.DAY,
)) {
} else if (createdAt.isAfter(now.subtract(days: 7), Units.DAY)) {
dayInfo = createdAt.EEEE;
} else if (Jiffy(createdAt).isAfter(
Jiffy(now).subtract(years: 1),
Units.DAY,
)) {
dayInfo = createdAt.MMMd;
} else {
} else if (createdAt.isAfter(now.subtract(years: 1), Units.DAY)) {
dayInfo = createdAt.MMMd;
}
@@ -127,7 +127,8 @@ extension FlipBorder on BorderRadius {
topLeft: topRight,
topRight: topLeft,
bottomLeft: bottomRight,
bottomRight: bottomLeft)
bottomRight: bottomLeft,
)
: this;
}
@@ -87,7 +87,7 @@ class _FullScreenMediaState extends State<FullScreenMedia>
await Future.wait(videoPackages.values.map(
(it) => it.initialize(),
));
setState(() {});
setState(() {}); // ignore: no-empty-block
}
@override
@@ -96,83 +96,83 @@ class _FullScreenMediaState extends State<FullScreenMedia>
body: Stack(
children: [
AnimatedBuilder(
animation: _controller,
builder: (context, snapshot) => PageView.builder(
controller: _pageController,
onPageChanged: (val) {
animation: _controller,
builder: (context, snapshot) => PageView.builder(
controller: _pageController,
onPageChanged: (val) {
setState(() {
_currentPage = val;
});
},
itemBuilder: (context, index) {
final attachment = widget.mediaAttachments[index];
if (attachment.type == 'image' ||
attachment.type == 'giphy') {
final imageUrl = attachment.imageUrl ??
attachment.assetUrl ??
attachment.thumbUrl;
return PhotoView(
loadingBuilder: (context, image) =>
const Offstage(),imageProvider: (imageUrl == null &&
attachment.localUri != null &&
attachment.file?.bytes != null)
? Image.memory(attachment.file!.bytes!).image
: CachedNetworkImageProvider(imageUrl!),
maxScale: PhotoViewComputedScale.covered,
minScale: PhotoViewComputedScale.contained,
heroAttributes: PhotoViewHeroAttributes(
tag: widget.mediaAttachments,
),
backgroundDecoration: BoxDecoration(
color: ColorTween(
begin: ChannelHeaderTheme.of(context).color,
end: Colors.black,
).lerp(_controller.value),
),
onTapUp: (a, b, c) {
setState(() {
_currentPage = val;
_optionsShown = !_optionsShown;
});
},
itemBuilder: (context, index) {
final attachment = widget.mediaAttachments[index];
if (attachment.type == 'image' ||
attachment.type == 'giphy') {
final imageUrl = attachment.imageUrl ??
attachment.assetUrl ??
attachment.thumbUrl;
return PhotoView(
loadingBuilder: (context, image) =>
const Offstage(),
imageProvider: (imageUrl == null &&
attachment.localUri != null &&
attachment.file?.bytes != null)
? Image.memory(attachment.file!.bytes!).image
: CachedNetworkImageProvider(imageUrl!),
maxScale: PhotoViewComputedScale.covered,
minScale: PhotoViewComputedScale.contained,
heroAttributes: PhotoViewHeroAttributes(
tag: widget.mediaAttachments,
),
backgroundDecoration: BoxDecoration(
color: ColorTween(
begin: ChannelHeaderTheme.of(context).color,
end: Colors.black,
).lerp(_controller.value),
),
onTapUp: (a, b, c) {
setState(() {
_optionsShown = !_optionsShown;
});
if (_controller.isCompleted) {
_controller.reverse();
} else {
_controller.forward();
}
},
);
} else if (attachment.type == 'video') {
final controller = videoPackages[attachment.id]!;
if (!controller.initialized) {
return const Center(
child: CircularProgressIndicator(),
);
}
return InkWell(
onTap: () {
setState(() {
_optionsShown = !_optionsShown;
});
if (_controller.isCompleted) {
_controller.reverse();
} else {
_controller.forward();
}
},
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 50,
),
child: Chewie(
controller: controller.chewieController!,
),
),
);
if (_controller.isCompleted) {
_controller.reverse();
} else {
_controller.forward();
}
return Container();
},
itemCount: widget.mediaAttachments.length,
)),
);
} else if (attachment.type == 'video') {
final controller = videoPackages[attachment.id]!;
if (!controller.initialized) {
return const Center(
child: CircularProgressIndicator(),
);
}
return InkWell(
onTap: () {
setState(() {
_optionsShown = !_optionsShown;
});
if (_controller.isCompleted) {
_controller.reverse();
} else {
_controller.forward();
}
},
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 50,
),
child: Chewie(
controller: controller.chewieController!,
),
),
);
}
return Container();
},
itemCount: widget.mediaAttachments.length,
),
),
AnimatedOpacity(
opacity: _optionsShown ? 1.0 : 0.0,
duration: const Duration(milliseconds: 300),
@@ -1,4 +1,3 @@
import 'dart:async';
import 'dart:io';
import 'package:cached_network_image/cached_network_image.dart';
@@ -67,19 +66,6 @@ class GalleryFooter extends StatefulWidget implements PreferredSizeWidget {
}
class _GalleryFooterState extends State<GalleryFooter> {
final TextEditingController _messageController = TextEditingController();
final FocusNode _messageFocusNode = FocusNode();
final List<Channel> _selectedChannels = [];
@override
void initState() {
super.initState();
_messageFocusNode.addListener(() {
setState(() {});
});
}
@override
Widget build(BuildContext context) {
const showShareButton = !kIsWeb;
@@ -143,8 +129,9 @@ class _GalleryFooterState extends State<GalleryFooter> {
children: <Widget>[
Text(
context.translations.galleryPaginationText(
currentPage: widget.currentPage,
totalPages: widget.totalPages),
currentPage: widget.currentPage,
totalPages: widget.totalPages,
),
style: galleryFooterThemeData.titleTextStyle,
),
],
@@ -264,29 +251,26 @@ class _GalleryFooterState extends State<GalleryFooter> {
children: [
media,
if (widget.message.user != null)
Padding(
padding: const EdgeInsets.all(8),
child: Container(
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.white.withOpacity(0.6),
boxShadow: [
BoxShadow(
blurRadius: 8,
color: chatThemeData
.colorTheme.textHighEmphasis
.withOpacity(0.3),
),
],
),
padding: const EdgeInsets.all(2),
child: UserAvatar(
user: widget.message.user!,
constraints:
BoxConstraints.tight(const Size(24, 24)),
showOnlineStatus: false,
),
Container(
padding: const EdgeInsets.all(10),
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.white.withOpacity(0.6),
boxShadow: [
BoxShadow(
blurRadius: 8,
color: chatThemeData
.colorTheme.textHighEmphasis
.withOpacity(0.3),
),
],
),
child: UserAvatar(
user: widget.message.user!,
constraints:
BoxConstraints.tight(const Size(24, 24)),
showOnlineStatus: false,
),
),
],
@@ -301,25 +285,4 @@ class _GalleryFooterState extends State<GalleryFooter> {
},
);
}
/// Sends the current message
Future sendMessage() async {
final text = _messageController.text.trim();
final attachments = widget.message.attachments;
_messageController.clear();
for (final channel in _selectedChannels) {
final message = Message(
text: text,
attachments: [attachments[widget.currentPage]],
);
await channel.sendMessage(message);
}
_selectedChannels.clear();
Navigator.pop(context);
}
}
@@ -106,7 +106,8 @@ class DemoPainter extends CustomPainter {
final p4 = pointsList.indexOf(off4);
squares.add(
Offset4(p1, p2, p3, p4, i, j, rowCount, columnCount, gradient));
Offset4(p1, p2, p3, p4, i, j, rowCount, columnCount, gradient),
);
}
}
@@ -123,17 +124,18 @@ class DemoPainter extends CustomPainter {
final fontSize = username.length == 2 ? textSize : textSize * 1.5;
TextPainter(
text: TextSpan(
text: username,
style: TextStyle(
fontFamily: fontFamily,
fontSize: fontSize,
fontWeight: FontWeight.w500,
color: Colors.white.withOpacity(0.7),
),
text: TextSpan(
text: username,
style: TextStyle(
fontFamily: fontFamily,
fontSize: fontSize,
fontWeight: FontWeight.w500,
color: Colors.white.withOpacity(0.7),
),
textAlign: TextAlign.center,
textDirection: TextDirection.ltr)
),
textAlign: TextAlign.center,
textDirection: TextDirection.ltr,
)
..layout(maxWidth: size.width)
..paint(
canvas,
@@ -168,8 +170,8 @@ class DemoPainter extends CustomPainter {
final sign1 = rand.nextInt(2) == 1 ? 1 : -1;
final sign2 = rand.nextInt(2) == 1 ? 1 : -1;
final dx = 0.6 * sign1 * rand.nextInt(size.width ~/ columnCount);
final dy = 0.6 * sign2 * rand.nextInt(size.height ~/ rowCount);
final dx = sign1 * 0.6 * rand.nextInt(size.width ~/ columnCount);
final dy = sign2 * 0.6 * rand.nextInt(size.height ~/ rowCount);
transformedList.add(Offset(orgDx + dx, orgDy + dy));
}
@@ -223,8 +225,12 @@ class Offset4 {
/// Draw the polygon on canvas
void draw(Canvas canvas, List<Offset> points) {
final paint = Paint()
..color = Color.fromARGB(255, Random().nextInt(255),
Random().nextInt(255), Random().nextInt(255))
..color = Color.fromARGB(
255,
Random().nextInt(255),
Random().nextInt(255),
Random().nextInt(255),
)
..shader = ui.Gradient.linear(
points[p1],
points[p3],
@@ -300,8 +300,10 @@ abstract class Translations {
String get youText;
/// Gallery footer pagination text
String galleryPaginationText(
{required int currentPage, required int totalPages});
String galleryPaginationText({
required int currentPage,
required int totalPages,
});
/// The text shown for "File"
String get fileText;
@@ -665,8 +667,10 @@ class DefaultTranslations implements Translations {
String get youText => 'You';
@override
String galleryPaginationText(
{required int currentPage, required int totalPages}) =>
String galleryPaginationText({
required int currentPage,
required int totalPages,
}) =>
'${currentPage + 1} of $totalPages';
@override
@@ -129,7 +129,7 @@ class _MediaListViewState extends State<MediaListView> {
),
),
),
]
],
],
),
),
@@ -144,9 +144,9 @@ class _MediaListViewState extends State<MediaListView> {
_getMedia();
}
void _getMedia() async {
Future<void> _getMedia() async {
final assetList = await PhotoManager.getAssetPathList().then((value) {
if (value.isNotEmpty == true) {
if (value.isNotEmpty) {
return value.singleWhere((element) => element.isAll);
}
});
@@ -178,7 +178,9 @@ class MediaThumbnailProvider extends ImageProvider<MediaThumbnailProvider> {
@override
ImageStreamCompleter load(
MediaThumbnailProvider key, DecoderCallback decode) =>
MediaThumbnailProvider key,
DecoderCallback decode,
) =>
MultiFrameImageStreamCompleter(
codec: _loadAsync(key, decode),
scale: 1,
@@ -188,7 +190,9 @@ class MediaThumbnailProvider extends ImageProvider<MediaThumbnailProvider> {
);
Future<ui.Codec> _loadAsync(
MediaThumbnailProvider key, DecoderCallback decode) async {
MediaThumbnailProvider key,
DecoderCallback decode,
) async {
assert(key == this, 'Checks MediaThumbnailProvider');
final bytes = await media.thumbData;
@@ -104,7 +104,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
final size = mediaQueryData.size;
final user = StreamChat.of(context).currentUser;
final roughMaxSize = 2 * size.width / 3;
final roughMaxSize = size.width * 2 / 3;
var messageTextLength = widget.message.text!.length;
if (widget.message.quotedMessage != null) {
var quotedMessageLength =
@@ -119,7 +119,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
final roughSentenceSize = messageTextLength *
(widget.messageTheme.messageTextStyle?.fontSize ?? 1) *
1.2;
final divFactor = widget.message.attachments.isNotEmpty == true
final divFactor = widget.message.attachments.isNotEmpty
? 1
: (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize));
@@ -142,14 +142,15 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
(widget.message.status == MessageSendingStatus.sent))
Align(
alignment: Alignment(
user?.id == widget.message.user?.id
? (divFactor >= 1.0
? -0.2 - shiftFactor
: (1.2 - divFactor))
: (divFactor >= 1.0
? 0.2 + shiftFactor
: -(1.2 - divFactor)),
0),
user?.id == widget.message.user?.id
? (divFactor >= 1.0
? -0.2 - shiftFactor
: (1.2 - divFactor))
: (divFactor >= 1.0
? shiftFactor + 0.2
: -(1.2 - divFactor)),
0,
),
child: ReactionPicker(
message: widget.message,
),
@@ -194,7 +195,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
.map((action) => _buildCustomAction(
context,
action,
))
)),
].insertBetween(
Container(
height: 1,
@@ -373,11 +373,13 @@ class MessageInputState extends State<MessageInput> {
_parseExistingMessage(widget.editMessage ?? widget.initialMessage!);
}
textEditingController.addListener(_onChangedDebounced);
_focusNode.addListener(() {
if (_focusNode.hasFocus) {
_openFilePickerSection = false;
}
});
_focusNode.addListener(_focusNodeListener);
}
void _focusNodeListener() {
if (_focusNode.hasFocus) {
_openFilePickerSection = false;
}
}
int _timeOut = 0;
@@ -533,7 +535,7 @@ class MessageInputState extends State<MessageInput> {
? null
: Border.all(
color: _streamChatTheme.colorTheme.textHighEmphasis
.withOpacity(.5),
.withOpacity(0.5),
width: 2,
),
borderRadius: BorderRadius.circular(3),
@@ -703,7 +705,7 @@ class MessageInputState extends State<MessageInput> {
decoration: _getInputDecoration(context),
textCapitalization: TextCapitalization.sentences,
),
)
),
],
),
),
@@ -750,31 +752,28 @@ class MessageInputState extends State<MessageInput> {
? Row(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
Container(
padding: const EdgeInsets.all(8),
child: Container(
constraints: BoxConstraints.tight(const Size(64, 24)),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: _streamChatTheme.colorTheme.accentPrimary,
),
alignment: Alignment.center,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
StreamSvgIcon.lightning(
constraints: BoxConstraints.tight(const Size(64, 24)),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: _streamChatTheme.colorTheme.accentPrimary,
),
alignment: Alignment.center,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
StreamSvgIcon.lightning(
color: Colors.white,
size: 16,
),
Text(
_chosenCommand?.name.toUpperCase() ?? '',
style: _streamChatTheme.textTheme.footnoteBold.copyWith(
color: Colors.white,
size: 16,
),
Text(
_chosenCommand?.name.toUpperCase() ?? '',
style:
_streamChatTheme.textTheme.footnoteBold.copyWith(
color: Colors.white,
),
),
],
),
),
],
),
),
],
@@ -1054,15 +1053,13 @@ class MessageInputState extends State<MessageInput> {
),
),
child: Center(
child: Padding(
padding: const EdgeInsets.all(8),
child: Container(
width: 40,
height: 4,
decoration: BoxDecoration(
color: _streamChatTheme.colorTheme.inputBg,
borderRadius: BorderRadius.circular(4),
),
child: Container(
width: 40,
height: 4,
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: _streamChatTheme.colorTheme.inputBg,
borderRadius: BorderRadius.circular(4),
),
),
),
@@ -1193,12 +1190,13 @@ class MessageInputState extends State<MessageInput> {
textEditingController.value = TextEditingValue(
text: rejoin +
textEditingController.text
.substring(textEditingController.selection.start),
selection: TextSelection.collapsed(
offset: rejoin.length,
),
);
_onChangedDebounced.cancel();
.substring(textEditingController.selection.start,
),
selection: TextSelection.collapsed(
offset: rejoin.length,
),
);
_onChangedDebounced.cancel();
setState(() => _showMentionsOverlay = false);
},
);
@@ -1251,8 +1249,7 @@ class MessageInputState extends State<MessageInput> {
Widget _buildReplyToMessage() {
if (!_hasQuotedMessage) return const Offstage();
final containsUrl = widget.quotedMessage!.attachments
.any((element) => element.titleLink != null) ==
true;
.any((element) => element.titleLink != null);
return QuotedMessageWidget(
reverse: true,
showBorder: !containsUrl,
@@ -1357,7 +1354,7 @@ class MessageInputState extends State<MessageInput> {
setState(() => _attachments.remove(attachment.id));
},
fillColor:
_streamChatTheme.colorTheme.textHighEmphasis.withOpacity(.5),
_streamChatTheme.colorTheme.textHighEmphasis.withOpacity(0.5),
child: Center(
child: StreamSvgIcon.close(
size: 24,
@@ -1836,10 +1833,11 @@ class MessageInputState extends State<MessageInput> {
backgroundColor: _streamChatTheme.colorTheme.barsBg,
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16),
)),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16),
),
),
builder: (context) => Column(
mainAxisSize: MainAxisSize.min,
children: [
@@ -1872,7 +1870,7 @@ class MessageInputState extends State<MessageInput> {
),
Container(
color:
_streamChatTheme.colorTheme.textHighEmphasis.withOpacity(.08),
_streamChatTheme.colorTheme.textHighEmphasis.withOpacity(0.08),
height: 1,
),
Row(
@@ -1905,6 +1903,7 @@ class MessageInputState extends State<MessageInput> {
@override
void dispose() {
textEditingController.dispose();
_focusNode.removeListener(_focusNodeListener);
_stopSlowMode();
_onChangedDebounced.cancel();
super.dispose();
@@ -2015,7 +2014,8 @@ class _PickerWidgetState extends State<_PickerWidget> {
Text(
context.translations.enablePhotoAndVideoAccessMessage,
style: widget.streamChatTheme.textTheme.body.copyWith(
color: widget.streamChatTheme.colorTheme.textLowEmphasis),
color: widget.streamChatTheme.colorTheme.textLowEmphasis,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 6),
@@ -60,6 +60,7 @@ typedef OnMessageTap = void Function(Message);
typedef ReplyTapCallback = void Function(Message);
/// Class for message details
// ignore: prefer-match-file-name
class MessageDetails {
/// Constructor for creating [MessageDetails]
MessageDetails(
@@ -355,8 +356,9 @@ class _MessageListViewState extends State<MessageListView> {
child: Text(
context.translations.emptyChatMessagesText,
style: _streamTheme.textTheme.footnote.copyWith(
color: _streamTheme.colorTheme.textHighEmphasis
.withOpacity(.5)),
color: _streamTheme.colorTheme.textHighEmphasis
.withOpacity(0.5),
),
),
),
messageListBuilder: widget.messageListBuilder ??
@@ -368,8 +370,9 @@ class _MessageListViewState extends State<MessageListView> {
child: Text(
context.translations.genericErrorText,
style: _streamTheme.textTheme.footnote.copyWith(
color: _streamTheme.colorTheme.textHighEmphasis
.withOpacity(.5)),
color: _streamTheme.colorTheme.textHighEmphasis
.withOpacity(0.5),
),
),
),
);
@@ -380,7 +383,7 @@ class _MessageListViewState extends State<MessageListView> {
if (_messageListLength != null) {
if (_bottomPaginationActive || (_inBetweenList && _upToDate)) {
if (_itemPositionListener.itemPositions.value.isNotEmpty == true) {
if (_itemPositionListener.itemPositions.value.isNotEmpty) {
final first = _itemPositionListener.itemPositions.value.first;
final diff = newMessagesListLength - _messageListLength!;
if (diff > 0) {
@@ -973,7 +976,7 @@ class _MessageListViewState extends State<MessageListView> {
final allRead = readList.length >= (channel.memberCount ?? 0) - 1;
final hasFileAttachment =
message.attachments.any((it) => it.type == 'file') == true;
message.attachments.any((it) => it.type == 'file');
final isThreadMessage =
message.parentId != null && message.showInChannel == true;
@@ -1005,7 +1008,7 @@ class _MessageListViewState extends State<MessageListView> {
final isOnlyEmoji = message.text?.isOnlyEmoji ?? false;
final hasUrlAttachment =
message.attachments.any((it) => it.titleLink != null) == true;
message.attachments.any((it) => it.titleLink != null);
final borderSide =
isOnlyEmoji || hasUrlAttachment || (isMyMessage && !hasFileAttachment)
@@ -1250,10 +1253,11 @@ class _MessageListViewState extends State<MessageListView> {
if (widget.onThreadTap != null) {
_onThreadTap = (Message message) {
widget.onThreadTap!(
message,
widget.threadBuilder != null
? widget.threadBuilder!(context, message)
: null);
message,
widget.threadBuilder != null
? widget.threadBuilder!(context, message)
: null,
);
};
} else if (widget.threadBuilder != null) {
_onThreadTap = (Message message) {
@@ -1262,7 +1266,8 @@ class _MessageListViewState extends State<MessageListView> {
MaterialPageRoute(
builder: (_) => BetterStreamBuilder<Message>(
stream: streamChannel!.channel.state!.messagesStream.map(
(messages) => messages.firstWhere((m) => m.id == message.id)),
(messages) => messages.firstWhere((m) => m.id == message.id),
),
initialData: message,
builder: (_, data) => StreamChannel(
channel: streamChannel!.channel,
@@ -1309,7 +1314,7 @@ class _LoadingIndicator extends StatelessWidget {
stream: stream,
initialData: false,
errorBuilder: (context, error) => Container(
color: streamTheme.colorTheme.accentError.withOpacity(.2),
color: streamTheme.colorTheme.accentError.withOpacity(0.2),
child: Center(
child: Text(context.translations.loadingMessagesError),
),
@@ -46,11 +46,11 @@ class MessageReactionsModal extends StatelessWidget {
final size = MediaQuery.of(context).size;
final user = StreamChat.of(context).currentUser;
final roughMaxSize = 2 * size.width / 3;
final roughMaxSize = size.width * 2 / 3;
var messageTextLength = message.text!.length;
if (message.quotedMessage != null) {
var quotedMessageLength = message.quotedMessage!.text!.length + 40;
if (message.quotedMessage!.attachments.isNotEmpty == true) {
if (message.quotedMessage!.attachments.isNotEmpty) {
quotedMessageLength += 40;
}
if (quotedMessageLength > messageTextLength) {
@@ -60,7 +60,7 @@ class MessageReactionsModal extends StatelessWidget {
final roughSentenceSize = messageTextLength *
(messageTheme.messageTextStyle?.fontSize ?? 1) *
1.2;
final divFactor = message.attachments.isNotEmpty == true
final divFactor = message.attachments.isNotEmpty
? 1
: (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize));
@@ -80,14 +80,15 @@ class MessageReactionsModal extends StatelessWidget {
(message.status == MessageSendingStatus.sent))
Align(
alignment: Alignment(
user!.id == message.user!.id
? (divFactor >= 1.0
? -0.2 - shiftFactor
: (1.2 - divFactor))
: (divFactor >= 1.0
? 0.2 + shiftFactor
: -(1.2 - divFactor)),
0),
user!.id == message.user!.id
? (divFactor >= 1.0
? -0.2 - shiftFactor
: (1.2 - divFactor))
: (divFactor >= 1.0
? shiftFactor + 0.2
: -(1.2 - divFactor)),
0,
),
child: ReactionPicker(
message: message,
),
@@ -102,7 +103,7 @@ class MessageReactionsModal extends StatelessWidget {
context,
user,
),
]
],
],
),
),
@@ -146,11 +146,12 @@ class MessageSearchItem extends StatelessWidget {
}
TextSpan _getDisplayText(
String text,
List<User> mentions,
List<Attachment> attachments,
TextStyle? normalTextStyle,
TextStyle? mentionsTextStyle) {
String text,
List<User> mentions,
List<Attachment> attachments,
TextStyle? normalTextStyle,
TextStyle? mentionsTextStyle,
) {
final textList = text.split(' ');
final resList = <TextSpan>[];
for (final e in textList) {
@@ -217,7 +217,9 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
);
Widget _listItemBuilder(
BuildContext context, GetMessageResponse getMessageResponse) {
BuildContext context,
GetMessageResponse getMessageResponse,
) {
if (widget.itemBuilder != null) {
return widget.itemBuilder!(context, getMessageResponse);
}
@@ -231,33 +233,34 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
final messageSearchBloc = MessageSearchBloc.of(context);
return StreamBuilder<bool>(
stream: messageSearchBloc.queryMessagesLoading,
initialData: false,
builder: (context, snapshot) {
if (snapshot.hasError) {
return Container(
color: StreamChatTheme.of(context)
.colorTheme
.accentError
.withOpacity(.2),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 16),
child: Center(
child: Text(context.translations.loadingMessagesError),
),
),
);
}
stream: messageSearchBloc.queryMessagesLoading,
initialData: false,
builder: (context, snapshot) {
if (snapshot.hasError) {
return Container(
height: 100,
padding: const EdgeInsets.all(32),
child: Center(
child: snapshot.data!
? const CircularProgressIndicator()
: Container(),
color: StreamChatTheme.of(context)
.colorTheme
.accentError
.withOpacity(0.2),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 16),
child: Center(
child: Text(context.translations.loadingMessagesError),
),
),
);
});
}
return Container(
height: 100,
padding: const EdgeInsets.all(32),
child: Center(
child: snapshot.data!
? const CircularProgressIndicator()
: Container(),
),
);
},
);
}
Widget _buildListView(List<GetMessageResponse> data) {
@@ -88,7 +88,9 @@ class MessageText extends StatelessWidget {
for (final user in message.mentionedUsers.toSet()) {
final userName = user.name;
messageTextToRender = messageTextToRender.replaceAll(
'@$userName', '[@$userName](@${userName.replaceAll(' ', '')})');
'@$userName',
'[@$userName](@${userName.replaceAll(' ', '')})',
);
}
return messageTextToRender;
}
@@ -575,8 +575,7 @@ class _MessageWidgetState extends State<MessageWidget>
bool get isFailedState => isSendFailed || isUpdateFailed || isDeleteFailed;
bool get isGiphy =>
widget.message.attachments.any((element) => element.type == 'giphy') ==
true;
widget.message.attachments.any((element) => element.type == 'giphy');
bool get isOnlyEmoji => widget.message.text?.isOnlyEmoji == true;
@@ -596,7 +595,7 @@ class _MessageWidgetState extends State<MessageWidget>
isDeleted;
@override
bool get wantKeepAlive => widget.message.attachments.isNotEmpty == true;
bool get wantKeepAlive => widget.message.attachments.isNotEmpty;
late StreamChatThemeData _streamChatTheme;
late StreamChatState _streamChat;
@@ -674,7 +673,10 @@ class _MessageWidgetState extends State<MessageWidget>
child: PortalEntry(
portal: Container(
transform: Matrix4.translationValues(
widget.reverse ? 12 : -12, 0, 0),
widget.reverse ? 12 : -12,
0,
0,
),
constraints: const BoxConstraints(
maxWidth: 22 * 6.0,
),
@@ -704,13 +706,15 @@ class _MessageWidgetState extends State<MessageWidget>
? Container(
// ignore: lines_longer_than_80_chars
margin: EdgeInsets.symmetric(
horizontal:
// ignore: lines_longer_than_80_chars
widget.showUserAvatar ==
// ignore: lines_longer_than_80_chars
DisplayWidget.gone
? 0
: 4.0),
horizontal:
// ignore: lines_longer_than_80_chars
widget.showUserAvatar ==
// ignore: lines_longer_than_80_chars
DisplayWidget
.gone
? 0
: 4.0,
),
child: DeletedMessage(
borderRadiusGeometry: widget
.borderRadiusGeometry,
@@ -794,7 +798,7 @@ class _MessageWidgetState extends State<MessageWidget>
widget.message.user != null) ...[
_buildUserAvatar(),
const SizedBox(width: 4),
]
],
],
),
if (showBottomRow)
@@ -856,7 +860,11 @@ class _MessageWidgetState extends State<MessageWidget>
: chatThemeData.ownMessageTheme,
reverse: widget.reverse,
padding: EdgeInsets.only(
right: 8, left: 8, top: 8, bottom: hasNonUrlAttachments ? 8 : 0),
right: 8,
left: 8,
top: 8,
bottom: hasNonUrlAttachments ? 8 : 0,
),
);
}
@@ -1053,64 +1061,64 @@ class _MessageWidgetState extends State<MessageWidget>
final channel = StreamChannel.of(context).channel;
showDialog(
useRootNavigator: false,
context: context,
barrierColor: _streamChatTheme.colorTheme.overlay,
builder: (context) => StreamChannel(
channel: channel,
child: MessageActionsModal(
messageWidget: widget.copyWith(
key: const Key('MessageWidget'),
message: widget.message.copyWith(
text: (widget.message.text?.length ?? 0) > 200
? '${widget.message.text!.substring(0, 200)}...'
: widget.message.text,
),
showReactions: false,
showUsername: false,
showTimestamp: false,
translateUserAvatar: false,
showSendingIndicator: false,
padding: const EdgeInsets.all(0),
showReactionPickerIndicator: widget.showReactions &&
(widget.message.status == MessageSendingStatus.sent),
showPinHighlight: false,
showUserAvatar: widget.message.user!.id ==
channel.client.state.currentUser!.id
? DisplayWidget.gone
: DisplayWidget.show,
),
onCopyTap: (message) =>
Clipboard.setData(ClipboardData(text: message.text)),
messageTheme: widget.messageTheme,
reverse: widget.reverse,
showDeleteMessage: widget.showDeleteMessage || isDeleteFailed,
message: widget.message,
editMessageInputBuilder: widget.editMessageInputBuilder,
onReplyTap: widget.onReplyTap,
onThreadReplyTap: widget.onThreadTap,
showResendMessage: widget.showResendMessage &&
(isSendFailed || isUpdateFailed),
showCopyMessage: widget.showCopyMessage &&
!isFailedState &&
widget.message.text?.trim().isNotEmpty == true,
showEditMessage: widget.showEditMessage &&
!isDeleteFailed &&
widget.message.attachments
.any((element) => element.type == 'giphy') !=
true,
showReactions: widget.showReactions,
showReplyMessage: widget.showReplyMessage &&
!isFailedState &&
widget.onReplyTap != null,
showThreadReplyMessage: widget.showThreadReplyMessage &&
!isFailedState &&
widget.onThreadTap != null,
showFlagButton: widget.showFlagButton,
showPinButton: widget.showPinButton,
customActions: widget.customActions,
),
));
useRootNavigator: false,
context: context,
barrierColor: _streamChatTheme.colorTheme.overlay,
builder: (context) => StreamChannel(
channel: channel,
child: MessageActionsModal(
messageWidget: widget.copyWith(
key: const Key('MessageWidget'),
message: widget.message.copyWith(
text: (widget.message.text?.length ?? 0) > 200
? '${widget.message.text!.substring(0, 200)}...'
: widget.message.text,
),
showReactions: false,
showUsername: false,
showTimestamp: false,
translateUserAvatar: false,
showSendingIndicator: false,
padding: const EdgeInsets.all(0),
showReactionPickerIndicator: widget.showReactions &&
(widget.message.status == MessageSendingStatus.sent),
showPinHighlight: false,
showUserAvatar:
widget.message.user!.id == channel.client.state.currentUser!.id
? DisplayWidget.gone
: DisplayWidget.show,
),
onCopyTap: (message) =>
Clipboard.setData(ClipboardData(text: message.text)),
messageTheme: widget.messageTheme,
reverse: widget.reverse,
showDeleteMessage: widget.showDeleteMessage || isDeleteFailed,
message: widget.message,
editMessageInputBuilder: widget.editMessageInputBuilder,
onReplyTap: widget.onReplyTap,
onThreadReplyTap: widget.onThreadTap,
showResendMessage:
widget.showResendMessage && (isSendFailed || isUpdateFailed),
showCopyMessage: widget.showCopyMessage &&
!isFailedState &&
widget.message.text?.trim().isNotEmpty == true,
showEditMessage: widget.showEditMessage &&
!isDeleteFailed &&
!widget.message.attachments
.any((element) => element.type == 'giphy'),
showReactions: widget.showReactions,
showReplyMessage: widget.showReplyMessage &&
!isFailedState &&
widget.onReplyTap != null,
showThreadReplyMessage: widget.showThreadReplyMessage &&
!isFailedState &&
widget.onThreadTap != null,
showFlagButton: widget.showFlagButton,
showPinButton: widget.showPinButton,
customActions: widget.customActions,
),
),
);
}
void _showMessageReactionsModalBottomSheet(BuildContext context) {
@@ -1290,8 +1298,9 @@ class _MessageWidgetState extends State<MessageWidget>
? widget.messageTheme.copyWith(
messageTextStyle:
widget.messageTheme.messageTextStyle!.copyWith(
fontSize: 42,
))
fontSize: 42,
),
)
: widget.messageTheme,
),
),
@@ -1325,7 +1334,7 @@ class _MessageWidgetState extends State<MessageWidget>
fontSize: 13,
fontWeight: FontWeight.w400,
),
)
),
],
),
);
@@ -1431,8 +1440,12 @@ class _ThreadReplyPainter extends CustomPainter {
final path = Path()
..moveTo(reverse ? size.width : 0, 0)
..quadraticBezierTo(reverse ? size.width : 0, size.height * 0.38,
reverse ? size.width : 0, size.height * 0.50)
..quadraticBezierTo(
reverse ? size.width : 0,
size.height * 0.38,
reverse ? size.width : 0,
size.height * 0.5,
)
..quadraticBezierTo(
reverse ? size.width : 0,
size.height,
@@ -35,6 +35,7 @@ class _VideoAttachmentThumbnailState extends State<_VideoAttachmentThumbnail> {
super.initState();
_controller = VideoPlayerController.network(widget.attachment.assetUrl!)
..initialize().then((_) {
// ignore: no-empty-block
setState(() {}); //when your thumbnail will show.
});
}
@@ -95,10 +96,10 @@ class QuotedMessageWidget extends StatelessWidget {
/// Callback for tap on widget
final GestureTapCallback? onTap;
bool get _hasAttachments => message.attachments.isNotEmpty == true;
bool get _hasAttachments => message.attachments.isNotEmpty;
bool get _containsLinkAttachment =>
message.attachments.any((element) => element.titleLink != null) == true;
message.attachments.any((element) => element.titleLink != null);
bool get _containsText => message.text?.isNotEmpty == true;
@@ -140,12 +141,14 @@ class QuotedMessageWidget extends StatelessWidget {
messageTheme: isOnlyEmoji && _containsText
? messageTheme.copyWith(
messageTextStyle: messageTheme.messageTextStyle?.copyWith(
fontSize: 32,
))
fontSize: 32,
),
)
: messageTheme.copyWith(
messageTextStyle: messageTheme.messageTextStyle?.copyWith(
fontSize: 12,
)),
fontSize: 12,
),
),
),
),
].insertBetween(const SizedBox(width: 8));
@@ -275,7 +278,8 @@ class QuotedMessageWidget extends StatelessWidget {
height: 32,
width: 32,
child: getFileTypeImage(
attachment.extraData['mime_type'] as String?),
attachment.extraData['mime_type'] as String?,
),
),
};
@@ -142,7 +142,7 @@ class ReactionBubble extends StatelessWidget {
size: 16,
color: (!highlightOwnReactions || reaction.user?.id == userId)
? chatThemeData.colorTheme.accentPrimary
: chatThemeData.colorTheme.textHighEmphasis.withOpacity(.5),
: chatThemeData.colorTheme.textHighEmphasis.withOpacity(0.5),
),
);
}
@@ -62,10 +62,11 @@ class _ReactionPickerState extends State<ReactionPicker>
mainAxisSize: MainAxisSize.min,
children: reactionIcons
.map<Widget>((reactionIcon) {
final ownReactionIndex = widget.message.ownReactions
?.indexWhere(
(reaction) => reaction.type == reactionIcon.type) ??
-1;
final ownReactionIndex =
widget.message.ownReactions?.indexWhere(
(reaction) => reaction.type == reactionIcon.type,
) ??
-1;
final index = reactionIcons.indexOf(reactionIcon);
final child = reactionIcon.builder(
@@ -75,7 +75,8 @@ class StreamChat extends StatefulWidget {
if (streamChatState == null) {
throw Exception(
'You must have a StreamChat widget at the top of your widget tree');
'You must have a StreamChat widget at the top of your widget tree',
);
}
return streamChatState;
@@ -145,7 +145,7 @@ class StreamChatThemeData {
) {
final accentColor = colorTheme.accentPrimary;
final iconTheme =
IconThemeData(color: colorTheme.textHighEmphasis.withOpacity(.5));
IconThemeData(color: colorTheme.textHighEmphasis.withOpacity(0.5));
final channelHeaderTheme = ChannelHeaderThemeData(
avatarTheme: AvatarThemeData(
borderRadius: BorderRadius.circular(20),
@@ -174,7 +174,7 @@ class StreamChatThemeData {
color: const Color(0xff7A7A7A),
),
lastMessageAtStyle: textTheme.footnote.copyWith(
color: colorTheme.textHighEmphasis.withOpacity(.5),
color: colorTheme.textHighEmphasis.withOpacity(0.5),
),
indicatorIconSize: 16,
);
@@ -278,7 +278,7 @@ class StreamChatThemeData {
return StreamSvgIcon.loveReaction(
color: highlighted
? theme.colorTheme.accentPrimary
: theme.primaryIconTheme.color!.withOpacity(.5),
: theme.primaryIconTheme.color!.withOpacity(0.5),
size: size,
);
},
@@ -290,7 +290,7 @@ class StreamChatThemeData {
return StreamSvgIcon.thumbsUpReaction(
color: highlighted
? theme.colorTheme.accentPrimary
: theme.primaryIconTheme.color!.withOpacity(.5),
: theme.primaryIconTheme.color!.withOpacity(0.5),
size: size,
);
},
@@ -302,7 +302,7 @@ class StreamChatThemeData {
return StreamSvgIcon.thumbsDownReaction(
color: highlighted
? theme.colorTheme.accentPrimary
: theme.primaryIconTheme.color!.withOpacity(.5),
: theme.primaryIconTheme.color!.withOpacity(0.5),
size: size,
);
},
@@ -314,7 +314,7 @@ class StreamChatThemeData {
return StreamSvgIcon.lolReaction(
color: highlighted
? theme.colorTheme.accentPrimary
: theme.primaryIconTheme.color!.withOpacity(.5),
: theme.primaryIconTheme.color!.withOpacity(0.5),
size: size,
);
},
@@ -326,7 +326,7 @@ class StreamChatThemeData {
return StreamSvgIcon.wutReaction(
color: highlighted
? theme.colorTheme.accentPrimary
: theme.primaryIconTheme.color!.withOpacity(.5),
: theme.primaryIconTheme.color!.withOpacity(0.5),
size: size,
);
},
@@ -2,6 +2,7 @@ import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
/// A style that overrides the default appearance of various avatar widgets.
// ignore: prefer-match-file-name
class AvatarThemeData with Diagnosticable {
/// Creates an [AvatarThemeData].
const AvatarThemeData({
@@ -25,13 +25,23 @@ class ColorTheme {
stops: [0, 1],
),
this.borderTop = const Effect(
sigmaX: 0, sigmaY: -1, color: Color(0xff000000), blur: 0, alpha: 0.08),
sigmaX: 0,
sigmaY: -1,
color: Color(0xff000000),
blur: 0,
alpha: 0.08,
),
this.borderBottom = const Effect(
sigmaX: 0, sigmaY: 1, color: Color(0xff000000), blur: 0, alpha: 0.08),
sigmaX: 0,
sigmaY: 1,
color: Color(0xff000000),
blur: 0,
alpha: 0.08,
),
this.shadowIconButton = const Effect(
sigmaX: 0, sigmaY: 2, color: Color(0xff000000), alpha: 0.5, blur: 4),
sigmaX: 0, sigmaY: 2, color: Color(0xff000000), alpha: 0.5, blur: 4,),
this.modalShadow = const Effect(
sigmaX: 0, sigmaY: 0, color: Color(0xff000000), alpha: 1, blur: 8),
sigmaX: 0, sigmaY: 0, color: Color(0xff000000), alpha: 1, blur: 8,),
}) : brightness = Brightness.light;
/// Initialise with dark theme
@@ -151,11 +151,20 @@ class GalleryFooterThemeData with Diagnosticable {
bottomSheetBarrierColor:
Color.lerp(a.bottomSheetBarrierColor, b.bottomSheetBarrierColor, t),
bottomSheetBackgroundColor: Color.lerp(
a.bottomSheetBackgroundColor, b.bottomSheetBackgroundColor, t),
a.bottomSheetBackgroundColor,
b.bottomSheetBackgroundColor,
t,
),
bottomSheetPhotosTextStyle: TextStyle.lerp(
a.bottomSheetPhotosTextStyle, b.bottomSheetPhotosTextStyle, t),
a.bottomSheetPhotosTextStyle,
b.bottomSheetPhotosTextStyle,
t,
),
bottomSheetCloseIconColor: Color.lerp(
a.bottomSheetCloseIconColor, b.bottomSheetCloseIconColor, t),
a.bottomSheetCloseIconColor,
b.bottomSheetCloseIconColor,
t,
),
);
/// Merges one [GalleryFooterThemeData] with another.
@@ -208,10 +217,16 @@ class GalleryFooterThemeData with Diagnosticable {
..add(ColorProperty('gridIconButtonColor', gridIconButtonColor))
..add(ColorProperty('bottomSheetBarrierColor', bottomSheetBarrierColor))
..add(ColorProperty(
'bottomSheetBackgroundColor', bottomSheetBackgroundColor))
'bottomSheetBackgroundColor',
bottomSheetBackgroundColor,
))
..add(DiagnosticsProperty(
'bottomSheetPhotosTextStyle', bottomSheetPhotosTextStyle))
'bottomSheetPhotosTextStyle',
bottomSheetPhotosTextStyle,
))
..add(ColorProperty(
'bottomSheetCloseIconColor', bottomSheetCloseIconColor));
'bottomSheetCloseIconColor',
bottomSheetCloseIconColor,
));
}
}
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/src/theme/avatar_theme.dart';
/// Class for getting message theme
// ignore: prefer-match-file-name
class MessageThemeData with Diagnosticable {
/// Creates a [MessageThemeData].
const MessageThemeData({
@@ -99,7 +100,7 @@ class MessageThemeData with Diagnosticable {
messageTextStyle:
TextStyle.lerp(a.messageTextStyle, b.messageTextStyle, t),
reactionsBackgroundColor: Color.lerp(
a.reactionsBackgroundColor, b.reactionsBackgroundColor, t),
a.reactionsBackgroundColor, b.reactionsBackgroundColor, t,),
reactionsBorderColor:
Color.lerp(a.messageBorderColor, b.reactionsBorderColor, t),
reactionsMaskColor:
@@ -48,7 +48,7 @@ class TypingIndicator extends StatelessWidget {
.map((e) => e.key)),
builder: (context, data) => AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: data.isNotEmpty == true
child: data.isNotEmpty
? Padding(
key: const Key('main'),
padding: padding,
@@ -90,12 +90,13 @@ class UserItem extends StatelessWidget {
Widget _buildLastActive(BuildContext context) {
final chatTheme = StreamChatTheme.of(context);
return Text(
user.online == true
user.online
? context.translations.userOnlineText
: '${context.translations.userLastOnlineText} '
'${Jiffy(user.lastActive).fromNow()}',
style: chatTheme.textTheme.footnote.copyWith(
color: chatTheme.colorTheme.textHighEmphasis.withOpacity(.5)),
color: chatTheme.colorTheme.textHighEmphasis.withOpacity(0.5),
),
);
}
}
@@ -73,7 +73,7 @@ class UserListView extends StatefulWidget {
this.listBuilder,
this.userListController,
}) : assert(
crossAxisCount == 1 || groupAlphabetically == false,
crossAxisCount == 1 || !groupAlphabetically,
'Cannot group alphabetically when crossAxisCount > 1',
),
limit = limit ?? pagination?.limit ?? 30,
@@ -407,33 +407,34 @@ class _UserListViewState extends State<UserListView>
Widget _buildQueryProgressIndicator(context, UsersBlocState usersProvider) =>
StreamBuilder<bool>(
stream: usersProvider.queryUsersLoading,
initialData: false,
builder: (context, snapshot) {
if (snapshot.hasError) {
return Container(
color: StreamChatTheme.of(context)
.colorTheme
.accentError
.withOpacity(.2),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 16),
child: Center(
child: Text(context.translations.loadingUsersError),
),
),
);
}
stream: usersProvider.queryUsersLoading,
initialData: false,
builder: (context, snapshot) {
if (snapshot.hasError) {
return Container(
height: 100,
padding: const EdgeInsets.all(32),
child: Center(
child: snapshot.data!
? const CircularProgressIndicator()
: Container(),
color: StreamChatTheme.of(context)
.colorTheme
.accentError
.withOpacity(0.2),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 16),
child: Center(
child: Text(context.translations.loadingUsersError),
),
),
);
});
}
return Container(
height: 100,
padding: const EdgeInsets.all(32),
child: Center(
child: snapshot.data!
? const CircularProgressIndicator()
: Container(),
),
);
},
);
Widget _separatorBuilder(context, i) => Container(
height: 1,
@@ -1,60 +0,0 @@
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,
required this.message,
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) => Container(
color: Colors.black87,
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: reactionToEmoji.keys.map((reactionType) {
final firstUserReaction = message.latestReactions!
.firstWhere((element) => element.type == reactionType,
//ignore: unnecessary_parenthesis
orElse: (() => null) as Reaction Function()?);
if (firstUserReaction.user == null) {
return IconButton(
iconSize: size,
icon: Container(),
onPressed: null,
);
}
return IconButton(
iconSize: size,
icon: UserAvatar(
user: firstUserReaction.user!,
constraints: BoxConstraints(
maxHeight: size - 5,
maxWidth: size - 5,
),
onTap: (user) {},
),
onPressed: () {},
);
}).toList(),
),
);
}
+67 -62
View File
@@ -29,78 +29,82 @@ Future<bool?> showConfirmationDialog(
}) {
final chatThemeData = StreamChatTheme.of(context);
return showModalBottomSheet(
useRootNavigator: false,
backgroundColor: chatThemeData.colorTheme.barsBg,
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
useRootNavigator: false,
backgroundColor: chatThemeData.colorTheme.barsBg,
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16),
)),
builder: (context) {
final effect = chatThemeData.colorTheme.borderTop;
return SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 26),
if (icon != null) icon,
const SizedBox(height: 26),
),
),
builder: (context) {
final effect = chatThemeData.colorTheme.borderTop;
return SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(height: 26),
if (icon != null) icon,
const SizedBox(height: 26),
Text(
title,
style: chatThemeData.textTheme.headlineBold,
),
const SizedBox(height: 7),
if (question != null)
Text(
title,
style: chatThemeData.textTheme.headlineBold,
question,
textAlign: TextAlign.center,
),
const SizedBox(height: 7),
if (question != null)
Text(
question,
textAlign: TextAlign.center,
),
const SizedBox(height: 36),
Container(
color: effect.color!.withOpacity(effect.alpha ?? 1),
height: 1,
),
Row(
children: [
if (cancelText != null)
Flexible(
child: Container(
alignment: Alignment.center,
child: TextButton(
onPressed: () {
Navigator.of(context).pop(false);
},
child: Text(
cancelText,
style: chatThemeData.textTheme.bodyBold.copyWith(
color: chatThemeData.colorTheme.textHighEmphasis
.withOpacity(0.5)),
),
),
),
),
const SizedBox(height: 36),
Container(
color: effect.color!.withOpacity(effect.alpha ?? 1),
height: 1,
),
Row(
children: [
if (cancelText != null)
Flexible(
child: Container(
alignment: Alignment.center,
child: TextButton(
onPressed: () {
Navigator.pop(context, true);
Navigator.of(context).pop(false);
},
child: Text(
okText,
cancelText,
style: chatThemeData.textTheme.bodyBold.copyWith(
color: chatThemeData.colorTheme.accentError),
color: chatThemeData.colorTheme.textHighEmphasis
.withOpacity(0.5),
),
),
),
),
),
],
),
],
),
);
});
Flexible(
child: Container(
alignment: Alignment.center,
child: TextButton(
onPressed: () {
Navigator.pop(context, true);
},
child: Text(
okText,
style: chatThemeData.textTheme.bodyBold.copyWith(
color: chatThemeData.colorTheme.accentError,
),
),
),
),
),
],
),
],
),
);
},
);
}
/// Shows info dialog
@@ -119,10 +123,11 @@ Future<bool?> showInfoDialog(
theme?.colorTheme.barsBg ?? chatThemeData.colorTheme.barsBg,
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16),
)),
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16),
),
),
builder: (context) => SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
@@ -147,8 +152,8 @@ Future<bool?> showInfoDialog(
height: 36,
),
Container(
color: theme?.colorTheme.textHighEmphasis.withOpacity(.08) ??
chatThemeData.colorTheme.textHighEmphasis.withOpacity(.08),
color: theme?.colorTheme.textHighEmphasis.withOpacity(0.08) ??
chatThemeData.colorTheme.textHighEmphasis.withOpacity(0.08),
height: 1,
),
Center(
@@ -6,6 +6,7 @@ import 'package:video_compress/video_compress.dart';
import 'package:video_thumbnail/video_thumbnail.dart';
///
// ignore: prefer-match-file-name
class IVideoService {
IVideoService._();
+1 -1
View File
@@ -55,7 +55,7 @@ flutter:
uses-material-design: true
dev_dependencies:
dart_code_metrics: ^4.2.0-dev.1
dart_code_metrics: ^4.2.0-dev.5
flutter_test:
sdk: flutter
golden_toolkit: ^0.9.0
@@ -59,7 +59,7 @@ final _channelPreviewThemeControl = ChannelPreviewThemeData(
color: const Color(0xff7A7A7A),
),
lastMessageAtStyle: TextTheme.light().footnote.copyWith(
color: ColorTheme.light().textHighEmphasis.withOpacity(.5),
color: ColorTheme.light().textHighEmphasis.withOpacity(0.5),
),
indicatorIconSize: 16,
);
@@ -83,7 +83,7 @@ final _channelPreviewThemeControlMidLerp = ChannelPreviewThemeData(
fontSize: 12,
),
lastMessageAtStyle: TextTheme.light().footnote.copyWith(
color: const Color(0x807f7f7f).withOpacity(.5),
color: const Color(0x807f7f7f).withOpacity(0.5),
),
indicatorIconSize: 16,
);
@@ -102,7 +102,7 @@ final _channelPreviewThemeControlDark = ChannelPreviewThemeData(
color: const Color(0xff7A7A7A),
),
lastMessageAtStyle: TextTheme.dark().footnote.copyWith(
color: ColorTheme.dark().textHighEmphasis.withOpacity(.5),
color: ColorTheme.dark().textHighEmphasis.withOpacity(0.5),
),
indicatorIconSize: 16,
);