import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/channel_header.dart'; import 'package:stream_chat_flutter/src/channel_preview.dart'; import 'package:stream_chat_flutter/src/extension.dart'; import 'package:stream_chat_flutter/src/message_input.dart'; import 'package:stream_chat_flutter/src/reaction_icon.dart'; import 'package:stream_chat_flutter/src/utils.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; /// Inherited widget providing the [StreamChatThemeData] to the widget tree class StreamChatTheme extends InheritedWidget { /// Constructor for creating a [StreamChatTheme] const StreamChatTheme({ Key? key, required this.data, required Widget child, }) : super( key: key, child: child, ); /// Theme data final StreamChatThemeData data; @override bool updateShouldNotify(StreamChatTheme old) => data != old.data; /// Use this method to get the current [StreamChatThemeData] instance static StreamChatThemeData of(BuildContext context) { final streamChatTheme = context.dependOnInheritedWidgetOfExactType(); assert( streamChatTheme != null, 'You must have a StreamChatTheme widget at the top of your widget tree', ); return streamChatTheme!.data; } } /// Theme data class StreamChatThemeData { /// Create a theme from scratch factory StreamChatThemeData({ Brightness? brightness, TextTheme? textTheme, ColorTheme? colorTheme, ChannelListHeaderTheme? channelListHeaderTheme, ChannelPreviewTheme? channelPreviewTheme, ChannelTheme? channelTheme, MessageTheme? otherMessageTheme, MessageTheme? ownMessageTheme, MessageInputTheme? messageInputTheme, Widget Function(BuildContext, Channel)? defaultChannelImage, Widget Function(BuildContext, User)? defaultUserImage, IconThemeData? primaryIconTheme, List? reactionIcons, }) { brightness ??= colorTheme?.brightness ?? Brightness.light; final isDark = brightness == Brightness.dark; textTheme ??= isDark ? TextTheme.dark() : TextTheme.light(); colorTheme ??= isDark ? ColorTheme.dark() : ColorTheme.light(); final defaultData = fromColorAndTextTheme( colorTheme, textTheme, ); final customizedData = defaultData.copyWith( channelListHeaderTheme: channelListHeaderTheme, channelPreviewTheme: channelPreviewTheme, channelTheme: channelTheme, otherMessageTheme: otherMessageTheme, ownMessageTheme: ownMessageTheme, messageInputTheme: messageInputTheme, defaultChannelImage: defaultChannelImage, defaultUserImage: defaultUserImage, primaryIconTheme: primaryIconTheme, reactionIcons: reactionIcons, ); return defaultData.merge(customizedData); } /// Theme initialised with light factory StreamChatThemeData.light() => StreamChatThemeData(brightness: Brightness.light); /// Theme initialised with dark factory StreamChatThemeData.dark() => StreamChatThemeData(brightness: Brightness.dark); /// Raw theme init const StreamChatThemeData.raw({ required this.textTheme, required this.colorTheme, required this.channelListHeaderTheme, required this.channelPreviewTheme, required this.channelTheme, required this.otherMessageTheme, required this.ownMessageTheme, required this.messageInputTheme, required this.defaultChannelImage, required this.defaultUserImage, required this.primaryIconTheme, required this.reactionIcons, }); /// Create a theme from a Material [Theme] factory StreamChatThemeData.fromTheme(ThemeData theme) { final defaultTheme = StreamChatThemeData(brightness: theme.brightness); final customizedTheme = StreamChatThemeData.fromColorAndTextTheme( defaultTheme.colorTheme.copyWith( accentBlue: theme.accentColor, ), defaultTheme.textTheme, ); return defaultTheme.merge(customizedTheme); } /// The text themes used in the widgets final TextTheme textTheme; /// The color themes used in the widgets final ColorTheme colorTheme; /// Theme of the [ChannelPreview] final ChannelPreviewTheme channelPreviewTheme; /// Theme of the [ChannelListHeader] final ChannelListHeaderTheme channelListHeaderTheme; /// Theme of the chat widgets dedicated to a channel final ChannelTheme channelTheme; /// Theme of the current user messages final MessageTheme ownMessageTheme; /// Theme of other users messages final MessageTheme otherMessageTheme; /// Theme dedicated to the [MessageInput] widget final MessageInputTheme messageInputTheme; /// The widget that will be built when the channel image is unavailable final Widget Function(BuildContext, Channel) defaultChannelImage; /// The widget that will be built when the user image is unavailable final Widget Function(BuildContext, User) defaultUserImage; /// Primary icon theme final IconThemeData primaryIconTheme; /// Assets used for rendering reactions final List reactionIcons; /// Creates a copy of [StreamChatThemeData] with specified attributes /// overridden. StreamChatThemeData copyWith({ TextTheme? textTheme, ColorTheme? colorTheme, ChannelPreviewTheme? channelPreviewTheme, ChannelTheme? channelTheme, MessageTheme? ownMessageTheme, MessageTheme? otherMessageTheme, MessageInputTheme? messageInputTheme, Widget Function(BuildContext, Channel)? defaultChannelImage, Widget Function(BuildContext, User)? defaultUserImage, IconThemeData? primaryIconTheme, ChannelListHeaderTheme? channelListHeaderTheme, List? reactionIcons, }) => StreamChatThemeData.raw( channelListHeaderTheme: this.channelListHeaderTheme.merge(channelListHeaderTheme), textTheme: this.textTheme.merge(textTheme), colorTheme: this.colorTheme.merge(colorTheme), primaryIconTheme: this.primaryIconTheme.merge(primaryIconTheme), defaultChannelImage: defaultChannelImage ?? this.defaultChannelImage, defaultUserImage: defaultUserImage ?? this.defaultUserImage, channelPreviewTheme: this.channelPreviewTheme.merge(channelPreviewTheme), channelTheme: this.channelTheme.merge(channelTheme), ownMessageTheme: this.ownMessageTheme.merge(ownMessageTheme), otherMessageTheme: this.otherMessageTheme.merge(otherMessageTheme), messageInputTheme: this.messageInputTheme.merge(messageInputTheme), reactionIcons: reactionIcons ?? this.reactionIcons, ); /// Merge themes StreamChatThemeData merge(StreamChatThemeData? other) { if (other == null) return this; return copyWith( channelListHeaderTheme: channelListHeaderTheme.merge(other.channelListHeaderTheme), textTheme: textTheme.merge(other.textTheme), colorTheme: colorTheme.merge(other.colorTheme), primaryIconTheme: other.primaryIconTheme, defaultChannelImage: other.defaultChannelImage, defaultUserImage: other.defaultUserImage, channelPreviewTheme: channelPreviewTheme.merge(other.channelPreviewTheme), channelTheme: channelTheme.merge(other.channelTheme), ownMessageTheme: ownMessageTheme.merge(other.ownMessageTheme), otherMessageTheme: otherMessageTheme.merge(other.otherMessageTheme), messageInputTheme: messageInputTheme.merge(other.messageInputTheme), reactionIcons: other.reactionIcons, ); } /// Create theme from color and text theme // ignore: prefer_constructors_over_static_methods static StreamChatThemeData fromColorAndTextTheme( ColorTheme colorTheme, TextTheme textTheme, ) { final accentColor = colorTheme.accentBlue; return StreamChatThemeData.raw( textTheme: textTheme, colorTheme: colorTheme, primaryIconTheme: IconThemeData(color: colorTheme.black.withOpacity(.5)), defaultChannelImage: (context, channel) => const SizedBox(), defaultUserImage: (context, user) => Center( child: CachedNetworkImage( filterQuality: FilterQuality.high, imageUrl: getRandomPicUrl(user), fit: BoxFit.cover, ), ), channelPreviewTheme: ChannelPreviewTheme( unreadCounterColor: colorTheme.accentRed, avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), constraints: const BoxConstraints.tightFor( height: 40, width: 40, ), ), title: textTheme.bodyBold, subtitle: textTheme.footnote.copyWith( color: const Color(0xff7A7A7A), ), lastMessageAt: textTheme.footnote.copyWith( color: colorTheme.black.withOpacity(.5), ), indicatorIconSize: 16, ), channelListHeaderTheme: ChannelListHeaderTheme( avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), constraints: const BoxConstraints.tightFor( height: 40, width: 40, ), ), color: colorTheme.white, title: textTheme.headlineBold, ), channelTheme: ChannelTheme( channelHeaderTheme: ChannelHeaderTheme( avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), constraints: const BoxConstraints.tightFor( height: 40, width: 40, ), ), color: colorTheme.white, title: textTheme.headlineBold, subtitle: textTheme.footnote.copyWith( color: const Color(0xff7A7A7A), ), ), ), ownMessageTheme: MessageTheme( messageAuthor: textTheme.footnote.copyWith(color: colorTheme.grey), messageText: textTheme.body, createdAt: textTheme.footnote.copyWith(color: colorTheme.grey), replies: textTheme.footnoteBold.copyWith(color: accentColor), messageBackgroundColor: colorTheme.greyGainsboro, reactionsBackgroundColor: colorTheme.white, reactionsBorderColor: colorTheme.greyWhisper, reactionsMaskColor: colorTheme.whiteSnow, messageBorderColor: colorTheme.greyGainsboro, avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), constraints: const BoxConstraints.tightFor( height: 32, width: 32, ), ), messageLinks: TextStyle( color: accentColor, ), ), otherMessageTheme: MessageTheme( reactionsBackgroundColor: colorTheme.greyGainsboro, reactionsBorderColor: colorTheme.white, reactionsMaskColor: colorTheme.whiteSnow, messageText: textTheme.body, createdAt: textTheme.footnote.copyWith(color: colorTheme.grey), messageAuthor: textTheme.footnote.copyWith(color: colorTheme.grey), replies: textTheme.footnoteBold.copyWith(color: accentColor), messageLinks: TextStyle( color: accentColor, ), messageBackgroundColor: colorTheme.white, messageBorderColor: colorTheme.greyWhisper, avatarTheme: AvatarTheme( borderRadius: BorderRadius.circular(20), constraints: const BoxConstraints.tightFor( height: 32, width: 32, ), ), ), messageInputTheme: MessageInputTheme( borderRadius: BorderRadius.circular(20), sendAnimationDuration: const Duration(milliseconds: 300), actionButtonColor: colorTheme.accentBlue, actionButtonIdleColor: colorTheme.grey, expandButtonColor: colorTheme.accentBlue, sendButtonColor: colorTheme.accentBlue, sendButtonIdleColor: colorTheme.greyGainsboro, inputBackground: colorTheme.white, inputTextStyle: textTheme.body, idleBorderGradient: LinearGradient( colors: [ colorTheme.greyGainsboro, colorTheme.greyGainsboro, ], ), activeBorderGradient: LinearGradient( colors: [ colorTheme.greyGainsboro, colorTheme.greyGainsboro, ], ), ), reactionIcons: [ ReactionIcon( type: 'love', assetName: 'Icon_love_reaction.svg', ), ReactionIcon( type: 'like', assetName: 'Icon_thumbs_up_reaction.svg', ), ReactionIcon( type: 'sad', assetName: 'Icon_thumbs_down_reaction.svg', ), ReactionIcon( type: 'haha', assetName: 'Icon_LOL_reaction.svg', ), ReactionIcon( type: 'wow', assetName: 'Icon_wut_reaction.svg', ), ], ); } } /// Class for holding text theme class TextTheme { /// Initialise light text theme TextTheme.light({ this.title = const TextStyle( fontSize: 22, fontWeight: FontWeight.bold, color: Colors.black, ), this.headlineBold = const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.black, ), this.headline = const TextStyle( fontSize: 16, fontWeight: FontWeight.w500, color: Colors.black, ), this.bodyBold = const TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: Colors.black, ), this.body = const TextStyle( fontSize: 14, fontWeight: FontWeight.w500, color: Colors.black, ), this.footnoteBold = const TextStyle( fontSize: 12, fontWeight: FontWeight.w500, color: Colors.black, ), this.footnote = const TextStyle( fontSize: 12, color: Colors.black, ), this.captionBold = const TextStyle( fontSize: 10, fontWeight: FontWeight.bold, color: Colors.black, ), }); /// Initialise with dark theme TextTheme.dark({ this.title = const TextStyle( fontSize: 22, fontWeight: FontWeight.bold, color: Colors.white, ), this.headlineBold = const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Colors.white, ), this.headline = const TextStyle( fontSize: 16, fontWeight: FontWeight.w500, color: Colors.white, ), this.bodyBold = const TextStyle( fontSize: 14, fontWeight: FontWeight.bold, color: Colors.white, ), this.body = const TextStyle( fontSize: 14, fontWeight: FontWeight.w500, color: Colors.white, ), this.footnoteBold = const TextStyle( fontSize: 12, fontWeight: FontWeight.w500, color: Colors.white, ), this.footnote = const TextStyle( fontSize: 12, color: Colors.white, ), this.captionBold = const TextStyle( fontSize: 10, fontWeight: FontWeight.bold, color: Colors.white, ), }); /// Text theme for title final TextStyle title; /// Body Text theme for headline final TextStyle headlineBold; /// Text theme for headline final TextStyle headline; /// Bold Text theme for body final TextStyle bodyBold; /// Text theme body final TextStyle body; /// Bold Text theme for footnote final TextStyle footnoteBold; /// Text theme for footnote final TextStyle footnote; /// Bold Text theme for caption final TextStyle captionBold; /// Copy with theme TextTheme copyWith({ Brightness brightness = Brightness.light, TextStyle? body, TextStyle? title, TextStyle? headlineBold, TextStyle? headline, TextStyle? bodyBold, TextStyle? footnoteBold, TextStyle? footnote, TextStyle? captionBold, }) => brightness == Brightness.light ? TextTheme.light( body: body ?? this.body, title: title ?? this.title, headlineBold: headlineBold ?? this.headlineBold, headline: headline ?? this.headline, bodyBold: bodyBold ?? this.bodyBold, footnoteBold: footnoteBold ?? this.footnoteBold, footnote: footnote ?? this.footnote, captionBold: captionBold ?? this.captionBold, ) : TextTheme.dark( body: body ?? this.body, title: title ?? this.title, headlineBold: headlineBold ?? this.headlineBold, headline: headline ?? this.headline, bodyBold: bodyBold ?? this.bodyBold, footnoteBold: footnoteBold ?? this.footnoteBold, footnote: footnote ?? this.footnote, captionBold: captionBold ?? this.captionBold, ); /// Merge text theme TextTheme merge(TextTheme? other) { if (other == null) return this; return copyWith( body: body.merge(other.body), title: title.merge(other.title), headlineBold: headlineBold.merge(other.headlineBold), headline: headline.merge(other.headline), bodyBold: bodyBold.merge(other.bodyBold), footnoteBold: footnoteBold.merge(other.footnoteBold), footnote: footnote.merge(other.footnote), captionBold: captionBold.merge(other.captionBold), ); } } /// Theme that holds colors class ColorTheme { /// Initialise with light theme ColorTheme.light({ this.black = const Color(0xff000000), this.grey = const Color(0xff7a7a7a), this.greyGainsboro = const Color(0xffdbdbdb), this.greyWhisper = const Color(0xffecebeb), this.whiteSmoke = const Color(0xfff2f2f2), this.whiteSnow = const Color(0xfffcfcfc), this.white = const Color(0xffffffff), this.blueAlice = const Color(0xffe9f2ff), this.accentBlue = const Color(0xff005FFF), this.accentRed = const Color(0xffFF3842), this.accentGreen = const Color(0xff20E070), this.highlight = const Color(0xfffbf4dd), this.overlay = const Color.fromRGBO(0, 0, 0, 0.2), this.overlayDark = const Color.fromRGBO(0, 0, 0, 0.6), this.bgGradient = const LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [Color(0xfff7f7f7), Color(0xfffcfcfc)], stops: [0, 1], ), this.borderTop = const Effect( 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), this.shadowIconButton = const Effect( 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), }) : brightness = Brightness.light; /// Initialise with dark theme ColorTheme.dark({ this.black = const Color(0xffffffff), this.grey = const Color(0xff7a7a7a), this.greyGainsboro = const Color(0xff2d2f2f), this.greyWhisper = const Color(0xff1c1e22), this.whiteSmoke = const Color(0xff13151b), this.whiteSnow = const Color(0xff070A0D), this.white = const Color(0xff101418), this.blueAlice = const Color(0xff00193D), this.accentBlue = const Color(0xff005FFF), this.accentRed = const Color(0xffFF3742), this.accentGreen = const Color(0xff20E070), this.borderTop = const Effect( sigmaX: 0, sigmaY: -1, color: Color(0xff141924), blur: 0, ), this.borderBottom = const Effect( sigmaX: 0, sigmaY: 1, color: Color(0xff141924), blur: 0, alpha: 1, ), this.shadowIconButton = const Effect( 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, ), this.highlight = const Color(0xff302d22), this.overlay = const Color.fromRGBO(0, 0, 0, 0.4), this.overlayDark = const Color.fromRGBO(255, 255, 255, 0.6), this.bgGradient = const LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Color(0xff101214), Color(0xff070a0d), ], stops: [0, 1], ), }) : brightness = Brightness.dark; /// final Color black; /// final Color grey; /// final Color greyGainsboro; /// final Color greyWhisper; /// final Color whiteSmoke; /// final Color whiteSnow; /// final Color white; /// final Color blueAlice; /// final Color accentBlue; /// final Color accentRed; /// final Color accentGreen; /// final Effect borderTop; /// final Effect borderBottom; /// final Effect shadowIconButton; /// final Effect modalShadow; /// final Color highlight; /// final Color overlay; /// final Color overlayDark; /// final Gradient bgGradient; /// final Brightness brightness; /// Copy with theme ColorTheme copyWith({ Brightness brightness = Brightness.light, Color? black, Color? grey, Color? greyGainsboro, Color? greyWhisper, Color? whiteSmoke, Color? whiteSnow, Color? white, Color? blueAlice, Color? accentBlue, Color? accentRed, Color? accentGreen, Effect? borderTop, Effect? borderBottom, Effect? shadowIconButton, Effect? modalShadow, Color? highlight, Color? overlay, Color? overlayDark, Gradient? bgGradient, }) => brightness == Brightness.light ? ColorTheme.light( black: black ?? this.black, grey: grey ?? this.grey, greyGainsboro: greyGainsboro ?? this.greyGainsboro, greyWhisper: greyWhisper ?? this.greyWhisper, whiteSmoke: whiteSmoke ?? this.whiteSmoke, whiteSnow: whiteSnow ?? this.whiteSnow, white: white ?? this.white, blueAlice: blueAlice ?? this.blueAlice, accentBlue: accentBlue ?? this.accentBlue, accentRed: accentRed ?? this.accentRed, accentGreen: accentGreen ?? this.accentGreen, borderTop: borderTop ?? this.borderTop, borderBottom: borderBottom ?? this.borderBottom, shadowIconButton: shadowIconButton ?? this.shadowIconButton, modalShadow: modalShadow ?? this.modalShadow, highlight: highlight ?? this.highlight, overlay: overlay ?? this.overlay, overlayDark: overlayDark ?? this.overlayDark, bgGradient: bgGradient ?? this.bgGradient, ) : ColorTheme.dark( black: black ?? this.black, grey: grey ?? this.grey, greyGainsboro: greyGainsboro ?? this.greyGainsboro, greyWhisper: greyWhisper ?? this.greyWhisper, whiteSmoke: whiteSmoke ?? this.whiteSmoke, whiteSnow: whiteSnow ?? this.whiteSnow, white: white ?? this.white, blueAlice: blueAlice ?? this.blueAlice, accentBlue: accentBlue ?? this.accentBlue, accentRed: accentRed ?? this.accentRed, accentGreen: accentGreen ?? this.accentGreen, borderTop: borderTop ?? this.borderTop, borderBottom: borderBottom ?? this.borderBottom, shadowIconButton: shadowIconButton ?? this.shadowIconButton, modalShadow: modalShadow ?? this.modalShadow, highlight: highlight ?? this.highlight, overlay: overlay ?? this.overlay, overlayDark: overlayDark ?? this.overlayDark, bgGradient: bgGradient ?? this.bgGradient, ); /// Merge color theme ColorTheme merge(ColorTheme? other) { if (other == null) return this; return copyWith( black: other.black, grey: other.grey, greyGainsboro: other.greyGainsboro, greyWhisper: other.greyWhisper, whiteSmoke: other.whiteSmoke, whiteSnow: other.whiteSnow, white: other.white, blueAlice: other.blueAlice, accentBlue: other.accentBlue, accentRed: other.accentRed, accentGreen: other.accentGreen, highlight: other.highlight, overlay: other.overlay, overlayDark: other.overlayDark, bgGradient: other.bgGradient, borderTop: other.borderTop, borderBottom: other.borderBottom, shadowIconButton: other.shadowIconButton, modalShadow: other.modalShadow, ); } } /// Channel theme data class ChannelTheme { /// Constructor for creating [ChannelTheme] ChannelTheme({ required this.channelHeaderTheme, }); /// Theme of the [ChannelHeader] widget final ChannelHeaderTheme channelHeaderTheme; /// Creates a copy of [ChannelTheme] with specified attributes overridden. ChannelTheme copyWith({ ChannelHeaderTheme? channelHeaderTheme, }) => ChannelTheme( channelHeaderTheme: channelHeaderTheme ?? this.channelHeaderTheme, ); /// Merge with theme ChannelTheme merge(ChannelTheme? other) { if (other == null) return this; return copyWith( channelHeaderTheme: channelHeaderTheme.merge(other.channelHeaderTheme), ); } } /// Theme for avatar class AvatarTheme { /// Constructor for creating [AvatarTheme] AvatarTheme({ BoxConstraints? constraints, BorderRadius? borderRadius, }) : _constraints = constraints, _borderRadius = borderRadius; final BoxConstraints? _constraints; final BorderRadius? _borderRadius; /// Get constraints for avatar BoxConstraints get constraints => _constraints ?? const BoxConstraints.tightFor( height: 32, width: 32, ); /// Get border radius BorderRadius get borderRadius => _borderRadius ?? BorderRadius.circular(20); /// Copy with another theme AvatarTheme copyWith({ BoxConstraints? constraints, BorderRadius? borderRadius, }) => AvatarTheme( constraints: constraints ?? _constraints, borderRadius: borderRadius ?? _borderRadius, ); /// Merge with another AvatarTheme AvatarTheme merge(AvatarTheme? other) { if (other == null) return this; return copyWith( constraints: other._constraints, borderRadius: other._borderRadius, ); } } /// Class for getting message theme class MessageTheme { /// Constructor into [MessageTheme] const MessageTheme({ this.replies, this.messageText, this.messageAuthor, this.messageLinks, this.messageBackgroundColor, this.messageBorderColor, this.reactionsBackgroundColor, this.reactionsBorderColor, this.reactionsMaskColor, this.avatarTheme, this.createdAt, }); /// Text style for message text final TextStyle? messageText; /// Text style for message author final TextStyle? messageAuthor; /// Text style for message links final TextStyle? messageLinks; /// Text style for created at text final TextStyle? createdAt; /// Text style for replies final TextStyle? replies; /// Color for messageBackgroundColor final Color? messageBackgroundColor; /// Color for message border color final Color? messageBorderColor; /// Color for reactions final Color? reactionsBackgroundColor; /// Colors reaction border final Color? reactionsBorderColor; /// Color for reaction mask final Color? reactionsMaskColor; /// Theme of the avatar final AvatarTheme? avatarTheme; /// Copy with a theme MessageTheme copyWith({ TextStyle? messageText, TextStyle? messageAuthor, TextStyle? messageLinks, TextStyle? createdAt, TextStyle? replies, Color? messageBackgroundColor, Color? messageBorderColor, AvatarTheme? avatarTheme, Color? reactionsBackgroundColor, Color? reactionsBorderColor, Color? reactionsMaskColor, }) => MessageTheme( messageText: messageText ?? this.messageText, messageAuthor: messageAuthor ?? this.messageAuthor, messageLinks: messageLinks ?? this.messageLinks, createdAt: createdAt ?? this.createdAt, messageBackgroundColor: messageBackgroundColor ?? this.messageBackgroundColor, messageBorderColor: messageBorderColor ?? this.messageBorderColor, avatarTheme: avatarTheme ?? this.avatarTheme, replies: replies ?? this.replies, reactionsBackgroundColor: reactionsBackgroundColor ?? this.reactionsBackgroundColor, reactionsBorderColor: reactionsBorderColor ?? this.reactionsBorderColor, reactionsMaskColor: reactionsMaskColor ?? this.reactionsMaskColor, ); /// Merge with a theme MessageTheme merge(MessageTheme? other) { if (other == null) return this; return copyWith( messageText: messageText?.merge(other.messageText) ?? other.messageText, messageAuthor: messageAuthor?.merge(other.messageAuthor) ?? other.messageAuthor, messageLinks: messageLinks?.merge(other.messageLinks) ?? other.messageLinks, createdAt: createdAt?.merge(other.createdAt) ?? other.createdAt, replies: replies?.merge(other.replies) ?? other.replies, messageBackgroundColor: other.messageBackgroundColor, messageBorderColor: other.messageBorderColor, avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, reactionsBackgroundColor: other.reactionsBackgroundColor, reactionsBorderColor: other.reactionsBorderColor, reactionsMaskColor: other.reactionsMaskColor, ); } } /// Theme for channel preview class ChannelPreviewTheme { /// Constructor for creating [ChannelPreviewTheme] const ChannelPreviewTheme({ this.title, this.subtitle, this.lastMessageAt, this.avatarTheme, this.unreadCounterColor, this.indicatorIconSize, }); /// Theme for title final TextStyle? title; /// Theme for subtitle final TextStyle? subtitle; /// Theme of last message at final TextStyle? lastMessageAt; /// Avatar theme final AvatarTheme? avatarTheme; /// Unread counter color final Color? unreadCounterColor; /// Indicator icon size final double? indicatorIconSize; /// Copy with theme ChannelPreviewTheme copyWith({ TextStyle? title, TextStyle? subtitle, TextStyle? lastMessageAt, AvatarTheme? avatarTheme, Color? unreadCounterColor, double? indicatorIconSize, }) => ChannelPreviewTheme( title: title ?? this.title, subtitle: subtitle ?? this.subtitle, lastMessageAt: lastMessageAt ?? this.lastMessageAt, avatarTheme: avatarTheme ?? this.avatarTheme, unreadCounterColor: unreadCounterColor ?? this.unreadCounterColor, indicatorIconSize: indicatorIconSize ?? this.indicatorIconSize, ); /// Merge with theme ChannelPreviewTheme merge(ChannelPreviewTheme? other) { if (other == null) return this; return copyWith( title: title?.merge(other.title) ?? other.title, subtitle: subtitle?.merge(other.subtitle) ?? other.subtitle, lastMessageAt: lastMessageAt?.merge(other.lastMessageAt) ?? other.lastMessageAt, avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, unreadCounterColor: other.unreadCounterColor, ); } } /// Theme for [ChannelHeader] class ChannelHeaderTheme { /// Constructor for creating a [ChannelHeaderTheme] const ChannelHeaderTheme({ this.title, this.subtitle, this.avatarTheme, this.color, }); /// Theme for title final TextStyle? title; /// Theme for subtitle final TextStyle? subtitle; /// Theme for avatar final AvatarTheme? avatarTheme; /// Color for [ChannelHeaderTheme] final Color? color; /// Copy with theme ChannelHeaderTheme copyWith({ TextStyle? title, TextStyle? subtitle, AvatarTheme? avatarTheme, Color? color, }) => ChannelHeaderTheme( title: title ?? this.title, subtitle: subtitle ?? this.subtitle, avatarTheme: avatarTheme ?? this.avatarTheme, color: color ?? this.color, ); /// Merge with other [ChannelHeaderTheme] ChannelHeaderTheme merge(ChannelHeaderTheme? other) { if (other == null) return this; return copyWith( title: title?.merge(other.title) ?? other.title, subtitle: subtitle?.merge(other.subtitle) ?? other.subtitle, avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, color: other.color, ); } } /// Theme dedicated to the [ChannelListHeader] class ChannelListHeaderTheme { /// Returns a new [ChannelListHeaderTheme] const ChannelListHeaderTheme({ this.title, this.avatarTheme, this.color, }); /// Style of the title text final TextStyle? title; /// Theme dedicated to the userAvatar final AvatarTheme? avatarTheme; /// Background color of the appbar final Color? color; /// Returns a new [ChannelListHeaderTheme] replacing some of its properties ChannelListHeaderTheme copyWith({ TextStyle? title, AvatarTheme? avatarTheme, Color? color, }) => ChannelListHeaderTheme( title: title ?? this.title, avatarTheme: avatarTheme ?? this.avatarTheme, color: color ?? this.color, ); /// Merges [this] [ChannelListHeaderTheme] with the [other] ChannelListHeaderTheme merge(ChannelListHeaderTheme? other) { if (other == null) return this; return copyWith( title: title?.merge(other.title) ?? other.title, avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, color: other.color, ); } } /// Defines the theme dedicated to the [MessageInput] widget class MessageInputTheme { /// Returns a new [MessageInputTheme] const MessageInputTheme({ this.sendAnimationDuration, this.actionButtonColor, this.sendButtonColor, this.actionButtonIdleColor, this.sendButtonIdleColor, this.inputBackground, this.inputTextStyle, this.inputDecoration, this.activeBorderGradient, this.idleBorderGradient, this.borderRadius, this.expandButtonColor, }); /// Duration of the [MessageInput] send button animation final Duration? sendAnimationDuration; /// Background color of [MessageInput] send button final Color? sendButtonColor; /// Background color of [MessageInput] action buttons final Color? actionButtonColor; /// Background color of [MessageInput] send button final Color? sendButtonIdleColor; /// Background color of [MessageInput] action buttons final Color? actionButtonIdleColor; /// Background color of [MessageInput] expand button final Color? expandButtonColor; /// Background color of [MessageInput] final Color? inputBackground; /// TextStyle of [MessageInput] final TextStyle? inputTextStyle; /// InputDecoration of [MessageInput] final InputDecoration? inputDecoration; /// Border gradient when the [MessageInput] is not focused final Gradient? idleBorderGradient; /// Border gradient when the [MessageInput] is focused final Gradient? activeBorderGradient; /// Border radius of [MessageInput] final BorderRadius? borderRadius; /// Returns a new [MessageInputTheme] replacing some of its properties MessageInputTheme copyWith({ Duration? sendAnimationDuration, Color? inputBackground, Color? actionButtonColor, Color? sendButtonColor, Color? actionButtonIdleColor, Color? sendButtonIdleColor, Color? expandButtonColor, TextStyle? inputTextStyle, InputDecoration? inputDecoration, Gradient? activeBorderGradient, Gradient? idleBorderGradient, BorderRadius? borderRadius, }) => MessageInputTheme( sendAnimationDuration: sendAnimationDuration ?? this.sendAnimationDuration, inputBackground: inputBackground ?? this.inputBackground, actionButtonColor: actionButtonColor ?? this.actionButtonColor, sendButtonColor: sendButtonColor ?? this.sendButtonColor, actionButtonIdleColor: actionButtonIdleColor ?? this.actionButtonIdleColor, expandButtonColor: expandButtonColor ?? this.expandButtonColor, inputTextStyle: inputTextStyle ?? this.inputTextStyle, sendButtonIdleColor: sendButtonIdleColor ?? this.sendButtonIdleColor, inputDecoration: inputDecoration ?? this.inputDecoration, activeBorderGradient: activeBorderGradient ?? this.activeBorderGradient, idleBorderGradient: idleBorderGradient ?? this.idleBorderGradient, borderRadius: borderRadius ?? this.borderRadius, ); /// Merges [this] [MessageInputTheme] with the [other] MessageInputTheme merge(MessageInputTheme? other) { if (other == null) return this; return copyWith( sendAnimationDuration: other.sendAnimationDuration, inputBackground: other.inputBackground, actionButtonColor: other.actionButtonColor, actionButtonIdleColor: other.actionButtonIdleColor, sendButtonColor: other.sendButtonColor, sendButtonIdleColor: other.sendButtonIdleColor, inputTextStyle: inputTextStyle?.merge(other.inputTextStyle) ?? other.inputTextStyle, inputDecoration: inputDecoration?.merge(other.inputDecoration) ?? other.inputDecoration, activeBorderGradient: other.activeBorderGradient, idleBorderGradient: other.idleBorderGradient, borderRadius: other.borderRadius, expandButtonColor: other.expandButtonColor, ); } } /// Effect store class Effect { /// Constructor for creating [Effect] const Effect({ this.sigmaX, this.sigmaY, this.color, this.alpha, this.blur, }); /// final double? sigmaX; /// final double? sigmaY; /// final Color? color; /// final double? alpha; /// final double? blur; /// Copy with new effect Effect copyWith({ double? sigmaX, double? sigmaY, Color? color, double? alpha, double? blur, }) => Effect( sigmaX: sigmaX ?? this.sigmaX, sigmaY: sigmaY ?? this.sigmaY, color: color ?? this.color, alpha: color as double? ?? this.alpha, blur: blur ?? this.blur, ); }