Files
stream-chat-flutter/lib/src/stream_chat_theme.dart
T
2020-05-06 09:46:43 +02:00

488 lines
16 KiB
Dart

import 'package:flutter/material.dart';
import 'package:stream_chat/stream_chat.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/message_input.dart';
/// Inherited widget providing the [StreamChatThemeData] to the widget tree
class StreamChatTheme extends InheritedWidget {
final StreamChatThemeData data;
StreamChatTheme({
Key key,
@required this.data,
Widget child,
}) : super(
key: key,
child: child,
);
@override
bool updateShouldNotify(StreamChatTheme old) {
return data != old.data;
}
/// Use this method to get the current [StreamChatThemeData] instance
static StreamChatThemeData of(BuildContext context) {
return context.dependOnInheritedWidgetOfExactType<StreamChatTheme>().data;
}
}
/// Theme data
class StreamChatThemeData {
/// Primary color of the chat widgets
final Color primaryColor;
/// Secondary color of the chat widgets
final Color secondaryColor;
/// Accent color of the chat widgets
final Color accentColor;
/// Background color of the chat widgets
final Color backgroundColor;
/// Theme of the [ChannelPreview]
final ChannelPreviewTheme channelPreviewTheme;
/// 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;
/// 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;
/// Create a theme from scratch
StreamChatThemeData({
this.primaryColor,
this.secondaryColor,
this.accentColor,
this.backgroundColor,
this.channelPreviewTheme,
this.channelTheme,
this.otherMessageTheme,
this.ownMessageTheme,
this.defaultChannelImage,
this.defaultUserImage,
this.primaryIconTheme,
});
/// Create a theme from a Material [Theme]
factory StreamChatThemeData.fromTheme(ThemeData theme) {
final defaultTheme = getDefaultTheme(theme);
return defaultTheme.copyWith(
accentColor: theme.accentColor,
primaryIconTheme: theme.primaryIconTheme,
primaryColor: theme.colorScheme.primary,
secondaryColor: theme.colorScheme.secondary,
backgroundColor: theme.scaffoldBackgroundColor,
channelTheme: ChannelTheme(
inputGradient: LinearGradient(colors: [
theme.accentColor.withOpacity(.5),
theme.accentColor,
]),
),
ownMessageTheme: MessageTheme(
replies: defaultTheme.ownMessageTheme.replies.copyWith(
color: theme.accentColor,
),
),
otherMessageTheme: MessageTheme(
replies: defaultTheme.ownMessageTheme.replies.copyWith(
color: theme.accentColor,
),
),
);
}
/// Creates a copy of [StreamChatThemeData] with specified attributes overridden.
StreamChatThemeData copyWith({
Color primaryColor,
Color secondaryColor,
Color accentColor,
Color backgroundColor,
ChannelPreviewTheme channelPreviewTheme,
ChannelTheme channelTheme,
MessageTheme ownMessageTheme,
MessageTheme otherMessageTheme,
Widget Function(BuildContext, Channel) defaultChannelImage,
Widget Function(BuildContext, User) defaultUserImage,
IconThemeData primaryIconTheme,
}) =>
StreamChatThemeData(
primaryColor: primaryColor ?? this.primaryColor,
secondaryColor: secondaryColor ?? this.secondaryColor,
primaryIconTheme: primaryIconTheme ?? this.primaryIconTheme,
accentColor: accentColor ?? this.accentColor,
defaultChannelImage: defaultChannelImage ?? this.defaultChannelImage,
defaultUserImage: defaultUserImage ?? this.defaultUserImage,
backgroundColor: backgroundColor ?? this.backgroundColor,
channelPreviewTheme: channelPreviewTheme?.copyWith(
title:
channelPreviewTheme.title ?? this.channelPreviewTheme.title,
subtitle: channelPreviewTheme.subtitle ??
this.channelPreviewTheme.subtitle,
lastMessageAt: channelPreviewTheme.lastMessageAt ??
this.channelPreviewTheme.lastMessageAt,
avatarTheme: channelPreviewTheme.avatarTheme ??
this.channelPreviewTheme.avatarTheme,
) ??
this.channelPreviewTheme,
channelTheme: channelTheme?.copyWith(
channelHeaderTheme: channelTheme.channelHeaderTheme ??
this.channelTheme.channelHeaderTheme,
messageInputButtonIconTheme:
channelTheme.messageInputButtonIconTheme ??
this.channelTheme.messageInputButtonIconTheme,
messageInputButtonTheme: channelTheme.messageInputButtonTheme ??
this.channelTheme.messageInputButtonTheme,
inputGradient:
channelTheme.inputGradient ?? this.channelTheme.inputGradient,
inputBackground: channelTheme.inputBackground ??
this.channelTheme.inputBackground,
) ??
this.channelTheme,
ownMessageTheme: ownMessageTheme?.copyWith(
messageText: ownMessageTheme?.messageText ??
this.ownMessageTheme.messageText,
messageAuthor: ownMessageTheme?.messageAuthor ??
this.ownMessageTheme.messageAuthor,
messageMention: ownMessageTheme?.messageMention ??
this.ownMessageTheme.messageMention,
createdAt:
ownMessageTheme?.createdAt ?? this.ownMessageTheme.createdAt,
replies: ownMessageTheme?.replies ?? this.ownMessageTheme.replies,
messageBackgroundColor: ownMessageTheme?.messageBackgroundColor ??
this.ownMessageTheme.messageBackgroundColor,
avatarTheme: ownMessageTheme?.avatarTheme ??
this.ownMessageTheme.avatarTheme,
) ??
this.ownMessageTheme,
otherMessageTheme: otherMessageTheme?.copyWith(
messageText: otherMessageTheme?.messageText ??
this.otherMessageTheme.messageText,
messageAuthor: otherMessageTheme?.messageAuthor ??
this.otherMessageTheme.messageAuthor,
messageMention: otherMessageTheme?.messageMention ??
this.otherMessageTheme.messageMention,
createdAt: otherMessageTheme?.createdAt ??
this.otherMessageTheme.createdAt,
replies:
otherMessageTheme?.replies ?? this.otherMessageTheme.replies,
messageBackgroundColor:
otherMessageTheme?.messageBackgroundColor ??
this.otherMessageTheme.messageBackgroundColor,
avatarTheme: otherMessageTheme?.avatarTheme ??
this.otherMessageTheme.avatarTheme,
) ??
this.otherMessageTheme,
);
/// Get the default Stream Chat theme
static StreamChatThemeData getDefaultTheme(ThemeData theme) {
final accentColor = Color(0xff006cff);
final isDark = theme.brightness == Brightness.dark;
return StreamChatThemeData(
accentColor: accentColor,
primaryColor: isDark ? Colors.black : Colors.white,
primaryIconTheme:
IconThemeData(color: isDark ? Colors.white : Colors.black),
defaultChannelImage: (context, channel) => SizedBox(),
backgroundColor: isDark ? Colors.black : Colors.white,
defaultUserImage: (context, user) => Center(
child: Text(
user.name?.substring(0, 1) ?? '',
style: TextStyle(color: Colors.white),
),
),
channelPreviewTheme: ChannelPreviewTheme(
unreadCounterColor: Color(0xffd0021B),
avatarTheme: AvatarTheme(
borderRadius: BorderRadius.circular(20),
constraints: BoxConstraints.tightFor(
height: 40,
width: 40,
),
),
title: TextStyle(
fontSize: 14,
color: isDark ? Colors.white : Colors.black,
),
subtitle: TextStyle(
fontSize: 13,
color: isDark ? Colors.white : Colors.black,
),
lastMessageAt: TextStyle(
fontSize: 11,
color: isDark
? Colors.white.withOpacity(.5)
: Colors.black.withOpacity(.5),
),
),
channelTheme: ChannelTheme(
messageInputButtonIconTheme: theme.iconTheme.copyWith(
color: accentColor,
),
channelHeaderTheme: ChannelHeaderTheme(
avatarTheme: AvatarTheme(
borderRadius: BorderRadius.circular(20),
constraints: BoxConstraints.tightFor(
height: 40,
width: 40,
),
),
color: isDark ? Colors.black : Colors.white,
title: TextStyle(
fontSize: 14,
color: isDark ? Colors.white : Colors.black,
),
lastMessageAt: TextStyle(
fontSize: 11,
color: isDark
? Colors.white.withOpacity(.5)
: Colors.black.withOpacity(.5),
),
),
inputBackground:
isDark ? Colors.black.withAlpha(12) : Colors.white.withAlpha(12),
inputGradient: LinearGradient(colors: [
Color(0xFF00AEFF),
Color(0xFF0076FF),
]),
),
ownMessageTheme: MessageTheme(
messageText: TextStyle(
fontSize: 15,
color: isDark ? Colors.white : Colors.black,
),
createdAt: TextStyle(
color: isDark
? Colors.white.withOpacity(.5)
: Colors.black.withOpacity(.5),
fontSize: 11,
),
replies: TextStyle(
color: accentColor,
fontWeight: FontWeight.bold,
fontSize: 12,
),
messageBackgroundColor: Color(0x33ebebeb),
avatarTheme: AvatarTheme(
borderRadius: BorderRadius.circular(20),
constraints: BoxConstraints.tightFor(
height: 32,
width: 32,
),
),
),
otherMessageTheme: MessageTheme(
messageText: TextStyle(
fontSize: 15,
color: isDark ? Colors.white : Colors.black,
),
createdAt: TextStyle(
color: isDark
? Colors.white.withOpacity(.5)
: Colors.black.withOpacity(.5),
fontSize: 11,
),
replies: TextStyle(
color: accentColor,
fontWeight: FontWeight.bold,
fontSize: 12,
),
messageBackgroundColor: isDark ? Colors.black : Colors.white,
avatarTheme: AvatarTheme(
borderRadius: BorderRadius.circular(20),
constraints: BoxConstraints.tightFor(
height: 32,
width: 32,
),
),
),
);
}
}
/// Channel theme data
class ChannelTheme {
/// Theme of the [ChannelHeader] widget
final ChannelHeaderTheme channelHeaderTheme;
/// IconTheme of the send button in [MessageInput]
final IconThemeData messageInputButtonIconTheme;
/// Theme of the send button in [MessageInput]
final ButtonThemeData messageInputButtonTheme;
/// Gradient of [MessageInput]
final Gradient inputGradient;
/// Background color of [MessageInput]
final Color inputBackground;
ChannelTheme({
this.channelHeaderTheme,
this.messageInputButtonIconTheme,
this.messageInputButtonTheme,
this.inputBackground,
this.inputGradient,
});
/// Creates a copy of [ChannelTheme] with specified attributes overridden.
ChannelTheme copyWith({
ChannelHeaderTheme channelHeaderTheme,
IconThemeData messageInputButtonIconTheme,
ButtonThemeData messageInputButtonTheme,
Gradient inputGradient,
Color inputBackground,
}) =>
ChannelTheme(
channelHeaderTheme: channelHeaderTheme?.copyWith(
title: channelHeaderTheme?.title ?? this.channelHeaderTheme.title,
lastMessageAt: channelHeaderTheme?.lastMessageAt ??
this.channelHeaderTheme.lastMessageAt,
avatarTheme: channelHeaderTheme?.avatarTheme ??
this.channelHeaderTheme.avatarTheme,
color: channelHeaderTheme?.color ?? this.channelHeaderTheme.color,
) ??
this.channelHeaderTheme,
messageInputButtonIconTheme:
messageInputButtonIconTheme ?? this.messageInputButtonIconTheme,
messageInputButtonTheme:
messageInputButtonTheme ?? this.messageInputButtonTheme,
inputGradient: inputGradient ?? this.inputGradient,
inputBackground: inputBackground ?? this.inputBackground,
);
}
class AvatarTheme {
final BoxConstraints constraints;
final BorderRadius borderRadius;
AvatarTheme({
this.constraints,
this.borderRadius,
});
AvatarTheme copyWith({
BoxConstraints constraints,
BorderRadius borderRadius,
}) =>
AvatarTheme(
constraints: constraints ?? this.constraints,
borderRadius: borderRadius ?? this.borderRadius,
);
}
class MessageTheme {
final TextStyle messageText;
final TextStyle messageAuthor;
final TextStyle messageMention;
final TextStyle createdAt;
final TextStyle replies;
final Color messageBackgroundColor;
final AvatarTheme avatarTheme;
const MessageTheme({
this.replies,
this.messageText,
this.messageAuthor,
this.messageMention,
this.messageBackgroundColor,
this.avatarTheme,
this.createdAt,
});
MessageTheme copyWith({
TextStyle messageText,
TextStyle messageAuthor,
TextStyle messageMention,
TextStyle createdAt,
TextStyle replies,
Color messageBackgroundColor,
Color otherMessageBackgroundColor,
AvatarTheme avatarTheme,
}) =>
MessageTheme(
messageText: messageText ?? this.messageText,
messageAuthor: messageAuthor ?? this.messageAuthor,
messageMention: messageMention ?? this.messageMention,
createdAt: createdAt ?? this.createdAt,
messageBackgroundColor:
messageBackgroundColor ?? this.messageBackgroundColor,
avatarTheme: avatarTheme ?? this.avatarTheme,
replies: replies ?? this.replies,
);
}
class ChannelPreviewTheme {
final TextStyle title;
final TextStyle subtitle;
final TextStyle lastMessageAt;
final AvatarTheme avatarTheme;
final Color unreadCounterColor;
const ChannelPreviewTheme({
this.title,
this.subtitle,
this.lastMessageAt,
this.avatarTheme,
this.unreadCounterColor,
});
ChannelPreviewTheme copyWith({
TextStyle title,
TextStyle subtitle,
TextStyle lastMessageAt,
AvatarTheme avatarTheme,
Color unreadCounterColor,
}) =>
ChannelPreviewTheme(
title: title ?? this.title,
subtitle: subtitle ?? this.subtitle,
lastMessageAt: lastMessageAt ?? this.lastMessageAt,
avatarTheme: avatarTheme ?? this.avatarTheme,
unreadCounterColor: unreadCounterColor ?? this.unreadCounterColor,
);
}
class ChannelHeaderTheme {
final TextStyle title;
final TextStyle lastMessageAt;
final AvatarTheme avatarTheme;
final Color color;
const ChannelHeaderTheme({
this.title,
this.lastMessageAt,
this.avatarTheme,
this.color,
});
ChannelHeaderTheme copyWith({
TextStyle title,
TextStyle lastMessageAt,
AvatarTheme avatarTheme,
Color color,
}) =>
ChannelHeaderTheme(
title: title ?? this.title,
lastMessageAt: lastMessageAt ?? this.lastMessageAt,
avatarTheme: avatarTheme ?? this.avatarTheme,
color: color ?? this.color,
);
}