migrate missing files

This commit is contained in:
Salvatore Giordano
2021-05-10 16:01:20 +02:00
parent 43d5e9063e
commit 435a88cd1b
25 changed files with 1292 additions and 1336 deletions
@@ -44,17 +44,18 @@ class DateDivider extends StatelessWidget {
if (uppercase) dayInfo = dayInfo.toUpperCase();
final chatThemeData = StreamChatTheme.of(context);
return Center(
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 1),
decoration: BoxDecoration(
color: StreamChatTheme.of(context).colorTheme.overlayDark,
color: chatThemeData.colorTheme.overlayDark,
borderRadius: BorderRadius.circular(8),
),
child: Text(
dayInfo,
style: StreamChatTheme.of(context).textTheme.footnote.copyWith(
color: StreamChatTheme.of(context).colorTheme.white,
style: chatThemeData.textTheme.footnote.copyWith(
color: chatThemeData.colorTheme.white,
),
),
),
@@ -31,7 +31,9 @@ class DeletedMessage extends StatelessWidget {
final bool reverse;
@override
Widget build(BuildContext context) => Transform(
Widget build(BuildContext context) {
final chatThemeData = StreamChatTheme.of(context);
return Transform(
transform: Matrix4.rotationY(reverse ? pi : 0),
alignment: Alignment.center,
child: Material(
@@ -42,14 +44,8 @@ class DeletedMessage extends StatelessWidget {
side: borderSide ??
BorderSide(
color: Theme.of(context).brightness == Brightness.dark
? StreamChatTheme.of(context)
.colorTheme
.white
.withAlpha(24)
: StreamChatTheme.of(context)
.colorTheme
.black
.withAlpha(24),
? chatThemeData.colorTheme.white.withAlpha(24)
: chatThemeData.colorTheme.black.withAlpha(24),
),
),
child: Padding(
@@ -71,4 +67,5 @@ class DeletedMessage extends StatelessWidget {
),
),
);
}
}
@@ -46,18 +46,12 @@ class GroupImage extends StatelessWidget {
onTap: onTap,
child: ClipRRect(
borderRadius: borderRadius ??
StreamChatTheme.of(context)
.ownMessageTheme
.avatarTheme
?.borderRadius,
streamChatTheme.ownMessageTheme.avatarTheme?.borderRadius,
child: Container(
constraints: constraints ??
StreamChatTheme.of(context)
.ownMessageTheme
.avatarTheme
?.constraints,
streamChatTheme.ownMessageTheme.avatarTheme?.constraints,
decoration: BoxDecoration(
color: StreamChatTheme.of(context).colorTheme.accentBlue,
color: streamChatTheme.colorTheme.accentBlue,
),
child: Flex(
direction: Axis.vertical,
@@ -125,8 +119,7 @@ class GroupImage extends StatelessWidget {
BorderRadius.zero) +
BorderRadius.circular(selectionThickness),
child: Container(
color: selectionColor ??
StreamChatTheme.of(context).colorTheme.accentBlue,
color: selectionColor ?? streamChatTheme.colorTheme.accentBlue,
height: 64,
width: 64,
child: Padding(
@@ -77,16 +77,18 @@ class _ImageFooterState extends State<ImageFooter> {
@override
Widget build(BuildContext context) {
final showShareButton = !kIsWeb;
final mediaQueryData = MediaQuery.of(context);
final chatThemeData = StreamChatTheme.of(context);
return SizedBox.fromSize(
size: Size(
MediaQuery.of(context).size.width,
MediaQuery.of(context).padding.bottom + widget.preferredSize.height,
mediaQueryData.size.width,
mediaQueryData.padding.bottom + widget.preferredSize.height,
),
child: MediaQuery.removePadding(
context: context,
removeTop: true,
child: BottomAppBar(
color: StreamChatTheme.of(context).colorTheme.white,
color: chatThemeData.colorTheme.white,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@@ -98,7 +100,7 @@ class _ImageFooterState extends State<ImageFooter> {
IconButton(
icon: StreamSvgIcon.iconShare(
size: 24,
color: StreamChatTheme.of(context).colorTheme.black,
color: chatThemeData.colorTheme.black,
),
onPressed: () async {
final attachment =
@@ -134,8 +136,7 @@ class _ImageFooterState extends State<ImageFooter> {
children: <Widget>[
Text(
'${widget.currentPage + 1} of ${widget.totalPages}',
style:
StreamChatTheme.of(context).textTheme.headlineBold,
style: chatThemeData.textTheme.headlineBold,
),
],
),
@@ -143,7 +144,7 @@ class _ImageFooterState extends State<ImageFooter> {
),
IconButton(
icon: StreamSvgIcon.iconGrid(
color: StreamChatTheme.of(context).colorTheme.black,
color: chatThemeData.colorTheme.black,
),
onPressed: () => _showPhotosModal(context),
),
@@ -155,10 +156,11 @@ class _ImageFooterState extends State<ImageFooter> {
}
void _showPhotosModal(context) {
final chatThemeData = StreamChatTheme.of(context);
showModalBottomSheet(
context: context,
barrierColor: StreamChatTheme.of(context).colorTheme.overlay,
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
barrierColor: chatThemeData.colorTheme.overlay,
backgroundColor: chatThemeData.colorTheme.white,
isScrollControlled: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
@@ -189,9 +191,7 @@ class _ImageFooterState extends State<ImageFooter> {
padding: const EdgeInsets.all(16),
child: Text(
'Photos',
style: StreamChatTheme.of(context)
.textTheme
.headlineBold,
style: chatThemeData.textTheme.headlineBold,
),
),
),
@@ -199,7 +199,7 @@ class _ImageFooterState extends State<ImageFooter> {
alignment: Alignment.centerRight,
child: IconButton(
icon: StreamSvgIcon.close(
color: StreamChatTheme.of(context).colorTheme.black,
color: chatThemeData.colorTheme.black,
),
onPressed: () => Navigator.maybePop(context),
),
@@ -262,9 +262,7 @@ class _ImageFooterState extends State<ImageFooter> {
boxShadow: [
BoxShadow(
blurRadius: 8,
color: StreamChatTheme.of(context)
.colorTheme
.black
color: chatThemeData.colorTheme.black
.withOpacity(0.3),
),
],
@@ -50,25 +50,26 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget {
final int currentIndex;
@override
Widget build(BuildContext context) => AppBar(
Widget build(BuildContext context) {
final chatThemeData = StreamChatTheme.of(context);
return AppBar(
brightness: Theme.of(context).brightness,
elevation: 1,
leading: showBackButton
? IconButton(
icon: StreamSvgIcon.close(
color: StreamChatTheme.of(context).colorTheme.black,
color: chatThemeData.colorTheme.black,
size: 24,
),
onPressed: onBackPressed,
)
: const SizedBox(),
backgroundColor:
StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color,
backgroundColor: chatThemeData.channelTheme.channelHeaderTheme.color,
actions: <Widget>[
if (message.type != 'ephemeral')
IconButton(
icon: StreamSvgIcon.iconMenuPoint(
color: StreamChatTheme.of(context).colorTheme.black,
color: chatThemeData.colorTheme.black,
),
onPressed: () {
_showMessageActionModalBottomSheet(context);
@@ -88,14 +89,11 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget {
children: <Widget>[
Text(
userName,
style:
StreamChatTheme.of(context).textTheme.headlineBold,
style: chatThemeData.textTheme.headlineBold,
),
Text(
sentAt,
style: StreamChatTheme.of(context)
.channelPreviewTheme
.subtitle,
style: chatThemeData.channelPreviewTheme.subtitle,
),
],
),
@@ -103,6 +101,7 @@ class ImageHeader extends StatelessWidget implements PreferredSizeWidget {
)
: const SizedBox(),
);
}
@override
final Size preferredSize;
@@ -38,19 +38,21 @@ class InfoTile extends StatelessWidget {
final Color? backgroundColor;
@override
Widget build(BuildContext context) => PortalEntry(
Widget build(BuildContext context) {
final chatThemeData = StreamChatTheme.of(context);
return PortalEntry(
visible: showMessage,
portalAnchor: tileAnchor ?? Alignment.topCenter,
childAnchor: childAnchor ?? Alignment.bottomCenter,
portal: Container(
height: 25,
color: backgroundColor ??
StreamChatTheme.of(context).colorTheme.grey.withOpacity(0.9),
color:
backgroundColor ?? chatThemeData.colorTheme.grey.withOpacity(0.9),
child: Center(
child: Text(
message,
style: textStyle ??
StreamChatTheme.of(context).textTheme.body.copyWith(
chatThemeData.textTheme.body.copyWith(
color: Colors.white,
),
maxLines: 1,
@@ -60,4 +62,5 @@ class InfoTile extends StatelessWidget {
),
child: child,
);
}
}
@@ -56,6 +56,7 @@ class _MediaListViewState extends State<MediaListView> {
position,
) {
final media = _media.elementAt(position);
final chatThemeData = StreamChatTheme.of(context);
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 1, vertical: 1),
child: InkWell(
@@ -89,10 +90,8 @@ class _MediaListViewState extends State<MediaListView> {
? 1.0
: 0.0,
child: Container(
color: StreamChatTheme.of(context)
.colorTheme
.black
.withOpacity(0.5),
color:
chatThemeData.colorTheme.black.withOpacity(0.5),
alignment: Alignment.topRight,
padding: const EdgeInsets.only(
top: 8,
@@ -100,13 +99,10 @@ class _MediaListViewState extends State<MediaListView> {
),
child: CircleAvatar(
radius: 12,
backgroundColor:
StreamChatTheme.of(context).colorTheme.white,
backgroundColor: chatThemeData.colorTheme.white,
child: StreamSvgIcon.check(
size: 24,
color: StreamChatTheme.of(context)
.colorTheme
.black,
color: chatThemeData.colorTheme.black,
),
),
),
@@ -128,7 +124,7 @@ class _MediaListViewState extends State<MediaListView> {
child: Text(
media.videoDuration.format(),
style: TextStyle(
color: StreamChatTheme.of(context).colorTheme.white,
color: chatThemeData.colorTheme.white,
),
),
),
@@ -1,5 +1,4 @@
import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// This widget is used for showing user tiles for mentions
@@ -32,7 +31,9 @@ class MentionTile extends StatelessWidget {
final Widget? trailing;
@override
Widget build(BuildContext context) => SizedBox(
Widget build(BuildContext context) {
final chatThemeData = StreamChatTheme.of(context);
return SizedBox(
height: 56,
child: Row(
children: [
@@ -64,7 +65,7 @@ class MentionTile extends StatelessWidget {
member.user!.name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: StreamChatTheme.of(context).textTheme.bodyBold,
style: chatThemeData.textTheme.bodyBold,
),
const SizedBox(
height: 2,
@@ -74,12 +75,8 @@ class MentionTile extends StatelessWidget {
'@${member.userId}',
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: StreamChatTheme.of(context)
.textTheme
.footnoteBold
.copyWith(
color:
StreamChatTheme.of(context).colorTheme.grey,
style: chatThemeData.textTheme.footnoteBold.copyWith(
color: chatThemeData.colorTheme.grey,
),
),
],
@@ -93,10 +90,11 @@ class MentionTile extends StatelessWidget {
left: 8,
),
child: StreamSvgIcon.mentions(
color: StreamChatTheme.of(context).colorTheme.accentBlue,
color: chatThemeData.colorTheme.accentBlue,
),
),
],
),
);
}
}
@@ -3,12 +3,12 @@ import 'dart:ui';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/src/message_action.dart';
import 'package:stream_chat_flutter/src/reaction_picker.dart';
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
import 'package:stream_chat_flutter/src/utils.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:stream_chat_flutter/src/extension.dart';
/// Constructs a modal with actions for a message
class MessageActionsModal extends StatefulWidget {
@@ -108,7 +108,8 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
Widget build(BuildContext context) => _showMessageOptionsModal();
Widget _showMessageOptionsModal() {
final size = MediaQuery.of(context).size;
final mediaQueryData = MediaQuery.of(context);
final size = mediaQueryData.size;
final user = StreamChat.of(context).user;
final roughMaxSize = 2 * size.width / 3;
@@ -133,6 +134,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
final hasFileAttachment =
widget.message.attachments.any((it) => it.type == 'file') == true;
final streamChatThemeData = StreamChatTheme.of(context);
return GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () => Navigator.maybePop(context),
@@ -145,7 +147,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
sigmaY: 10,
),
child: Container(
color: StreamChatTheme.of(context).colorTheme.overlay,
color: streamChatThemeData.colorTheme.overlay,
),
),
),
@@ -226,11 +228,9 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
left: widget.reverse ? 0 : 40,
),
child: SizedBox(
width: MediaQuery.of(context).size.width * 0.75,
width: mediaQueryData.size.width * 0.75,
child: Material(
color: StreamChatTheme.of(context)
.colorTheme
.whiteSnow,
color: streamChatThemeData.colorTheme.whiteSnow,
clipBehavior: Clip.hardEdge,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
@@ -266,9 +266,8 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
].insertBetween(
Container(
height: 1,
color: StreamChatTheme.of(context)
.colorTheme
.greyWhisper,
color: streamChatThemeData
.colorTheme.greyWhisper,
),
),
),
@@ -310,11 +309,12 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
void _showFlagDialog() async {
final client = StreamChat.of(context).client;
final streamChatThemeData = StreamChatTheme.of(context);
final answer = await showConfirmationDialog(
context,
title: 'Flag Message',
icon: StreamSvgIcon.flag(
color: StreamChatTheme.of(context).colorTheme.accentRed,
color: streamChatThemeData.colorTheme.accentRed,
size: 24,
),
question:
@@ -324,7 +324,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
cancelText: 'CANCEL',
);
final theme = StreamChatTheme.of(context);
final theme = streamChatThemeData;
if (answer == true) {
try {
await client.flagMessage(widget.message.id);
@@ -400,7 +400,9 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
);
}
Widget _buildReplyButton(BuildContext context) => InkWell(
Widget _buildReplyButton(BuildContext context) {
final streamChatThemeData = StreamChatTheme.of(context);
return InkWell(
onTap: () {
Navigator.pop(context);
if (widget.onReplyTap != null) {
@@ -412,36 +414,40 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
child: Row(
children: [
StreamSvgIcon.reply(
color: StreamChatTheme.of(context).primaryIconTheme.color,
color: streamChatThemeData.primaryIconTheme.color,
),
const SizedBox(width: 16),
Text(
'Reply',
style: StreamChatTheme.of(context).textTheme.body,
style: streamChatThemeData.textTheme.body,
),
],
),
),
);
}
Widget _buildFlagButton(BuildContext context) => InkWell(
Widget _buildFlagButton(BuildContext context) {
final streamChatThemeData = StreamChatTheme.of(context);
return InkWell(
onTap: _showFlagDialog,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 11, horizontal: 16),
child: Row(
children: [
StreamSvgIcon.iconFlag(
color: StreamChatTheme.of(context).primaryIconTheme.color,
color: streamChatThemeData.primaryIconTheme.color,
),
const SizedBox(width: 16),
Text(
'Flag Message',
style: StreamChatTheme.of(context).textTheme.body,
style: streamChatThemeData.textTheme.body,
),
],
),
),
);
}
Widget _buildDeleteButton(BuildContext context) {
final isDeleteFailed =
@@ -469,7 +475,9 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
);
}
Widget _buildCopyButton(BuildContext context) => InkWell(
Widget _buildCopyButton(BuildContext context) {
final streamChatThemeData = StreamChatTheme.of(context);
return InkWell(
onTap: () async {
widget.onCopyTap?.call(widget.message);
Navigator.pop(context);
@@ -480,19 +488,22 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
children: [
StreamSvgIcon.copy(
size: 24,
color: StreamChatTheme.of(context).primaryIconTheme.color,
color: streamChatThemeData.primaryIconTheme.color,
),
const SizedBox(width: 16),
Text(
'Copy Message',
style: StreamChatTheme.of(context).textTheme.body,
style: streamChatThemeData.textTheme.body,
),
],
),
),
);
}
Widget _buildEditMessage(BuildContext context) => InkWell(
Widget _buildEditMessage(BuildContext context) {
final streamChatThemeData = StreamChatTheme.of(context);
return InkWell(
onTap: () async {
Navigator.pop(context);
_showEditBottomSheet(context);
@@ -502,21 +513,23 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
child: Row(
children: [
StreamSvgIcon.edit(
color: StreamChatTheme.of(context).primaryIconTheme.color,
color: streamChatThemeData.primaryIconTheme.color,
),
const SizedBox(width: 16),
Text(
'Edit Message',
style: StreamChatTheme.of(context).textTheme.body,
style: streamChatThemeData.textTheme.body,
),
],
),
),
);
}
Widget _buildResendMessage(BuildContext context) {
final isUpdateFailed =
widget.message.status == MessageSendingStatus.failed_update;
final streamChatThemeData = StreamChatTheme.of(context);
return InkWell(
onTap: () {
Navigator.pop(context);
@@ -532,12 +545,12 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
child: Row(
children: [
StreamSvgIcon.circleUp(
color: StreamChatTheme.of(context).colorTheme.accentBlue,
color: streamChatThemeData.colorTheme.accentBlue,
),
const SizedBox(width: 16),
Text(
isUpdateFailed ? 'Resend Edited Message' : 'Resend',
style: StreamChatTheme.of(context).textTheme.body,
style: streamChatThemeData.textTheme.body,
),
],
),
@@ -547,13 +560,13 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
void _showEditBottomSheet(BuildContext context) {
final channel = StreamChannel.of(context).channel;
final streamChatThemeData = StreamChatTheme.of(context);
showModalBottomSheet(
context: context,
elevation: 2,
clipBehavior: Clip.hardEdge,
isScrollControlled: true,
backgroundColor:
StreamChatTheme.of(context).messageInputTheme.inputBackground,
backgroundColor: streamChatThemeData.messageInputTheme.inputBackground,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(16),
@@ -575,8 +588,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
Padding(
padding: const EdgeInsets.all(8),
child: StreamSvgIcon.edit(
color:
StreamChatTheme.of(context).colorTheme.greyGainsboro,
color: streamChatThemeData.colorTheme.greyGainsboro,
),
),
const Text(
@@ -608,7 +620,9 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
);
}
Widget _buildThreadReplyButton(BuildContext context) => InkWell(
Widget _buildThreadReplyButton(BuildContext context) {
final streamChatThemeData = StreamChatTheme.of(context);
return InkWell(
onTap: () {
Navigator.pop(context);
if (widget.onThreadReplyTap != null) {
@@ -620,15 +634,16 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
child: Row(
children: [
StreamSvgIcon.thread(
color: StreamChatTheme.of(context).primaryIconTheme.color,
color: streamChatThemeData.primaryIconTheme.color,
),
const SizedBox(width: 16),
Text(
'Thread Reply',
style: StreamChatTheme.of(context).textTheme.body,
style: streamChatThemeData.textTheme.body,
),
],
),
),
);
}
}
@@ -12,6 +12,7 @@ import 'package:image_picker/image_picker.dart';
import 'package:photo_manager/photo_manager.dart';
import 'package:shimmer/shimmer.dart';
import 'package:stream_chat_flutter/src/emoji/emoji.dart';
import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/src/media_list_view.dart';
import 'package:stream_chat_flutter/src/message_list_view.dart';
import 'package:stream_chat_flutter/src/quoted_message_widget.dart';
@@ -19,11 +20,10 @@ import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
import 'package:stream_chat_flutter/src/video_service.dart';
import 'package:stream_chat_flutter/src/video_thumbnail_image.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
import 'package:substring_highlight/substring_highlight.dart';
import 'package:video_compress/video_compress.dart';
import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// Builder for attachment thumbnails
typedef AttachmentThumbnailBuilder = Widget Function(
@@ -299,8 +299,9 @@ class MessageInputState extends State<MessageInput> {
@override
Widget build(BuildContext context) {
final streamChatThemeData = StreamChatTheme.of(context);
Widget child = Container(
color: StreamChatTheme.of(context).messageInputTheme.inputBackground,
color: streamChatThemeData.messageInputTheme.inputBackground,
child: SafeArea(
child: GestureDetector(
onPanUpdate: (details) {
@@ -325,9 +326,7 @@ class MessageInputState extends State<MessageInput> {
Padding(
padding: const EdgeInsets.all(8),
child: StreamSvgIcon.reply(
color: StreamChatTheme.of(context)
.colorTheme
.greyGainsboro,
color: streamChatThemeData.colorTheme.greyGainsboro,
),
),
const Text(
@@ -385,7 +384,9 @@ class MessageInputState extends State<MessageInput> {
],
);
Widget _buildDmCheckbox() => Row(
Widget _buildDmCheckbox() {
final streamChatThemeData = StreamChatTheme.of(context);
return Row(
children: [
Container(
height: 16,
@@ -394,10 +395,7 @@ class MessageInputState extends State<MessageInput> {
border: _sendAsDm
? null
: Border.all(
color: StreamChatTheme.of(context)
.colorTheme
.black
.withOpacity(.5),
color: streamChatThemeData.colorTheme.black.withOpacity(.5),
width: 2,
),
borderRadius: BorderRadius.circular(3),
@@ -406,8 +404,8 @@ class MessageInputState extends State<MessageInput> {
child: Material(
borderRadius: BorderRadius.circular(3),
color: _sendAsDm
? StreamChatTheme.of(context).colorTheme.accentBlue
: StreamChatTheme.of(context).colorTheme.white,
? streamChatThemeData.colorTheme.accentBlue
: streamChatThemeData.colorTheme.white,
child: InkWell(
onTap: () {
setState(() {
@@ -422,7 +420,7 @@ class MessageInputState extends State<MessageInput> {
: CrossFadeState.showSecond,
firstChild: StreamSvgIcon.check(
size: 16,
color: StreamChatTheme.of(context).colorTheme.white,
color: streamChatThemeData.colorTheme.white,
),
secondChild: const SizedBox(
height: 16,
@@ -437,16 +435,14 @@ class MessageInputState extends State<MessageInput> {
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Text(
'Also send as direct message',
style: StreamChatTheme.of(context).textTheme.footnote.copyWith(
color: StreamChatTheme.of(context)
.colorTheme
.black
.withOpacity(0.5),
style: streamChatThemeData.textTheme.footnote.copyWith(
color: streamChatThemeData.colorTheme.black.withOpacity(0.5),
),
),
),
],
);
}
Widget _animateSendButton(BuildContext context) {
final sendButton = widget.activeSendButton != null
@@ -636,10 +632,7 @@ class MessageInputState extends State<MessageInput> {
),
Text(
_chosenCommand?.name.toUpperCase() ?? '',
style: StreamChatTheme.of(context)
.textTheme
.footnoteBold
.copyWith(
style: theme.textTheme.footnoteBold.copyWith(
color: Colors.white,
),
),
@@ -839,7 +832,9 @@ class MessageInputState extends State<MessageInput> {
tween: Tween(begin: 0, end: 1),
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOutExpo,
builder: (context, val, wid) => Transform.scale(
builder: (context, val, wid) {
final streamChatThemeData = StreamChatTheme.of(context);
return Transform.scale(
scale: val,
child: Padding(
padding: const EdgeInsets.all(8),
@@ -848,15 +843,13 @@ class MessageInputState extends State<MessageInput> {
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
color: StreamChatTheme.of(context).colorTheme.white,
color: streamChatThemeData.colorTheme.white,
clipBehavior: Clip.antiAlias,
child: Container(
constraints: BoxConstraints.loose(
const Size.fromHeight(400)),
decoration: BoxDecoration(
color: StreamChatTheme.of(context)
.colorTheme
.white,
color: streamChatThemeData.colorTheme.white,
borderRadius: BorderRadius.circular(8)),
child: ListView(
padding: const EdgeInsets.all(0),
@@ -872,17 +865,15 @@ class MessageInputState extends State<MessageInput> {
horizontal: 8,
),
child: StreamSvgIcon.lightning(
color: StreamChatTheme.of(context)
.colorTheme
.accentBlue,
color: streamChatThemeData
.colorTheme.accentBlue,
),
),
Text(
'Instant Commands',
style: TextStyle(
color: StreamChatTheme.of(context)
.colorTheme
.black
color: streamChatThemeData
.colorTheme.black
.withOpacity(.5),
),
)
@@ -919,16 +910,11 @@ class MessageInputState extends State<MessageInput> {
TextSpan(
text:
' /${c.name} ${c.args}',
style:
StreamChatTheme.of(
context)
.textTheme
.body
style: streamChatThemeData
.textTheme.body
.copyWith(
// ignore: lines_longer_than_80_chars
color: StreamChatTheme.of(
// ignore: lines_longer_than_80_chars
context)
color: streamChatThemeData
// ignore: lines_longer_than_80_chars
.colorTheme
.grey,
@@ -948,7 +934,8 @@ class MessageInputState extends State<MessageInput> {
),
),
),
)),
);
}),
));
}
@@ -956,37 +943,30 @@ class MessageInputState extends State<MessageInput> {
final _attachmentContainsFile =
_attachments.values.any((it) => it.type == 'file');
final chatThemeData = StreamChatTheme.of(context);
Color _getIconColor(int index) {
final streamChatThemeData = chatThemeData;
switch (index) {
case 0:
return _attachments.isEmpty
? StreamChatTheme.of(context).colorTheme.accentBlue
? streamChatThemeData.colorTheme.accentBlue
: (!_attachmentContainsFile
? StreamChatTheme.of(context).colorTheme.accentBlue
: StreamChatTheme.of(context)
.colorTheme
.black
.withOpacity(0.2));
? streamChatThemeData.colorTheme.accentBlue
: streamChatThemeData.colorTheme.black.withOpacity(0.2));
case 1:
return _attachmentContainsFile
? StreamChatTheme.of(context).colorTheme.accentBlue
? streamChatThemeData.colorTheme.accentBlue
: (_attachments.isEmpty
? StreamChatTheme.of(context)
.colorTheme
.black
.withOpacity(0.5)
: StreamChatTheme.of(context)
.colorTheme
.black
.withOpacity(0.2));
? streamChatThemeData.colorTheme.black.withOpacity(0.5)
: streamChatThemeData.colorTheme.black.withOpacity(0.2));
case 2:
return _attachmentContainsFile && _attachments.isNotEmpty
? StreamChatTheme.of(context).colorTheme.black.withOpacity(0.2)
: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5);
? streamChatThemeData.colorTheme.black.withOpacity(0.2)
: streamChatThemeData.colorTheme.black.withOpacity(0.5);
case 3:
return _attachmentContainsFile && _attachments.isNotEmpty
? StreamChatTheme.of(context).colorTheme.black.withOpacity(0.2)
: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.5);
? streamChatThemeData.colorTheme.black.withOpacity(0.2)
: streamChatThemeData.colorTheme.black.withOpacity(0.5);
default:
return Colors.black;
}
@@ -997,7 +977,7 @@ class MessageInputState extends State<MessageInput> {
_animateContainer ? const Duration(milliseconds: 300) : Duration.zero,
height: _openFilePickerSection ? _filePickerSize : 0,
child: Material(
color: StreamChatTheme.of(context).colorTheme.whiteSmoke,
color: chatThemeData.colorTheme.whiteSmoke,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
@@ -1061,7 +1041,7 @@ class MessageInputState extends State<MessageInput> {
},
child: Container(
decoration: BoxDecoration(
color: StreamChatTheme.of(context).colorTheme.white,
color: chatThemeData.colorTheme.white,
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(16),
topRight: Radius.circular(16),
@@ -1076,8 +1056,7 @@ class MessageInputState extends State<MessageInput> {
width: 40,
height: 4,
decoration: BoxDecoration(
color:
StreamChatTheme.of(context).colorTheme.whiteSmoke,
color: chatThemeData.colorTheme.whiteSmoke,
borderRadius: BorderRadius.circular(4),
),
),
@@ -1090,7 +1069,7 @@ class MessageInputState extends State<MessageInput> {
Expanded(
child: Container(
decoration: BoxDecoration(
color: StreamChatTheme.of(context).colorTheme.white,
color: chatThemeData.colorTheme.white,
borderRadius: BorderRadius.circular(8),
),
child: _PickerWidget(
@@ -1166,6 +1145,7 @@ class MessageInputState extends State<MessageInput> {
}
Widget _buildCommandIcon(String iconType) {
final chatThemeData = StreamChatTheme.of(context);
switch (iconType) {
case 'giphy':
return CircleAvatar(
@@ -1176,7 +1156,7 @@ class MessageInputState extends State<MessageInput> {
);
case 'ban':
return CircleAvatar(
backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue,
backgroundColor: chatThemeData.colorTheme.accentBlue,
radius: 12,
child: StreamSvgIcon.iconUserDelete(
size: 16,
@@ -1185,7 +1165,7 @@ class MessageInputState extends State<MessageInput> {
);
case 'flag':
return CircleAvatar(
backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue,
backgroundColor: chatThemeData.colorTheme.accentBlue,
radius: 12,
child: StreamSvgIcon.flag(
size: 14,
@@ -1194,7 +1174,7 @@ class MessageInputState extends State<MessageInput> {
);
case 'imgur':
return CircleAvatar(
backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue,
backgroundColor: chatThemeData.colorTheme.accentBlue,
radius: 12,
child: ClipOval(
child: StreamSvgIcon.imgur(
@@ -1204,7 +1184,7 @@ class MessageInputState extends State<MessageInput> {
);
case 'mute':
return CircleAvatar(
backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue,
backgroundColor: chatThemeData.colorTheme.accentBlue,
radius: 12,
child: StreamSvgIcon.mute(
size: 16,
@@ -1213,7 +1193,7 @@ class MessageInputState extends State<MessageInput> {
);
case 'unban':
return CircleAvatar(
backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue,
backgroundColor: chatThemeData.colorTheme.accentBlue,
radius: 12,
child: StreamSvgIcon.userAdd(
size: 16,
@@ -1222,7 +1202,7 @@ class MessageInputState extends State<MessageInput> {
);
case 'unmute':
return CircleAvatar(
backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue,
backgroundColor: chatThemeData.colorTheme.accentBlue,
radius: 12,
child: StreamSvgIcon.volumeUp(
size: 16,
@@ -1231,7 +1211,7 @@ class MessageInputState extends State<MessageInput> {
);
default:
return CircleAvatar(
backgroundColor: StreamChatTheme.of(context).colorTheme.accentBlue,
backgroundColor: chatThemeData.colorTheme.accentBlue,
radius: 12,
child: StreamSvgIcon.lightning(
size: 16,
@@ -1249,17 +1229,14 @@ class MessageInputState extends State<MessageInput> {
Future<List<Member>>? queryMembers;
final channelState = StreamChannel.of(context);
if (query.isNotEmpty) {
queryMembers = StreamChannel.of(context)
.channel
queryMembers = channelState.channel
.queryMembers(filter: Filter.autoComplete('name', query))
.then((res) => res.members);
}
final members = StreamChannel.of(context)
.channel
.state
?.members
final members = channelState.channel.state?.members
.where((m) => m.user?.name.toLowerCase().contains(query) == true)
.toList() ??
[];
@@ -1281,12 +1258,14 @@ class MessageInputState extends State<MessageInput> {
tween: Tween(begin: 0, end: 1),
duration: const Duration(milliseconds: 300),
curve: Curves.easeInOutExpo,
builder: (context, val, wid) => Transform.scale(
builder: (context, val, wid) {
final chatThemeData = StreamChatTheme.of(context);
return Transform.scale(
scale: val,
child: Card(
margin: const EdgeInsets.all(8),
elevation: 2,
color: StreamChatTheme.of(context).colorTheme.white,
color: chatThemeData.colorTheme.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
@@ -1294,7 +1273,7 @@ class MessageInputState extends State<MessageInput> {
child: Container(
constraints: BoxConstraints.loose(const Size.fromHeight(240)),
decoration: BoxDecoration(
color: StreamChatTheme.of(context).colorTheme.white,
color: chatThemeData.colorTheme.white,
),
child: FutureBuilder<List<Member>>(
future: queryMembers ?? Future.value(members),
@@ -1310,8 +1289,7 @@ class MessageInputState extends State<MessageInput> {
.where((it) => it.user != null)
.map(
(m) => Material(
color:
StreamChatTheme.of(context).colorTheme.white,
color: chatThemeData.colorTheme.white,
child: InkWell(
onTap: () {
if (m.user != null) {
@@ -1350,7 +1328,8 @@ class MessageInputState extends State<MessageInput> {
),
),
),
),
);
},
),
),
);
@@ -1379,15 +1358,16 @@ class MessageInputState extends State<MessageInput> {
final renderBox = context.findRenderObject() as RenderBox;
final size = renderBox.size;
return OverlayEntry(
builder: (context) => Positioned(
return OverlayEntry(builder: (context) {
final chatThemeData = StreamChatTheme.of(context);
return Positioned(
bottom: size.height + MediaQuery.of(context).viewInsets.bottom,
left: 0,
right: 0,
child: Card(
margin: const EdgeInsets.all(8),
elevation: 2,
color: StreamChatTheme.of(context).colorTheme.white,
color: chatThemeData.colorTheme.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
@@ -1402,7 +1382,7 @@ class MessageInputState extends State<MessageInput> {
offset: Offset(0, -4),
),
],
color: StreamChatTheme.of(context).colorTheme.white,
color: chatThemeData.colorTheme.white,
),
child: ListView.builder(
padding: const EdgeInsets.all(0),
@@ -1415,21 +1395,16 @@ class MessageInputState extends State<MessageInput> {
child: Row(
children: [
Padding(
padding:
const EdgeInsets.symmetric(horizontal: 8),
padding: const EdgeInsets.symmetric(horizontal: 8),
child: StreamSvgIcon.smile(
color: StreamChatTheme.of(context)
.colorTheme
.accentBlue,
color: chatThemeData.colorTheme.accentBlue,
),
),
Flexible(
child: Text(
'Emoji matching "$query"',
style: TextStyle(
color: StreamChatTheme.of(context)
.colorTheme
.black
color: chatThemeData.colorTheme.black
.withOpacity(.5),
),
),
@@ -1440,6 +1415,7 @@ class MessageInputState extends State<MessageInput> {
}
final emoji = emojis.elementAt(i - 1)!;
final themeData = Theme.of(context);
return ListTile(
title: SubstringHighlight(
text:
@@ -1447,12 +1423,11 @@ class MessageInputState extends State<MessageInput> {
"${emoji.char} ${emoji.name!.replaceAll('_', ' ')}",
term: query,
textStyleHighlight:
Theme.of(context).textTheme.headline6!.copyWith(
themeData.textTheme.headline6!.copyWith(
fontSize: 14.5,
fontWeight: FontWeight.bold,
),
textStyle:
Theme.of(context).textTheme.headline6!.copyWith(
textStyle: themeData.textTheme.headline6!.copyWith(
fontSize: 14.5,
),
),
@@ -1463,7 +1438,8 @@ class MessageInputState extends State<MessageInput> {
}),
),
),
));
);
});
}
void _chooseEmoji(List<String> splits, Emoji emoji) {
@@ -1589,7 +1565,9 @@ class MessageInputState extends State<MessageInput> {
);
}
Widget _buildRemoveButton(Attachment attachment) => SizedBox(
Widget _buildRemoveButton(Attachment attachment) {
final chatThemeData = StreamChatTheme.of(context);
return SizedBox(
height: 24,
width: 24,
child: RawMaterialButton(
@@ -1603,16 +1581,16 @@ class MessageInputState extends State<MessageInput> {
onPressed: () {
setState(() => _attachments.remove(attachment.id));
},
fillColor:
StreamChatTheme.of(context).colorTheme.black.withOpacity(.5),
fillColor: chatThemeData.colorTheme.black.withOpacity(.5),
child: Center(
child: StreamSvgIcon.close(
size: 24,
color: StreamChatTheme.of(context).colorTheme.white,
color: chatThemeData.colorTheme.white,
),
),
),
);
}
Widget _buildAttachment(Attachment attachment) {
if (widget.attachmentThumbnailBuilders?.containsKey(attachment.type) ==
@@ -1642,18 +1620,18 @@ class MessageInputState extends State<MessageInput> {
fit: BoxFit.cover,
errorWidget: (_, obj, trace) =>
getFileTypeImage(attachment.extraData['other'] as String?),
progressIndicatorBuilder: (context, _, progress) =>
Shimmer.fromColors(
baseColor:
StreamChatTheme.of(context).colorTheme.greyGainsboro,
highlightColor:
StreamChatTheme.of(context).colorTheme.whiteSmoke,
progressIndicatorBuilder: (context, _, progress) {
final chatThemeData = StreamChatTheme.of(context);
return Shimmer.fromColors(
baseColor: chatThemeData.colorTheme.greyGainsboro,
highlightColor: chatThemeData.colorTheme.whiteSmoke,
child: Image.asset(
'images/placeholder.png',
fit: BoxFit.cover,
package: 'stream_chat_flutter',
),
),
);
},
);
case 'video':
return Stack(
@@ -1685,17 +1663,14 @@ class MessageInputState extends State<MessageInput> {
Widget _buildCommandButton() {
final s = textEditingController.text.trim();
final chatThemeData = StreamChatTheme.of(context);
return IconButton(
icon: StreamSvgIcon.lightning(
color: s.isNotEmpty
? StreamChatTheme.of(context).colorTheme.greyGainsboro
? chatThemeData.colorTheme.greyGainsboro
: (_commandsOverlay != null
? StreamChatTheme.of(context)
.messageInputTheme
.actionButtonColor
: StreamChatTheme.of(context)
.messageInputTheme
.actionButtonIdleColor),
? chatThemeData.messageInputTheme.actionButtonColor
: chatThemeData.messageInputTheme.actionButtonIdleColor),
),
padding: const EdgeInsets.all(0),
constraints: const BoxConstraints.tightFor(
@@ -1730,13 +1705,13 @@ class MessageInputState extends State<MessageInput> {
);
}
Widget _buildAttachmentButton() => IconButton(
Widget _buildAttachmentButton() {
final chatThemeData = StreamChatTheme.of(context);
return IconButton(
icon: StreamSvgIcon.attach(
color: _openFilePickerSection
? StreamChatTheme.of(context).messageInputTheme.actionButtonColor
: StreamChatTheme.of(context)
.messageInputTheme
.actionButtonIdleColor,
? chatThemeData.messageInputTheme.actionButtonColor
: chatThemeData.messageInputTheme.actionButtonIdleColor,
),
padding: const EdgeInsets.all(0),
constraints: const BoxConstraints.tightFor(
@@ -1763,6 +1738,7 @@ class MessageInputState extends State<MessageInput> {
}
},
);
}
/// Show the attachment modal, making the user choose where to
/// pick a media from
@@ -2103,8 +2079,9 @@ class MessageInputState extends State<MessageInput> {
StreamSubscription? _keyboardListener;
void _showErrorAlert(String description) {
final chatThemeData = StreamChatTheme.of(context);
showModalBottomSheet(
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
backgroundColor: chatThemeData.colorTheme.white,
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
@@ -2118,7 +2095,7 @@ class MessageInputState extends State<MessageInput> {
height: 26,
),
StreamSvgIcon.error(
color: StreamChatTheme.of(context).colorTheme.accentRed,
color: chatThemeData.colorTheme.accentRed,
size: 24,
),
const SizedBox(
@@ -2126,7 +2103,7 @@ class MessageInputState extends State<MessageInput> {
),
Text(
'Something went wrong',
style: StreamChatTheme.of(context).textTheme.headlineBold,
style: chatThemeData.textTheme.headlineBold,
),
const SizedBox(
height: 7,
@@ -2142,8 +2119,7 @@ class MessageInputState extends State<MessageInput> {
height: 36,
),
Container(
color:
StreamChatTheme.of(context).colorTheme.black.withOpacity(.08),
color: chatThemeData.colorTheme.black.withOpacity(.08),
height: 1,
),
Row(
@@ -2155,13 +2131,8 @@ class MessageInputState extends State<MessageInput> {
},
child: Text(
'OK',
style: StreamChatTheme.of(context)
.textTheme
.bodyBold
.copyWith(
color: StreamChatTheme.of(context)
.colorTheme
.accentBlue),
style: chatThemeData.textTheme.bodyBold
.copyWith(color: chatThemeData.colorTheme.accentBlue),
),
),
],
@@ -2291,6 +2262,7 @@ class __PickerWidgetState extends State<_PickerWidget> {
return const Center(child: CircularProgressIndicator());
}
final chatThemeData = StreamChatTheme.of(context);
if (snapshot.data!) {
if (widget.containsFile) {
return GestureDetector(
@@ -2299,12 +2271,12 @@ class __PickerWidgetState extends State<_PickerWidget> {
},
child: Container(
constraints: const BoxConstraints.expand(),
color: StreamChatTheme.of(context).colorTheme.whiteSmoke,
color: chatThemeData.colorTheme.whiteSmoke,
alignment: Alignment.center,
child: Text(
'Add more files',
style: TextStyle(
color: StreamChatTheme.of(context).colorTheme.accentBlue,
color: chatThemeData.colorTheme.accentBlue,
fontWeight: FontWeight.bold,
),
),
@@ -2322,7 +2294,7 @@ class __PickerWidgetState extends State<_PickerWidget> {
PhotoManager.openSetting();
},
child: Container(
color: StreamChatTheme.of(context).colorTheme.whiteSmoke,
color: chatThemeData.colorTheme.whiteSmoke,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.stretch,
@@ -2331,26 +2303,21 @@ class __PickerWidgetState extends State<_PickerWidget> {
'svgs/icon_picture_empty_state.svg',
package: 'stream_chat_flutter',
height: 140,
color: StreamChatTheme.of(context).colorTheme.greyGainsboro,
color: chatThemeData.colorTheme.greyGainsboro,
),
Text(
// ignore: lines_longer_than_80_chars
'Please enable access to your photos \nand videos so you can share them with friends.',
style: StreamChatTheme.of(context).textTheme.body.copyWith(
color: StreamChatTheme.of(context).colorTheme.grey),
style: chatThemeData.textTheme.body
.copyWith(color: chatThemeData.colorTheme.grey),
textAlign: TextAlign.center,
),
const SizedBox(height: 6),
Center(
child: Text(
'Allow access to your gallery',
style: StreamChatTheme.of(context)
.textTheme
.bodyBold
.copyWith(
color: StreamChatTheme.of(context)
.colorTheme
.accentBlue,
style: chatThemeData.textTheme.bodyBold.copyWith(
color: chatThemeData.colorTheme.accentBlue,
),
),
),
@@ -6,15 +6,15 @@ import 'package:flutter/material.dart';
import 'package:jiffy/jiffy.dart';
import 'package:rxdart/rxdart.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/src/info_tile.dart';
import 'package:stream_chat_flutter/src/message_widget.dart';
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
import 'package:stream_chat_flutter/src/swipeable.dart';
import 'package:stream_chat_flutter/src/system_message.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
import 'package:visibility_detector/visibility_detector.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/src/swipeable.dart';
/// Widget builder for message
typedef MessageBuilder = Widget Function(
@@ -274,15 +274,15 @@ class _MessageListViewState extends State<MessageListView> {
bool _showScrollToBottom = false;
late final ItemPositionsListener _itemPositionListener;
int? _messageListLength;
StreamChannelState? streamChannel;
late StreamChannelState streamChannel;
int? get _initialIndex {
if (widget.initialScrollIndex != null) return widget.initialScrollIndex;
if (streamChannel!.initialMessageId != null) {
final messages = streamChannel!.channel.state!.messages;
if (streamChannel.initialMessageId != null) {
final messages = streamChannel.channel.state!.messages;
final totalMessages = messages.length;
final messageIndex =
messages.indexWhere((e) => e.id == streamChannel!.initialMessageId);
messages.indexWhere((e) => e.id == streamChannel.initialMessageId);
final index = totalMessages - messageIndex;
if (index != 0) return index - 1;
return index;
@@ -295,9 +295,9 @@ class _MessageListViewState extends State<MessageListView> {
return 0;
}
bool _isInitialMessage(String id) => streamChannel!.initialMessageId == id;
bool _isInitialMessage(String id) => streamChannel.initialMessageId == id;
bool get _upToDate => streamChannel!.channel.state!.isUpToDate;
bool get _upToDate => streamChannel.channel.state!.isUpToDate;
bool get _isThreadConversation => widget.parentMessage != null;
@@ -316,7 +316,9 @@ class _MessageListViewState extends State<MessageListView> {
final MessageListController _messageListController = MessageListController();
@override
Widget build(BuildContext context) => MessageListCore(
Widget build(BuildContext context) {
final chatThemeData = StreamChatTheme.of(context);
return MessageListCore(
messageFilter: widget.messageFilter,
loadingBuilder: widget.loadingBuilder ??
(context) => const Center(
@@ -326,18 +328,12 @@ class _MessageListViewState extends State<MessageListView> {
(context) => Center(
child: Text(
'No chats here yet...',
style: StreamChatTheme.of(context)
.textTheme
.footnote
.copyWith(
color: StreamChatTheme.of(context)
.colorTheme
.black
.withOpacity(.5)),
style: chatThemeData.textTheme.footnote.copyWith(
color: chatThemeData.colorTheme.black.withOpacity(.5)),
),
),
messageListBuilder: widget.messageListBuilder ??
(context, list) => _buildListView(list),
messageListBuilder:
widget.messageListBuilder ?? (context, list) => _buildListView(list),
messageListController: _messageListController,
parentMessage: widget.parentMessage,
showScrollToBottom: widget.showScrollToBottom,
@@ -345,17 +341,12 @@ class _MessageListViewState extends State<MessageListView> {
(BuildContext context, Object error) => Center(
child: Text(
'Something went wrong',
style: StreamChatTheme.of(context)
.textTheme
.footnote
.copyWith(
color: StreamChatTheme.of(context)
.colorTheme
.black
.withOpacity(.5)),
style: chatThemeData.textTheme.footnote.copyWith(
color: chatThemeData.colorTheme.black.withOpacity(.5)),
),
),
);
}
Widget _buildListView(List<Message> data) {
messages = data;
@@ -448,10 +439,10 @@ class _MessageListViewState extends State<MessageListView> {
if (i == 0) return const SizedBox(height: 30);
if (i == messages.length + 1) {
final replyCount = widget.parentMessage!.replyCount;
final chatThemeData = StreamChatTheme.of(context);
return Container(
decoration: BoxDecoration(
gradient:
StreamChatTheme.of(context).colorTheme.bgGradient,
gradient: chatThemeData.colorTheme.bgGradient,
),
child: Padding(
padding: const EdgeInsets.all(8),
@@ -459,10 +450,8 @@ class _MessageListViewState extends State<MessageListView> {
// ignore: lines_longer_than_80_chars
'$replyCount ${replyCount == 1 ? 'Reply' : 'Replies'}',
textAlign: TextAlign.center,
style: StreamChatTheme.of(context)
.channelTheme
.channelHeaderTheme
.subtitle,
style: chatThemeData
.channelTheme.channelHeaderTheme.subtitle,
),
),
);
@@ -616,8 +605,8 @@ class _MessageListViewState extends State<MessageListView> {
Widget _buildScrollToBottom() => StreamBuilder<Tuple2<bool, int>>(
stream: Rx.combineLatest2(
streamChannel!.channel.state!.isUpToDateStream,
streamChannel!.channel.state!.unreadCountStream,
streamChannel.channel.state!.isUpToDateStream,
streamChannel.channel.state!.unreadCountStream,
(bool isUpToDate, int unreadCount) => Tuple2(isUpToDate, unreadCount),
),
builder: (_, snapshot) {
@@ -633,8 +622,9 @@ class _MessageListViewState extends State<MessageListView> {
}
final unreadCount = snapshot.data!.item2;
final showUnreadCount = unreadCount > 0 &&
streamChannel!.channel.state!.members.any((e) =>
e.userId == streamChannel!.channel.client.state.user!.id);
streamChannel.channel.state!.members.any((e) =>
e.userId == streamChannel.channel.client.state.user!.id);
final chatThemeData = StreamChatTheme.of(context);
return Positioned(
bottom: 8,
right: 8,
@@ -644,15 +634,15 @@ class _MessageListViewState extends State<MessageListView> {
clipBehavior: Clip.none,
children: [
FloatingActionButton(
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
backgroundColor: chatThemeData.colorTheme.white,
onPressed: () {
if (unreadCount > 0) {
streamChannel!.channel.markRead();
streamChannel.channel.markRead();
}
if (!_upToDate) {
_bottomPaginationActive = false;
_topPaginationActive = false;
streamChannel!.reloadChannel();
streamChannel.reloadChannel();
} else {
setState(() => _showScrollToBottom = false);
_scrollController!.scrollTo(
@@ -663,7 +653,7 @@ class _MessageListViewState extends State<MessageListView> {
}
},
child: StreamSvgIcon.down(
color: StreamChatTheme.of(context).colorTheme.black,
color: chatThemeData.colorTheme.black,
),
),
if (showUnreadCount)
@@ -692,12 +682,12 @@ class _MessageListViewState extends State<MessageListView> {
);
Widget _buildLoadingIndicator(
StreamChannelState? streamChannel,
StreamChannelState streamChannel,
QueryDirection direction,
) {
final stream = direction == QueryDirection.top
? streamChannel!.queryTopMessages
: streamChannel!.queryBottomMessages;
? streamChannel.queryTopMessages
: streamChannel.queryBottomMessages;
return StreamBuilder<bool>(
key: const Key('LOADING-INDICATOR'),
stream: stream,
@@ -764,7 +754,7 @@ class _MessageListViewState extends State<MessageListView> {
BuildContext context,
Message message,
List<Message> messages,
StreamChannelState? streamChannel,
StreamChannelState streamChannel,
) {
Widget messageWidget;
if (widget.messageBuilder != null) {
@@ -790,7 +780,7 @@ class _MessageListViewState extends State<MessageListView> {
onVisibilityChanged: (visibility) {
final isVisible = visibility.visibleBounds != Rect.zero;
if (isVisible) {
final channel = streamChannel!.channel;
final channel = streamChannel.channel;
if (_upToDate &&
channel.config?.readEvents == true &&
channel.state!.unreadCount! > 0) {
@@ -811,6 +801,7 @@ class _MessageListViewState extends State<MessageListView> {
final isMyMessage = message.user!.id == StreamChat.of(context).user!.id;
final isOnlyEmoji = message.text!.isOnlyEmoji;
final chatThemeData = StreamChatTheme.of(context);
return MessageWidget(
showReplyMessage: false,
showResendMessage: false,
@@ -837,8 +828,8 @@ class _MessageListViewState extends State<MessageListView> {
borderSide: isMyMessage || isOnlyEmoji ? BorderSide.none : null,
showUserAvatar: isMyMessage ? DisplayWidget.gone : DisplayWidget.show,
messageTheme: isMyMessage
? StreamChatTheme.of(context).ownMessageTheme
: StreamChatTheme.of(context).otherMessageTheme,
? chatThemeData.ownMessageTheme
: chatThemeData.otherMessageTheme,
onShowMessage: widget.onShowMessage,
onReturnAction: (action) {
switch (action) {
@@ -897,7 +888,7 @@ class _MessageListViewState extends State<MessageListView> {
);
}
final channel = streamChannel!.channel;
final channel = streamChannel.channel;
final readList = channel.state?.read?.where((read) {
if (read.user.id == userId) return false;
return read.lastRead.isAfter(message.createdAt) ||
@@ -946,6 +937,7 @@ class _MessageListViewState extends State<MessageListView> {
? BorderSide.none
: null;
final chatThemeData = StreamChatTheme.of(context);
Widget child = MessageWidget(
key: ValueKey<String>('MESSAGE-${message.id}'),
message: message,
@@ -970,7 +962,7 @@ class _MessageListViewState extends State<MessageListView> {
if (messages.map((e) => e.id).contains(quotedMessageId)) {
scrollToIndex();
} else {
await streamChannel!.loadChannelAtMessage(quotedMessageId).then((_) {
await streamChannel.loadChannelAtMessage(quotedMessageId).then((_) {
WidgetsBinding.instance!.addPostFrameCallback((_) {
if (messages.map((e) => e.id).contains(quotedMessageId)) {
scrollToIndex();
@@ -1013,8 +1005,8 @@ class _MessageListViewState extends State<MessageListView> {
horizontal: isOnlyEmoji ? 0 : 16.0,
),
messageTheme: isMyMessage
? StreamChatTheme.of(context).ownMessageTheme
: StreamChatTheme.of(context).otherMessageTheme,
? chatThemeData.ownMessageTheme
: chatThemeData.otherMessageTheme,
readList: readList,
allRead: allRead,
onShowMessage: widget.onShowMessage,
@@ -1054,7 +1046,7 @@ class _MessageListViewState extends State<MessageListView> {
widget.onMessageSwiped?.call(message);
},
backgroundIcon: StreamSvgIcon.reply(
color: StreamChatTheme.of(context).colorTheme.accentBlue,
color: chatThemeData.colorTheme.accentBlue,
),
child: child,
),
@@ -1064,7 +1056,7 @@ class _MessageListViewState extends State<MessageListView> {
if (!initialMessageHighlightComplete &&
widget.highlightInitialMessage &&
_isInitialMessage(message.id)) {
final colorTheme = StreamChatTheme.of(context).colorTheme;
final colorTheme = chatThemeData.colorTheme;
final highlightColor =
widget.messageHighlightColor ?? colorTheme.highlight;
child = TweenAnimationBuilder<Color?>(
@@ -1100,14 +1092,23 @@ class _MessageListViewState extends State<MessageListView> {
initialIndex = _initialIndex;
initialAlignment = _initialAlignment;
_getOnThreadTap();
super.initState();
}
@override
void didChangeDependencies() {
streamChannel = StreamChannel.of(context);
_messageNewListener?.cancel();
_messageNewListener =
streamChannel!.channel.on(EventType.messageNew).listen((event) {
streamChannel.channel.on(EventType.messageNew).listen((event) {
if (_upToDate) {
_bottomPaginationActive = false;
_topPaginationActive = false;
}
if (event.message!.user!.id ==
streamChannel!.channel.client.state.user!.id) {
streamChannel.channel.client.state.user!.id) {
WidgetsBinding.instance!.addPostFrameCallback((_) {
_scrollController?.jumpTo(
index: 0,
@@ -1117,11 +1118,9 @@ class _MessageListViewState extends State<MessageListView> {
});
if (_isThreadConversation) {
streamChannel!.getReplies(widget.parentMessage!.id);
streamChannel.getReplies(widget.parentMessage!.id);
}
_getOnThreadTap();
super.initState();
super.didChangeDependencies();
}
void _getOnThreadTap() {
@@ -1139,12 +1138,12 @@ class _MessageListViewState extends State<MessageListView> {
context,
MaterialPageRoute(
builder: (_) => StreamBuilder<Message>(
stream: streamChannel!.channel.state!.messagesStream.map(
stream: streamChannel.channel.state!.messagesStream.map(
(messages) =>
messages!.firstWhere((m) => m.id == message.id)),
initialData: message,
builder: (_, snapshot) => StreamChannel(
channel: streamChannel!.channel,
channel: streamChannel.channel,
child: widget.threadBuilder!(context, snapshot.data),
),
),
@@ -1157,7 +1156,7 @@ class _MessageListViewState extends State<MessageListView> {
@override
void dispose() {
if (!_upToDate) {
streamChannel!.reloadChannel();
streamChannel.reloadChannel();
}
_messageNewListener?.cancel();
super.dispose();
@@ -1,13 +1,13 @@
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/src/reaction_bubble.dart';
import 'package:stream_chat_flutter/src/reaction_picker.dart';
import 'package:stream_chat_flutter/src/stream_chat.dart';
import 'package:stream_chat_flutter/src/user_avatar.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
import 'package:stream_chat_flutter/src/extension.dart';
/// Modal widget for displaying message reactions
class MessageReactionsModal extends StatelessWidget {
@@ -176,8 +176,9 @@ class MessageReactionsModal extends StatelessWidget {
Widget _buildReactionCard(BuildContext context) {
final currentUser = StreamChat.of(context).user;
final chatThemeData = StreamChatTheme.of(context);
return Card(
color: StreamChatTheme.of(context).colorTheme.white,
color: chatThemeData.colorTheme.white,
clipBehavior: Clip.hardEdge,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
@@ -190,7 +191,7 @@ class MessageReactionsModal extends StatelessWidget {
children: [
Text(
'Message Reactions',
style: StreamChatTheme.of(context).textTheme.headlineBold,
style: chatThemeData.textTheme.headlineBold,
),
const SizedBox(height: 16),
Flexible(
@@ -220,6 +221,7 @@ class MessageReactionsModal extends StatelessWidget {
BuildContext context,
) {
final isCurrentUser = reaction.user?.id == currentUser.id;
final chatThemeData = StreamChatTheme.of(context);
return ConstrainedBox(
constraints: BoxConstraints.loose(const Size(
64,
@@ -258,7 +260,7 @@ class MessageReactionsModal extends StatelessWidget {
messageTheme.reactionsBorderColor ?? Colors.transparent,
backgroundColor: messageTheme.reactionsBackgroundColor ??
Colors.transparent,
maskColor: StreamChatTheme.of(context).colorTheme.white,
maskColor: chatThemeData.colorTheme.white,
tailCirclesSpacing: 1,
highlightOwnReactions: false,
),
@@ -269,7 +271,7 @@ class MessageReactionsModal extends StatelessWidget {
const SizedBox(height: 8),
Text(
reaction.user!.name.split(' ')[0],
style: StreamChatTheme.of(context).textTheme.footnoteBold,
style: chatThemeData.textTheme.footnoteBold,
textAlign: TextAlign.center,
),
],
@@ -35,6 +35,7 @@ class MessageSearchItem extends StatelessWidget {
final channel = getMessageResponse.channel;
final channelName = channel?.extraData['name'];
final user = message.user!;
final chatThemeData = StreamChatTheme.of(context);
return ListTile(
onTap: onTap,
leading: UserAvatar(
@@ -49,21 +50,18 @@ class MessageSearchItem extends StatelessWidget {
children: [
Text(
user.id == StreamChat.of(context).user?.id ? 'You' : user.name,
style: StreamChatTheme.of(context).channelPreviewTheme.title,
style: chatThemeData.channelPreviewTheme.title,
),
if (channelName != null) ...[
Text(
' in ',
style: StreamChatTheme.of(context)
.channelPreviewTheme
.title
?.copyWith(
style: chatThemeData.channelPreviewTheme.title?.copyWith(
fontWeight: FontWeight.normal,
),
),
Text(
channelName as String,
style: StreamChatTheme.of(context).channelPreviewTheme.title,
style: chatThemeData.channelPreviewTheme.title,
),
],
],
@@ -121,17 +119,18 @@ class MessageSearchItem extends StatelessWidget {
text = parts.join(' ');
}
final chatThemeData = StreamChatTheme.of(context);
return Text.rich(
_getDisplayText(
text!,
message.mentionedUsers,
message.attachments,
StreamChatTheme.of(context).channelPreviewTheme.subtitle?.copyWith(
chatThemeData.channelPreviewTheme.subtitle?.copyWith(
fontStyle: (message.isSystem || message.isDeleted)
? FontStyle.italic
: FontStyle.normal,
),
StreamChatTheme.of(context).channelPreviewTheme.subtitle?.copyWith(
chatThemeData.channelPreviewTheme.subtitle?.copyWith(
fontStyle: (message.isSystem || message.isDeleted)
? FontStyle.italic
: FontStyle.normal,
@@ -1,8 +1,8 @@
import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/src/info_tile.dart';
import 'package:stream_chat_flutter/src/message_search_item.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
/// Callback called when tapping on a user
typedef MessageSearchItemTapCallback = void Function(GetMessageResponse);
@@ -270,12 +270,13 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
);
if (widget.showResultCount) {
final chatThemeData = StreamChatTheme.of(context);
child = Column(
children: [
Container(
width: double.maxFinite,
decoration: BoxDecoration(
gradient: StreamChatTheme.of(context).colorTheme.bgGradient,
gradient: chatThemeData.colorTheme.bgGradient,
),
child: Padding(
padding: const EdgeInsets.symmetric(
@@ -285,7 +286,7 @@ class _MessageSearchListViewState extends State<MessageSearchListView> {
child: Text(
'${items.length} results',
style: TextStyle(
color: StreamChatTheme.of(context).colorTheme.grey,
color: chatThemeData.colorTheme.grey,
),
),
),
@@ -1,8 +1,8 @@
import 'package:collection/collection.dart' show IterableExtension;
import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
/// Text widget to display in message
class MessageText extends StatelessWidget {
@@ -31,6 +31,7 @@ class MessageText extends StatelessWidget {
Widget build(BuildContext context) {
final text = _replaceMentions(message.text ?? '').replaceAll('\n', '\\\n');
final themeData = Theme.of(context);
return MarkdownBody(
data: text,
onTapLink: (
@@ -60,8 +61,8 @@ class MessageText extends StatelessWidget {
}
},
styleSheet: MarkdownStyleSheet.fromTheme(
Theme.of(context).copyWith(
textTheme: Theme.of(context).textTheme.apply(
themeData.copyWith(
textTheme: themeData.textTheme.apply(
bodyColor: messageTheme.messageText?.color,
decoration: messageTheme.messageText?.decoration,
decorationColor: messageTheme.messageText?.decorationColor,
@@ -8,6 +8,8 @@ import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:flutter_portal/flutter_portal.dart';
import 'package:jiffy/jiffy.dart';
import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/src/image_group.dart';
import 'package:stream_chat_flutter/src/message_action.dart';
import 'package:stream_chat_flutter/src/message_actions_modal.dart';
import 'package:stream_chat_flutter/src/message_reactions_modal.dart';
@@ -15,8 +17,6 @@ import 'package:stream_chat_flutter/src/quoted_message_widget.dart';
import 'package:stream_chat_flutter/src/reaction_bubble.dart';
import 'package:stream_chat_flutter/src/url_attachment.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:stream_chat_flutter/src/image_group.dart';
import 'package:stream_chat_flutter/src/extension.dart';
/// Widget builder for building attachments
typedef AttachmentBuilder = Widget Function(
@@ -109,6 +109,7 @@ class MessageWidget extends StatefulWidget {
borderRadius: attachmentBorderRadiusGeometry ?? BorderRadius.zero,
);
final mediaQueryData = MediaQuery.of(context);
if (attachments.length > 1) {
return Padding(
padding: attachmentPadding,
@@ -118,8 +119,8 @@ class MessageWidget extends StatefulWidget {
color: messageTheme.messageBackgroundColor,
child: ImageGroup(
size: Size(
MediaQuery.of(context).size.width * 0.8,
MediaQuery.of(context).size.height * 0.3,
mediaQueryData.size.width * 0.8,
mediaQueryData.size.height * 0.3,
),
images: attachments,
message: message,
@@ -142,8 +143,8 @@ class MessageWidget extends StatefulWidget {
message: message,
messageTheme: messageTheme,
size: Size(
MediaQuery.of(context).size.width * 0.8,
MediaQuery.of(context).size.height * 0.3,
mediaQueryData.size.width * 0.8,
mediaQueryData.size.height * 0.3,
),
onShowMessage: onShowMessage,
onReturnAction: onReturnAction,
@@ -167,13 +168,14 @@ class MessageWidget extends StatefulWidget {
return wrapAttachmentWidget(
context,
Column(
children: attachments
.map((attachment) => VideoAttachment(
children: attachments.map((attachment) {
final mediaQueryData = MediaQuery.of(context);
return VideoAttachment(
attachment: attachment,
messageTheme: messageTheme,
size: Size(
MediaQuery.of(context).size.width * 0.8,
MediaQuery.of(context).size.height * 0.3,
mediaQueryData.size.width * 0.8,
mediaQueryData.size.height * 0.3,
),
message: message,
onShowMessage: onShowMessage,
@@ -183,8 +185,8 @@ class MessageWidget extends StatefulWidget {
onAttachmentTap(message, attachment);
}
: null,
))
.toList(),
);
}).toList(),
),
border,
reverse,
@@ -200,18 +202,19 @@ class MessageWidget extends StatefulWidget {
return wrapAttachmentWidget(
context,
Column(
children: attachments
.map((attachment) => GiphyAttachment(
children: attachments.map((attachment) {
final mediaQueryData = MediaQuery.of(context);
return GiphyAttachment(
attachment: attachment,
message: message,
size: Size(
MediaQuery.of(context).size.width * 0.8,
MediaQuery.of(context).size.height * 0.3,
mediaQueryData.size.width * 0.8,
mediaQueryData.size.height * 0.3,
),
onShowMessage: onShowMessage,
onReturnAction: onReturnAction,
))
.toList(),
);
}).toList(),
),
border,
reverse,
@@ -230,21 +233,24 @@ class MessageWidget extends StatefulWidget {
return Column(
children: attachments
.map<Widget>((attachment) => wrapAttachmentWidget(
.map<Widget>((attachment) {
final mediaQueryData = MediaQuery.of(context);
return wrapAttachmentWidget(
context,
FileAttachment(
message: message,
attachment: attachment,
size: Size(
MediaQuery.of(context).size.width * 0.8,
MediaQuery.of(context).size.height * 0.3,
mediaQueryData.size.width * 0.8,
mediaQueryData.size.height * 0.3,
),
),
border,
reverse,
attachmentBorderRadiusGeometry as BorderRadius? ??
BorderRadius.zero,
))
);
})
.insertBetween(SizedBox(
height: attachmentPadding.vertical / 2,
))
@@ -658,12 +664,13 @@ class _MessageWidgetState extends State<MessageWidget>
widget.onQuotedMessageTap != null
? () => widget.onQuotedMessageTap!(widget.message.quotedMessageId)
: null;
final chatThemeData = StreamChatTheme.of(context);
return QuotedMessageWidget(
onTap: onTap,
message: widget.message.quotedMessage!,
messageTheme: isMyMessage
? StreamChatTheme.of(context).otherMessageTheme
: StreamChatTheme.of(context).ownMessageTheme,
? chatThemeData.otherMessageTheme
: chatThemeData.ownMessageTheme,
reverse: widget.reverse,
padding: EdgeInsets.only(
right: 8, left: 8, top: 8, bottom: hasNonUrlAttachments ? 8 : 0),
@@ -672,6 +679,7 @@ class _MessageWidgetState extends State<MessageWidget>
Widget get _bottomRow {
if (isDeleted) {
final chatThemeData = StreamChatTheme.of(context);
return Transform(
transform: Matrix4.rotationY(widget.reverse ? pi : 0),
alignment: Alignment.center,
@@ -679,16 +687,14 @@ class _MessageWidgetState extends State<MessageWidget>
mainAxisSize: MainAxisSize.min,
children: [
StreamSvgIcon.eye(
color: StreamChatTheme.of(context).colorTheme.grey,
color: chatThemeData.colorTheme.grey,
size: 16,
),
const SizedBox(width: 8),
Text(
'Only visible to you',
style: StreamChatTheme.of(context)
.textTheme
.footnote
.copyWith(color: StreamChatTheme.of(context).colorTheme.grey),
style: chatThemeData.textTheme.footnote
.copyWith(color: chatThemeData.colorTheme.grey),
),
],
),
@@ -41,15 +41,16 @@ class OptionListTile extends StatelessWidget {
final TextStyle? titleTextStyle;
@override
Widget build(BuildContext context) => Column(
Widget build(BuildContext context) {
final chatThemeData = StreamChatTheme.of(context);
return Column(
children: [
Container(
color: separatorColor ??
StreamChatTheme.of(context).colorTheme.greyGainsboro,
color: separatorColor ?? chatThemeData.colorTheme.greyGainsboro,
height: 1,
),
Material(
color: tileColor ?? StreamChatTheme.of(context).colorTheme.white,
color: tileColor ?? chatThemeData.colorTheme.white,
child: SizedBox(
height: 63,
child: InkWell(
@@ -67,11 +68,8 @@ class OptionListTile extends StatelessWidget {
title!,
style: titleTextStyle ??
(titleColor == null
? StreamChatTheme.of(context).textTheme.bodyBold
: StreamChatTheme.of(context)
.textTheme
.bodyBold
.copyWith(
? chatThemeData.textTheme.bodyBold
: chatThemeData.textTheme.bodyBold.copyWith(
color: titleColor,
)),
),
@@ -93,4 +91,5 @@ class OptionListTile extends StatelessWidget {
),
],
);
}
}
@@ -126,6 +126,8 @@ class ReactionBubble extends StatelessWidget {
(r) => r.type == reaction.type,
);
final chatThemeData = StreamChatTheme.of(context);
final userId = StreamChat.of(context).user?.id;
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 4,
@@ -135,24 +137,16 @@ class ReactionBubble extends StatelessWidget {
assetName: reactionIcon.assetName,
width: 16,
height: 16,
color: (!highlightOwnReactions ||
reaction.user?.id == StreamChat.of(context).user?.id)
? StreamChatTheme.of(context).colorTheme.accentBlue
: StreamChatTheme.of(context)
.colorTheme
.black
.withOpacity(.5),
color: (!highlightOwnReactions || reaction.user?.id == userId)
? chatThemeData.colorTheme.accentBlue
: chatThemeData.colorTheme.black.withOpacity(.5),
)
: Icon(
Icons.help_outline_rounded,
size: 16,
color: (!highlightOwnReactions ||
reaction.user?.id == StreamChat.of(context).user?.id)
? StreamChatTheme.of(context).colorTheme.accentBlue
: StreamChatTheme.of(context)
.colorTheme
.black
.withOpacity(.5),
color: (!highlightOwnReactions || reaction.user?.id == userId)
? chatThemeData.colorTheme.accentBlue
: chatThemeData.colorTheme.black.withOpacity(.5),
),
);
}
@@ -2,8 +2,8 @@ import 'dart:math';
import 'package:ezanimation/ezanimation.dart';
import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
import 'package:stream_chat_flutter/src/extension.dart';
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// ![screenshot](https://raw.githubusercontent.com/GetStream/stream-chat-flutter/master/screenshots/reaction_picker.png)
@@ -33,7 +33,8 @@ class _ReactionPickerState extends State<ReactionPicker>
@override
Widget build(BuildContext context) {
final reactionIcons = StreamChatTheme.of(context).reactionIcons;
final chatThemeData = StreamChatTheme.of(context);
final reactionIcons = chatThemeData.reactionIcons;
if (animations.isEmpty && reactionIcons.isNotEmpty) {
reactionIcons.forEach((element) {
@@ -57,7 +58,7 @@ class _ReactionPickerState extends State<ReactionPicker>
scale: val,
child: Material(
borderRadius: BorderRadius.circular(24),
color: StreamChatTheme.of(context).colorTheme.white,
color: chatThemeData.colorTheme.white,
clipBehavior: Clip.hardEdge,
child: Padding(
padding: const EdgeInsets.symmetric(
@@ -119,9 +120,8 @@ class _ReactionPickerState extends State<ReactionPicker>
animations[index].value * 24.0,
),
color: ownReactionIndex != -1
? StreamChatTheme.of(context)
.colorTheme
.accentBlue
? chatThemeData
.colorTheme.accentBlue
: Theme.of(context)
.iconTheme
.color!
@@ -97,7 +97,9 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
final List<Widget>? actions;
@override
Widget build(BuildContext context) => AppBar(
Widget build(BuildContext context) {
final chatThemeData = StreamChatTheme.of(context);
return AppBar(
automaticallyImplyLeading: false,
brightness: Theme.of(context).brightness,
elevation: 1,
@@ -109,8 +111,7 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
showUnreads: true,
)
: const SizedBox()),
backgroundColor:
StreamChatTheme.of(context).channelTheme.channelHeaderTheme.color,
backgroundColor: chatThemeData.channelTheme.channelHeaderTheme.color,
centerTitle: true,
actions: actions,
title: InkWell(
@@ -123,10 +124,7 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
title ??
Text(
'Thread Reply',
style: StreamChatTheme.of(context)
.channelTheme
.channelHeaderTheme
.title,
style: chatThemeData.channelTheme.channelHeaderTheme.title,
),
const SizedBox(height: 2),
subtitle ??
@@ -136,17 +134,13 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
children: [
Text(
'with ',
style: StreamChatTheme.of(context)
.channelTheme
.channelHeaderTheme
.subtitle,
style: chatThemeData
.channelTheme.channelHeaderTheme.subtitle,
),
Flexible(
child: ChannelName(
textStyle: StreamChatTheme.of(context)
.channelTheme
.channelHeaderTheme
.subtitle,
textStyle: chatThemeData
.channelTheme.channelHeaderTheme.subtitle,
),
),
],
@@ -156,6 +150,7 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
),
),
);
}
@override
final Size preferredSize;
@@ -26,7 +26,9 @@ class UrlAttachment extends StatelessWidget {
final EdgeInsets textPadding;
@override
Widget build(BuildContext context) => GestureDetector(
Widget build(BuildContext context) {
final chatThemeData = StreamChatTheme.of(context);
return GestureDetector(
onTap: () {
launchURL(
context,
@@ -58,8 +60,7 @@ class UrlAttachment extends StatelessWidget {
borderRadius: const BorderRadius.only(
topRight: Radius.circular(16),
),
color:
StreamChatTheme.of(context).colorTheme.blueAlice,
color: chatThemeData.colorTheme.blueAlice,
),
child: Padding(
padding: const EdgeInsets.only(
@@ -69,13 +70,8 @@ class UrlAttachment extends StatelessWidget {
),
child: Text(
hostDisplayName,
style: StreamChatTheme.of(context)
.textTheme
.bodyBold
.copyWith(
color: StreamChatTheme.of(context)
.colorTheme
.accentBlue,
style: chatThemeData.textTheme.bodyBold.copyWith(
color: chatThemeData.colorTheme.accentBlue,
),
),
),
@@ -94,17 +90,13 @@ class UrlAttachment extends StatelessWidget {
urlAttachment.title!.trim(),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: StreamChatTheme.of(context)
.textTheme
.body
style: chatThemeData.textTheme.body
.copyWith(fontWeight: FontWeight.w700),
),
if (urlAttachment.text != null)
Text(
urlAttachment.text!,
style: StreamChatTheme.of(context)
.textTheme
.body
style: chatThemeData.textTheme.body
.copyWith(fontWeight: FontWeight.w400),
),
],
@@ -113,4 +105,5 @@ class UrlAttachment extends StatelessWidget {
],
),
);
}
}
@@ -1,7 +1,7 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
/// Widget that displays a user avatar
class UserAvatar extends StatelessWidget {
@@ -95,8 +95,7 @@ class UserAvatar extends StatelessWidget {
child: Container(
constraints: constraints ??
streamChatTheme.ownMessageTheme.avatarTheme?.constraints,
color: selectionColor ??
StreamChatTheme.of(context).colorTheme.accentBlue,
color: selectionColor ?? streamChatTheme.colorTheme.accentBlue,
child: Padding(
padding: EdgeInsets.all(selectionThickness),
child: avatar,
@@ -48,7 +48,9 @@ class UserItem extends StatelessWidget {
final bool showLastOnline;
@override
Widget build(BuildContext context) => ListTile(
Widget build(BuildContext context) {
final chatThemeData = StreamChatTheme.of(context);
return ListTile(
onTap: () {
if (onTap != null) {
onTap!(user);
@@ -73,22 +75,25 @@ class UserItem extends StatelessWidget {
),
trailing: selected
? StreamSvgIcon.checkSend(
color: StreamChatTheme.of(context).colorTheme.accentBlue,
color: chatThemeData.colorTheme.accentBlue,
)
: null,
title: Text(
user.name,
style: StreamChatTheme.of(context).textTheme.bodyBold,
style: chatThemeData.textTheme.bodyBold,
),
subtitle: showLastOnline ? _buildLastActive(context) : null,
);
}
Widget _buildLastActive(context) => Text(
Widget _buildLastActive(context) {
final chatTheme = StreamChatTheme.of(context);
return Text(
user.online == true
? 'Online'
: 'Last online ${Jiffy(user.lastActive).fromNow()}',
style: StreamChatTheme.of(context).textTheme.footnote.copyWith(
color:
StreamChatTheme.of(context).colorTheme.black.withOpacity(.5)),
style: chatTheme.textTheme.footnote
.copyWith(color: chatTheme.colorTheme.black.withOpacity(.5)),
);
}
}
@@ -295,9 +295,11 @@ class _UserListViewState extends State<UserListView>
if (i < items.length) {
final item = items[i];
return item.when(
headerItem: (header) => Container(
headerItem: (header) {
final chatThemeData = StreamChatTheme.of(context);
return Container(
key: ValueKey<String>('HEADER-$header'),
color: StreamChatTheme.of(context).colorTheme.black.withOpacity(0.05),
color: chatThemeData.colorTheme.black.withOpacity(0.05),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6),
child: Text(
@@ -305,11 +307,12 @@ class _UserListViewState extends State<UserListView>
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14.5,
color: StreamChatTheme.of(context).colorTheme.grey,
),
color: chatThemeData.colorTheme.grey,
),
),
),
);
},
userItem: (user) {
final selected = widget.selectedUsers?.contains(user) ?? false;
return Container(
+20 -27
View File
@@ -1,9 +1,9 @@
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
/// Launch URL
Future<void> launchURL(BuildContext context, String? url) async {
@@ -27,9 +27,10 @@ Future<bool?> showConfirmationDialog(
Widget? icon,
String? question,
String? cancelText,
}) =>
showModalBottomSheet(
backgroundColor: StreamChatTheme.of(context).colorTheme.white,
}) {
final chatThemeData = StreamChatTheme.of(context);
return showModalBottomSheet(
backgroundColor: chatThemeData.colorTheme.white,
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
@@ -37,7 +38,7 @@ Future<bool?> showConfirmationDialog(
topRight: Radius.circular(16),
)),
builder: (context) {
final effect = StreamChatTheme.of(context).colorTheme.borderTop;
final effect = chatThemeData.colorTheme.borderTop;
return SafeArea(
child: Column(
mainAxisSize: MainAxisSize.min,
@@ -47,7 +48,7 @@ Future<bool?> showConfirmationDialog(
const SizedBox(height: 26),
Text(
title,
style: StreamChatTheme.of(context).textTheme.headlineBold,
style: chatThemeData.textTheme.headlineBold,
),
const SizedBox(height: 7),
if (question != null)
@@ -72,13 +73,8 @@ Future<bool?> showConfirmationDialog(
},
child: Text(
cancelText,
style: StreamChatTheme.of(context)
.textTheme
.bodyBold
.copyWith(
color: StreamChatTheme.of(context)
.colorTheme
.black
style: chatThemeData.textTheme.bodyBold.copyWith(
color: chatThemeData.colorTheme.black
.withOpacity(0.5)),
),
),
@@ -93,13 +89,8 @@ Future<bool?> showConfirmationDialog(
},
child: Text(
okText,
style: StreamChatTheme.of(context)
.textTheme
.bodyBold
.copyWith(
color: StreamChatTheme.of(context)
.colorTheme
.accentRed),
style: chatThemeData.textTheme.bodyBold.copyWith(
color: chatThemeData.colorTheme.accentRed),
),
),
),
@@ -110,6 +101,7 @@ Future<bool?> showConfirmationDialog(
),
);
});
}
/// Shows info dialog
Future<bool?> showInfoDialog(
@@ -119,10 +111,10 @@ Future<bool?> showInfoDialog(
Widget? icon,
String? details,
StreamChatThemeData? theme,
}) =>
showModalBottomSheet(
backgroundColor: theme?.colorTheme.white ??
StreamChatTheme.of(context).colorTheme.white,
}) {
final chatThemeData = StreamChatTheme.of(context);
return showModalBottomSheet(
backgroundColor: theme?.colorTheme.white ?? chatThemeData.colorTheme.white,
context: context,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
@@ -143,7 +135,7 @@ Future<bool?> showInfoDialog(
Text(
title,
style: theme?.textTheme.headlineBold ??
StreamChatTheme.of(context).textTheme.headlineBold,
chatThemeData.textTheme.headlineBold,
),
const SizedBox(
height: 7,
@@ -154,7 +146,7 @@ Future<bool?> showInfoDialog(
),
Container(
color: theme?.colorTheme.black.withOpacity(.08) ??
StreamChatTheme.of(context).colorTheme.black.withOpacity(.08),
chatThemeData.colorTheme.black.withOpacity(.08),
height: 1,
),
Center(
@@ -166,7 +158,7 @@ Future<bool?> showInfoDialog(
okText,
style: TextStyle(
color: theme?.colorTheme.black.withOpacity(0.5) ??
StreamChatTheme.of(context).colorTheme.accentBlue,
chatThemeData.colorTheme.accentBlue,
fontWeight: FontWeight.w400,
),
),
@@ -176,6 +168,7 @@ Future<bool?> showInfoDialog(
),
),
);
}
/// Get random png with initials
String getRandomPicUrl(User user) =>