Files
stream-chat-flutter/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart
T

1244 lines
37 KiB
Dart

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<StreamChatTheme>();
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<ReactionIcon>? 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<ReactionIcon> 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<ReactionIcon>? 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,
);
}