Merge pull request #601 from GetStream/cds-362
This commit is contained in:
@@ -1,3 +1,21 @@
|
||||
## Upcoming
|
||||
|
||||
🔄 Changed
|
||||
|
||||
Theming has been upgraded! Most theme classes now have `InheritedTheme` classes
|
||||
associated with them, and have been upgraded with some goodies like `lerp` functions.
|
||||
Here's the full naming breakdown:
|
||||
* `AvatarTheme` is now `AvatarThemeData`
|
||||
* `ChannelHeaderTheme` is now `ChannelHeaderThemeData`
|
||||
* `ChannelListHeaderTheme` is now `ChannelListHeaderThemeData`
|
||||
* `ChannelListViewTheme` is now `ChannelListViewThemeData`
|
||||
* `ChannelPreviewTheme` is now `ChannelPreviewThemeData`
|
||||
* `MessageInputTheme` is now `MessageInputThemeData`
|
||||
* `MessageListViewTheme` is now `MessageListViewTheme`
|
||||
* `MessageSearchListViewTheme` is now `MessageSearchListViewThemeData`
|
||||
* `MessageTheme` is now `MessageThemeData`
|
||||
* `UserListViewTheme` is now `UserListViewThemeData`
|
||||
|
||||
## 2.1.2
|
||||
|
||||
🐞 Fixed
|
||||
@@ -531,6 +549,7 @@ Widget build(BuildContext context) {
|
||||
},
|
||||
home: ChannelListPage(),
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
- Fix reaction bubble going below previous message on iOS
|
||||
|
||||
@@ -118,13 +118,12 @@ class ChannelListPage extends StatelessWidget {
|
||||
channel: channel,
|
||||
),
|
||||
title: ChannelName(
|
||||
textStyle:
|
||||
StreamChatTheme.of(context).channelPreviewTheme.title!.copyWith(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.textHighEmphasis
|
||||
.withOpacity(opacity),
|
||||
),
|
||||
textStyle: ChannelPreviewTheme.of(context).titleStyle!.copyWith(
|
||||
color: StreamChatTheme.of(context)
|
||||
.colorTheme
|
||||
.textHighEmphasis
|
||||
.withOpacity(opacity),
|
||||
),
|
||||
),
|
||||
subtitle: Text(subtitle),
|
||||
trailing: channel.state!.unreadCount > 0
|
||||
|
||||
@@ -58,17 +58,17 @@ class MyApp extends StatelessWidget {
|
||||
final defaultTheme = StreamChatThemeData.fromTheme(themeData);
|
||||
final colorTheme = defaultTheme.colorTheme;
|
||||
final customTheme = defaultTheme.merge(StreamChatThemeData(
|
||||
channelPreviewTheme: ChannelPreviewTheme(
|
||||
avatarTheme: AvatarTheme(
|
||||
channelPreviewTheme: ChannelPreviewThemeData(
|
||||
avatarTheme: AvatarThemeData(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
otherMessageTheme: MessageTheme(
|
||||
otherMessageTheme: MessageThemeData(
|
||||
messageBackgroundColor: colorTheme.textHighEmphasis,
|
||||
messageText: TextStyle(
|
||||
messageTextStyle: TextStyle(
|
||||
color: colorTheme.barsBg,
|
||||
),
|
||||
avatarTheme: AvatarTheme(
|
||||
avatarTheme: AvatarThemeData(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/src/theme/themes.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||
|
||||
@@ -12,7 +13,7 @@ class AttachmentTitle extends StatelessWidget {
|
||||
}) : super(key: key);
|
||||
|
||||
/// Theme to apply to text
|
||||
final MessageTheme messageTheme;
|
||||
final MessageThemeData messageTheme;
|
||||
|
||||
/// Attachment data to display
|
||||
final Attachment attachment;
|
||||
@@ -34,7 +35,7 @@ class AttachmentTitle extends StatelessWidget {
|
||||
Text(
|
||||
attachment.title!,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: messageTheme.messageText?.copyWith(
|
||||
style: messageTheme.messageTextStyle?.copyWith(
|
||||
color: StreamChatTheme.of(context).colorTheme.accentPrimary,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
@@ -50,7 +51,7 @@ class AttachmentTitle extends StatelessWidget {
|
||||
.toList()
|
||||
.reversed
|
||||
.join('.'),
|
||||
style: messageTheme.messageText,
|
||||
style: messageTheme.messageTextStyle,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:shimmer/shimmer.dart';
|
||||
import 'package:stream_chat_flutter/src/attachment/attachment_title.dart';
|
||||
import 'package:stream_chat_flutter/src/attachment/attachment_upload_state_builder.dart';
|
||||
import 'package:stream_chat_flutter/src/attachment/attachment_widget.dart';
|
||||
import 'package:stream_chat_flutter/src/theme/themes.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||
|
||||
@@ -27,8 +28,8 @@ class ImageAttachment extends AttachmentWidget {
|
||||
size: size,
|
||||
);
|
||||
|
||||
/// [MessageTheme] for showing image title
|
||||
final MessageTheme messageTheme;
|
||||
/// [MessageThemeData] for showing image title
|
||||
final MessageThemeData messageTheme;
|
||||
|
||||
/// Flag for showing title
|
||||
final bool showTitle;
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/src/attachment/attachment_title.dart';
|
||||
import 'package:stream_chat_flutter/src/attachment/attachment_widget.dart';
|
||||
import 'package:stream_chat_flutter/src/full_screen_media.dart';
|
||||
import 'package:stream_chat_flutter/src/theme/themes.dart';
|
||||
import 'package:stream_chat_flutter/src/video_thumbnail_image.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
@@ -24,8 +25,8 @@ class VideoAttachment extends AttachmentWidget {
|
||||
size: size,
|
||||
);
|
||||
|
||||
/// [MessageTheme] for showing title
|
||||
final MessageTheme messageTheme;
|
||||
/// [MessageThemeData] for showing title
|
||||
final MessageThemeData messageTheme;
|
||||
|
||||
/// Callback when show message is tapped
|
||||
final ShowMessageCallback? onShowMessage;
|
||||
|
||||
@@ -19,6 +19,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
||||
bool _showActions = true;
|
||||
|
||||
late StreamChannelState _streamChannelState;
|
||||
late ChannelPreviewThemeData _channelPreviewThemeData;
|
||||
late StreamChatThemeData _streamChatThemeData;
|
||||
late StreamChatState _streamChatState;
|
||||
|
||||
@@ -64,8 +65,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
||||
child: ChannelInfo(
|
||||
showTypingIndicator: false,
|
||||
channel: _streamChannelState.channel,
|
||||
textStyle:
|
||||
_streamChatThemeData.channelPreviewTheme.subtitle,
|
||||
textStyle: _channelPreviewThemeData.subtitleStyle,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
@@ -213,6 +213,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
||||
void didChangeDependencies() {
|
||||
_streamChannelState = StreamChannel.of(context);
|
||||
_streamChatThemeData = StreamChatTheme.of(context);
|
||||
_channelPreviewThemeData = ChannelPreviewTheme.of(context);
|
||||
_streamChatState = StreamChat.of(context);
|
||||
super.didChangeDependencies();
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final channel = StreamChannel.of(context).channel;
|
||||
final chatThemeData = StreamChatTheme.of(context);
|
||||
final channelHeaderTheme = ChannelHeaderTheme.of(context);
|
||||
|
||||
final leadingWidget = leading ??
|
||||
(showBackButton
|
||||
@@ -141,18 +141,17 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
brightness: Theme.of(context).brightness,
|
||||
elevation: 1,
|
||||
leading: leadingWidget,
|
||||
backgroundColor:
|
||||
chatThemeData.channelTheme.channelHeaderTheme.color,
|
||||
backgroundColor: channelHeaderTheme.color,
|
||||
actions: actions ??
|
||||
<Widget>[
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 10),
|
||||
child: Center(
|
||||
child: ChannelAvatar(
|
||||
borderRadius: chatThemeData.channelTheme
|
||||
.channelHeaderTheme.avatarTheme?.borderRadius,
|
||||
constraints: chatThemeData.channelTheme
|
||||
.channelHeaderTheme.avatarTheme?.constraints,
|
||||
borderRadius:
|
||||
channelHeaderTheme.avatarTheme?.borderRadius,
|
||||
constraints:
|
||||
channelHeaderTheme.avatarTheme?.constraints,
|
||||
onTap: onImageTap,
|
||||
),
|
||||
),
|
||||
@@ -169,16 +168,14 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
children: <Widget>[
|
||||
title ??
|
||||
ChannelName(
|
||||
textStyle: chatThemeData
|
||||
.channelTheme.channelHeaderTheme.title,
|
||||
textStyle: channelHeaderTheme.titleStyle,
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
subtitle ??
|
||||
ChannelInfo(
|
||||
showTypingIndicator: showTypingIndicator,
|
||||
channel: channel,
|
||||
textStyle: chatThemeData
|
||||
.channelTheme.channelHeaderTheme.subtitle,
|
||||
textStyle: channelHeaderTheme.subtitleStyle,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -65,10 +65,7 @@ class ChannelInfo extends StatelessWidget {
|
||||
}
|
||||
alternativeWidget = Text(
|
||||
text,
|
||||
style: StreamChatTheme.of(context)
|
||||
.channelTheme
|
||||
.channelHeaderTheme
|
||||
.subtitle,
|
||||
style: ChannelHeaderTheme.of(context).subtitleStyle,
|
||||
);
|
||||
} else {
|
||||
final userId = StreamChat.of(context).currentUser?.id;
|
||||
|
||||
@@ -2,10 +2,10 @@ import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:stream_chat_flutter/src/extension.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_neumorphic_button.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';
|
||||
|
||||
/// Widget builder for title
|
||||
typedef TitleBuilder = Widget Function(
|
||||
@@ -46,7 +46,7 @@ typedef TitleBuilder = Widget Function(
|
||||
/// if you don't have it in the widget tree.
|
||||
///
|
||||
/// The widget components render the ui based on the first ancestor of type
|
||||
/// [StreamChatTheme] and on its [ChannelListHeaderTheme] property.
|
||||
/// [StreamChatTheme] and on its [ChannelListHeaderThemeData] property.
|
||||
/// Modify it to change the widget appearance.
|
||||
class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
/// Instantiates a ChannelListHeader
|
||||
@@ -116,6 +116,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
}
|
||||
|
||||
final chatThemeData = StreamChatTheme.of(context);
|
||||
final channelListHeaderThemeData = ChannelListHeaderTheme.of(context);
|
||||
return InfoTile(
|
||||
showMessage: showConnectionStateTile && showStatus,
|
||||
message: statusString,
|
||||
@@ -123,7 +124,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
textTheme: Theme.of(context).textTheme,
|
||||
brightness: Theme.of(context).brightness,
|
||||
elevation: 1,
|
||||
backgroundColor: chatThemeData.channelListHeaderTheme.color,
|
||||
backgroundColor: channelListHeaderThemeData.color,
|
||||
centerTitle: true,
|
||||
leading: leading ??
|
||||
Center(
|
||||
@@ -138,10 +139,10 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
}
|
||||
Scaffold.of(context).openDrawer();
|
||||
},
|
||||
borderRadius: chatThemeData
|
||||
.channelListHeaderTheme.avatarTheme?.borderRadius,
|
||||
constraints: chatThemeData
|
||||
.channelListHeaderTheme.avatarTheme?.constraints,
|
||||
borderRadius: channelListHeaderThemeData
|
||||
.avatarTheme?.borderRadius,
|
||||
constraints: channelListHeaderThemeData
|
||||
.avatarTheme?.constraints,
|
||||
)
|
||||
: const Offstage(),
|
||||
),
|
||||
@@ -227,10 +228,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
const SizedBox(width: 10),
|
||||
Text(
|
||||
context.translations.searchingForNetworkText,
|
||||
style: StreamChatTheme.of(context)
|
||||
.channelListHeaderTheme
|
||||
.title
|
||||
?.copyWith(
|
||||
style: ChannelListHeaderTheme.of(context).titleStyle?.copyWith(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
@@ -243,12 +241,13 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
StreamChatClient client,
|
||||
) {
|
||||
final chatThemeData = StreamChatTheme.of(context);
|
||||
final channelListHeaderTheme = ChannelListHeaderTheme.of(context);
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
context.translations.offlineLabel,
|
||||
style: chatThemeData.channelListHeaderTheme.title?.copyWith(
|
||||
style: channelListHeaderTheme.titleStyle?.copyWith(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
@@ -259,7 +258,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
..openConnection(),
|
||||
child: Text(
|
||||
context.translations.tryAgainLabel,
|
||||
style: chatThemeData.channelListHeaderTheme.title?.copyWith(
|
||||
style: channelListHeaderTheme.titleStyle?.copyWith(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: chatThemeData.colorTheme.accentPrimary,
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:flutter_slidable/flutter_slidable.dart';
|
||||
import 'package:shimmer/shimmer.dart';
|
||||
import 'package:stream_chat_flutter/src/channel_bottom_sheet.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_svg_icon.dart';
|
||||
import 'package:stream_chat_flutter/src/theme/themes.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';
|
||||
|
||||
@@ -3,10 +3,10 @@ import 'package:collection/collection.dart'
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:jiffy/jiffy.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';
|
||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||
import 'package:stream_chat_flutter/src/extension.dart';
|
||||
|
||||
/// 
|
||||
/// 
|
||||
@@ -69,7 +69,7 @@ class ChannelPreview extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final channelPreviewTheme = StreamChatTheme.of(context).channelPreviewTheme;
|
||||
final channelPreviewTheme = ChannelPreviewTheme.of(context);
|
||||
final streamChatState = StreamChat.of(context);
|
||||
return BetterStreamBuilder<bool>(
|
||||
stream: channel.isMutedStream,
|
||||
@@ -91,7 +91,7 @@ class ChannelPreview extends StatelessWidget {
|
||||
Flexible(
|
||||
child: title ??
|
||||
ChannelName(
|
||||
textStyle: channelPreviewTheme.title,
|
||||
textStyle: channelPreviewTheme.titleStyle,
|
||||
),
|
||||
),
|
||||
BetterStreamBuilder<List<Member>?>(
|
||||
@@ -183,14 +183,13 @@ class ChannelPreview extends StatelessWidget {
|
||||
|
||||
return Text(
|
||||
stringDate,
|
||||
style:
|
||||
StreamChatTheme.of(context).channelPreviewTheme.lastMessageAt,
|
||||
style: ChannelPreviewTheme.of(context).lastMessageAtStyle,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
Widget _buildSubtitle(BuildContext context) {
|
||||
final chatThemeData = StreamChatTheme.of(context);
|
||||
final channelPreviewTheme = ChannelPreviewTheme.of(context);
|
||||
if (channel.isMuted) {
|
||||
return Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
@@ -200,7 +199,7 @@ class ChannelPreview extends StatelessWidget {
|
||||
),
|
||||
Text(
|
||||
' ${context.translations.channelIsMutedText}',
|
||||
style: chatThemeData.channelPreviewTheme.subtitle,
|
||||
style: channelPreviewTheme.subtitleStyle,
|
||||
),
|
||||
],
|
||||
);
|
||||
@@ -208,7 +207,7 @@ class ChannelPreview extends StatelessWidget {
|
||||
return TypingIndicator(
|
||||
channel: channel,
|
||||
alternativeWidget: _buildLastMessage(context),
|
||||
style: chatThemeData.channelPreviewTheme.subtitle,
|
||||
style: channelPreviewTheme.subtitleStyle,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -243,19 +242,19 @@ class ChannelPreview extends StatelessWidget {
|
||||
|
||||
text = parts.join(' ');
|
||||
|
||||
final chatThemeData = StreamChatTheme.of(context);
|
||||
final channelPreviewTheme = ChannelPreviewTheme.of(context);
|
||||
return Text.rich(
|
||||
_getDisplayText(
|
||||
text,
|
||||
lastMessage.mentionedUsers,
|
||||
lastMessage.attachments,
|
||||
chatThemeData.channelPreviewTheme.subtitle?.copyWith(
|
||||
color: chatThemeData.channelPreviewTheme.subtitle?.color,
|
||||
channelPreviewTheme.subtitleStyle?.copyWith(
|
||||
color: channelPreviewTheme.subtitleStyle?.color,
|
||||
fontStyle: (lastMessage.isSystem || lastMessage.isDeleted)
|
||||
? FontStyle.italic
|
||||
: FontStyle.normal),
|
||||
chatThemeData.channelPreviewTheme.subtitle?.copyWith(
|
||||
color: chatThemeData.channelPreviewTheme.subtitle?.color,
|
||||
channelPreviewTheme.subtitleStyle?.copyWith(
|
||||
color: channelPreviewTheme.subtitleStyle?.color,
|
||||
fontStyle: (lastMessage.isSystem || lastMessage.isDeleted)
|
||||
? FontStyle.italic
|
||||
: FontStyle.normal,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||
import 'package:stream_chat_flutter/src/extension.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||
import 'package:stream_chat_flutter/src/theme/themes.dart';
|
||||
|
||||
/// Widget to display deleted message
|
||||
class DeletedMessage extends StatelessWidget {
|
||||
@@ -15,7 +16,7 @@ class DeletedMessage extends StatelessWidget {
|
||||
}) : super(key: key);
|
||||
|
||||
/// The theme of the message
|
||||
final MessageTheme messageTheme;
|
||||
final MessageThemeData messageTheme;
|
||||
|
||||
/// The border radius of the message text
|
||||
final BorderRadiusGeometry? borderRadiusGeometry;
|
||||
@@ -51,9 +52,9 @@ class DeletedMessage extends StatelessWidget {
|
||||
),
|
||||
child: Text(
|
||||
context.translations.messageDeletedLabel,
|
||||
style: messageTheme.messageText?.copyWith(
|
||||
style: messageTheme.messageTextStyle?.copyWith(
|
||||
fontStyle: FontStyle.italic,
|
||||
color: messageTheme.createdAt?.color,
|
||||
color: messageTheme.createdAtStyle?.color,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -124,10 +124,7 @@ class _FullScreenMediaState extends State<FullScreenMedia>
|
||||
),
|
||||
backgroundDecoration: BoxDecoration(
|
||||
color: ColorTween(
|
||||
begin: StreamChatTheme.of(context)
|
||||
.channelTheme
|
||||
.channelHeaderTheme
|
||||
.color,
|
||||
begin: ChannelHeaderTheme.of(context).color,
|
||||
end: Colors.black,
|
||||
).lerp(_controller.value),
|
||||
),
|
||||
|
||||
@@ -8,6 +8,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||
import 'package:stream_chat_flutter/src/theme/themes.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';
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/src/attachment_actions_modal.dart';
|
||||
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/theme/themes.dart';
|
||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||
|
||||
/// Header/AppBar widget for media display screen
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/src/full_screen_media.dart';
|
||||
import 'package:stream_chat_flutter/src/theme/themes.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||
|
||||
@@ -25,8 +26,8 @@ class ImageGroup extends StatelessWidget {
|
||||
/// Message which images are attached to
|
||||
final Message message;
|
||||
|
||||
/// [MessageTheme] to apply to message
|
||||
final MessageTheme messageTheme;
|
||||
/// [MessageThemeData] to apply to message
|
||||
final MessageThemeData messageTheme;
|
||||
|
||||
/// Size of iamges
|
||||
final Size size;
|
||||
|
||||
@@ -6,6 +6,7 @@ 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/theme/themes.dart';
|
||||
import 'package:stream_chat_flutter/src/utils.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
@@ -49,8 +50,8 @@ class MessageActionsModal extends StatefulWidget {
|
||||
/// Message in focus for actions
|
||||
final Message message;
|
||||
|
||||
/// [MessageTheme] for message
|
||||
final MessageTheme messageTheme;
|
||||
/// [MessageThemeData] for message
|
||||
final MessageThemeData messageTheme;
|
||||
|
||||
/// Flag for showing reactions
|
||||
final bool showReactions;
|
||||
@@ -116,7 +117,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
}
|
||||
}
|
||||
final roughSentenceSize = messageTextLength *
|
||||
(widget.messageTheme.messageText?.fontSize ?? 1) *
|
||||
(widget.messageTheme.messageTextStyle?.fontSize ?? 1) *
|
||||
1.2;
|
||||
final divFactor = widget.message.attachments.isNotEmpty == true
|
||||
? 1
|
||||
@@ -565,7 +566,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
||||
elevation: 2,
|
||||
clipBehavior: Clip.hardEdge,
|
||||
isScrollControlled: true,
|
||||
backgroundColor: streamChatThemeData.messageInputTheme.inputBackground,
|
||||
backgroundColor: MessageInputTheme.of(context).inputBackgroundColor,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(16),
|
||||
|
||||
@@ -288,6 +288,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
late final TextEditingController textEditingController;
|
||||
|
||||
late StreamChatThemeData _streamChatTheme;
|
||||
late MessageInputThemeData _messageInputTheme;
|
||||
|
||||
bool get _hasQuotedMessage => widget.quotedMessage != null;
|
||||
|
||||
@@ -328,7 +329,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
Widget build(BuildContext context) {
|
||||
Widget child = DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
color: _streamChatTheme.messageInputTheme.inputBackground,
|
||||
color: _messageInputTheme.inputBackgroundColor,
|
||||
),
|
||||
child: SafeArea(
|
||||
child: GestureDetector(
|
||||
@@ -484,7 +485,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
: CrossFadeState.showSecond,
|
||||
firstChild: sendButton,
|
||||
secondChild: widget.idleSendButton ?? _buildIdleSendButton(context),
|
||||
duration: _streamChatTheme.messageInputTheme.sendAnimationDuration!,
|
||||
duration: _messageInputTheme.sendAnimationDuration!,
|
||||
alignment: Alignment.center,
|
||||
);
|
||||
}
|
||||
@@ -509,7 +510,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
? pi
|
||||
: 0,
|
||||
child: StreamSvgIcon.emptyCircleLeft(
|
||||
color: _streamChatTheme.messageInputTheme.expandButtonColor,
|
||||
color: _messageInputTheme.expandButtonColor,
|
||||
),
|
||||
),
|
||||
padding: const EdgeInsets.all(0),
|
||||
@@ -555,17 +556,17 @@ class MessageInputState extends State<MessageInput> {
|
||||
clipBehavior: Clip.hardEdge,
|
||||
margin: margin,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: _streamChatTheme.messageInputTheme.borderRadius,
|
||||
borderRadius: _messageInputTheme.borderRadius,
|
||||
gradient: _focusNode.hasFocus
|
||||
? _streamChatTheme.messageInputTheme.activeBorderGradient
|
||||
: _streamChatTheme.messageInputTheme.idleBorderGradient,
|
||||
? _messageInputTheme.activeBorderGradient
|
||||
: _messageInputTheme.idleBorderGradient,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(1.5),
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: _streamChatTheme.messageInputTheme.borderRadius,
|
||||
color: _streamChatTheme.messageInputTheme.inputBackground,
|
||||
borderRadius: _messageInputTheme.borderRadius,
|
||||
color: _messageInputTheme.inputBackgroundColor,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@@ -583,7 +584,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
keyboardType: widget.keyboardType,
|
||||
controller: textEditingController,
|
||||
focusNode: _focusNode,
|
||||
style: _streamChatTheme.messageInputTheme.inputTextStyle,
|
||||
style: _messageInputTheme.inputTextStyle,
|
||||
autofocus: widget.autofocus,
|
||||
textAlignVertical: TextAlignVertical.center,
|
||||
decoration: _getInputDecoration(context),
|
||||
@@ -599,11 +600,11 @@ class MessageInputState extends State<MessageInput> {
|
||||
}
|
||||
|
||||
InputDecoration _getInputDecoration(BuildContext context) {
|
||||
final passedDecoration = _streamChatTheme.messageInputTheme.inputDecoration;
|
||||
final passedDecoration = _messageInputTheme.inputDecoration;
|
||||
return InputDecoration(
|
||||
isDense: true,
|
||||
hintText: _getHint(context),
|
||||
hintStyle: _streamChatTheme.messageInputTheme.inputTextStyle!.copyWith(
|
||||
hintStyle: _messageInputTheme.inputTextStyle!.copyWith(
|
||||
color: _streamChatTheme.colorTheme.textLowEmphasis,
|
||||
),
|
||||
border: const OutlineInputBorder(
|
||||
@@ -1688,8 +1689,8 @@ class MessageInputState extends State<MessageInput> {
|
||||
color: s.isNotEmpty
|
||||
? _streamChatTheme.colorTheme.disabled
|
||||
: (_commandsOverlay != null
|
||||
? _streamChatTheme.messageInputTheme.actionButtonColor
|
||||
: _streamChatTheme.messageInputTheme.actionButtonIdleColor),
|
||||
? _messageInputTheme.actionButtonColor
|
||||
: _messageInputTheme.actionButtonIdleColor),
|
||||
),
|
||||
padding: const EdgeInsets.all(0),
|
||||
constraints: const BoxConstraints.tightFor(
|
||||
@@ -1726,8 +1727,8 @@ class MessageInputState extends State<MessageInput> {
|
||||
Widget _buildAttachmentButton() => IconButton(
|
||||
icon: StreamSvgIcon.attach(
|
||||
color: _openFilePickerSection
|
||||
? _streamChatTheme.messageInputTheme.actionButtonColor
|
||||
: _streamChatTheme.messageInputTheme.actionButtonIdleColor,
|
||||
? _messageInputTheme.actionButtonColor
|
||||
: _messageInputTheme.actionButtonIdleColor,
|
||||
),
|
||||
padding: const EdgeInsets.all(0),
|
||||
constraints: const BoxConstraints.tightFor(
|
||||
@@ -1963,7 +1964,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
padding: const EdgeInsets.all(8),
|
||||
child: StreamSvgIcon(
|
||||
assetName: _getIdleSendIcon(),
|
||||
color: _streamChatTheme.messageInputTheme.sendButtonIdleColor,
|
||||
color: _messageInputTheme.sendButtonIdleColor,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -1979,7 +1980,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
),
|
||||
icon: StreamSvgIcon(
|
||||
assetName: _getSendIcon(),
|
||||
color: _streamChatTheme.messageInputTheme.sendButtonColor,
|
||||
color: _messageInputTheme.sendButtonColor,
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -2186,6 +2187,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
@override
|
||||
void didChangeDependencies() {
|
||||
_streamChatTheme = StreamChatTheme.of(context);
|
||||
_messageInputTheme = MessageInputTheme.of(context);
|
||||
if (widget.editMessage != null && !_initialized) {
|
||||
FocusScope.of(context).requestFocus(_focusNode);
|
||||
_initialized = true;
|
||||
|
||||
@@ -14,6 +14,7 @@ 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/src/theme/themes.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';
|
||||
@@ -628,7 +629,7 @@ class _MessageListViewState extends State<MessageListView> {
|
||||
child: Text(
|
||||
context.translations.threadSeparatorText(replyCount),
|
||||
textAlign: TextAlign.center,
|
||||
style: _streamTheme.channelTheme.channelHeaderTheme.subtitle,
|
||||
style: ChannelHeaderTheme.of(context).subtitleStyle,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -4,6 +4,7 @@ import 'package:flutter/material.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/theme/themes.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';
|
||||
@@ -28,8 +29,8 @@ class MessageReactionsModal extends StatelessWidget {
|
||||
/// Message to display reactions of
|
||||
final Message message;
|
||||
|
||||
/// [MessageTheme] to apply to [message]
|
||||
final MessageTheme messageTheme;
|
||||
/// [MessageThemeData] to apply to [message]
|
||||
final MessageThemeData messageTheme;
|
||||
|
||||
/// Flag to reverse message
|
||||
final bool reverse;
|
||||
@@ -56,8 +57,9 @@ class MessageReactionsModal extends StatelessWidget {
|
||||
messageTextLength = quotedMessageLength;
|
||||
}
|
||||
}
|
||||
final roughSentenceSize =
|
||||
messageTextLength * (messageTheme.messageText?.fontSize ?? 1) * 1.2;
|
||||
final roughSentenceSize = messageTextLength *
|
||||
(messageTheme.messageTextStyle?.fontSize ?? 1) *
|
||||
1.2;
|
||||
final divFactor = message.attachments.isNotEmpty == true
|
||||
? 1
|
||||
: (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize));
|
||||
|
||||
@@ -36,7 +36,7 @@ class MessageSearchItem extends StatelessWidget {
|
||||
final channel = getMessageResponse.channel;
|
||||
final channelName = channel?.extraData['name'];
|
||||
final user = message.user!;
|
||||
final chatThemeData = StreamChatTheme.of(context);
|
||||
final channelPreviewTheme = ChannelPreviewTheme.of(context);
|
||||
return ListTile(
|
||||
onTap: onTap,
|
||||
leading: UserAvatar(
|
||||
@@ -53,18 +53,18 @@ class MessageSearchItem extends StatelessWidget {
|
||||
user.id == StreamChat.of(context).currentUser?.id
|
||||
? context.translations.youText
|
||||
: user.name,
|
||||
style: chatThemeData.channelPreviewTheme.title,
|
||||
style: channelPreviewTheme.titleStyle,
|
||||
),
|
||||
if (channelName != null) ...[
|
||||
Text(
|
||||
' ${context.translations.inText} ',
|
||||
style: chatThemeData.channelPreviewTheme.title?.copyWith(
|
||||
style: channelPreviewTheme.titleStyle?.copyWith(
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
channelName as String,
|
||||
style: chatThemeData.channelPreviewTheme.title,
|
||||
style: channelPreviewTheme.titleStyle,
|
||||
),
|
||||
],
|
||||
],
|
||||
@@ -94,7 +94,7 @@ class MessageSearchItem extends StatelessWidget {
|
||||
|
||||
return Text(
|
||||
stringDate,
|
||||
style: StreamChatTheme.of(context).channelPreviewTheme.lastMessageAt,
|
||||
style: StreamChatTheme.of(context).channelPreviewTheme.lastMessageAtStyle,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -122,18 +122,18 @@ class MessageSearchItem extends StatelessWidget {
|
||||
text = parts.join(' ');
|
||||
}
|
||||
|
||||
final chatThemeData = StreamChatTheme.of(context);
|
||||
final channelPreviewTheme = ChannelPreviewTheme.of(context);
|
||||
return Text.rich(
|
||||
_getDisplayText(
|
||||
text!,
|
||||
message.mentionedUsers,
|
||||
message.attachments,
|
||||
chatThemeData.channelPreviewTheme.subtitle?.copyWith(
|
||||
channelPreviewTheme.subtitleStyle?.copyWith(
|
||||
fontStyle: (message.isSystem || message.isDeleted)
|
||||
? FontStyle.italic
|
||||
: FontStyle.normal,
|
||||
),
|
||||
chatThemeData.channelPreviewTheme.subtitle?.copyWith(
|
||||
channelPreviewTheme.subtitleStyle?.copyWith(
|
||||
fontStyle: (message.isSystem || message.isDeleted)
|
||||
? FontStyle.italic
|
||||
: FontStyle.normal,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
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/src/theme/themes.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';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:collection/collection.dart' show IterableExtension;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_markdown/flutter_markdown.dart';
|
||||
import 'package:stream_chat_flutter/src/theme/themes.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||
|
||||
@@ -24,8 +25,8 @@ class MessageText extends StatelessWidget {
|
||||
/// Callback for when link is tapped
|
||||
final void Function(String)? onLinkTap;
|
||||
|
||||
/// [MessageTheme] whose text theme is to be applied
|
||||
final MessageTheme messageTheme;
|
||||
/// [MessageThemeData] whose text theme is to be applied
|
||||
final MessageThemeData messageTheme;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@@ -66,16 +67,16 @@ class MessageText extends StatelessWidget {
|
||||
styleSheet: MarkdownStyleSheet.fromTheme(
|
||||
themeData.copyWith(
|
||||
textTheme: themeData.textTheme.apply(
|
||||
bodyColor: messageTheme.messageText?.color,
|
||||
decoration: messageTheme.messageText?.decoration,
|
||||
decorationColor: messageTheme.messageText?.decorationColor,
|
||||
decorationStyle: messageTheme.messageText?.decorationStyle,
|
||||
fontFamily: messageTheme.messageText?.fontFamily,
|
||||
bodyColor: messageTheme.messageTextStyle?.color,
|
||||
decoration: messageTheme.messageTextStyle?.decoration,
|
||||
decorationColor: messageTheme.messageTextStyle?.decorationColor,
|
||||
decorationStyle: messageTheme.messageTextStyle?.decorationStyle,
|
||||
fontFamily: messageTheme.messageTextStyle?.fontFamily,
|
||||
),
|
||||
),
|
||||
).copyWith(
|
||||
a: messageTheme.messageLinks,
|
||||
p: messageTheme.messageText,
|
||||
a: messageTheme.messageLinksStyle,
|
||||
p: messageTheme.messageTextStyle,
|
||||
),
|
||||
);
|
||||
},
|
||||
|
||||
@@ -14,6 +14,7 @@ import 'package:stream_chat_flutter/src/message_actions_modal.dart';
|
||||
import 'package:stream_chat_flutter/src/message_reactions_modal.dart';
|
||||
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/theme/themes.dart';
|
||||
import 'package:stream_chat_flutter/src/url_attachment.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
@@ -290,7 +291,7 @@ class MessageWidget extends StatefulWidget {
|
||||
final Message message;
|
||||
|
||||
/// The message theme
|
||||
final MessageTheme messageTheme;
|
||||
final MessageThemeData messageTheme;
|
||||
|
||||
/// If true the widget will be mirrored
|
||||
final bool reverse;
|
||||
@@ -422,7 +423,7 @@ class MessageWidget extends StatefulWidget {
|
||||
Widget Function(BuildContext, Message)? deletedBottomRowBuilder,
|
||||
void Function(BuildContext, Message)? onMessageActions,
|
||||
Message? message,
|
||||
MessageTheme? messageTheme,
|
||||
MessageThemeData? messageTheme,
|
||||
bool? reverse,
|
||||
ShapeBorder? shape,
|
||||
ShapeBorder? attachmentShape,
|
||||
@@ -893,14 +894,14 @@ class _MessageWidgetState extends State<MessageWidget>
|
||||
),
|
||||
InkWell(
|
||||
onTap: widget.onThreadTap != null ? onThreadTap : null,
|
||||
child: Text(msg, style: widget.messageTheme.replies),
|
||||
child: Text(msg, style: widget.messageTheme.repliesStyle),
|
||||
),
|
||||
],
|
||||
if (showUsername) _buildUsername(usernameKey),
|
||||
if (showTimeStamp)
|
||||
Text(
|
||||
Jiffy(widget.message.createdAt.toLocal()).jm,
|
||||
style: widget.messageTheme.createdAt,
|
||||
style: widget.messageTheme.createdAtStyle,
|
||||
),
|
||||
if (showSendingIndicator) _buildSendingIndicator(),
|
||||
]);
|
||||
@@ -917,7 +918,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
||||
Container(
|
||||
margin: EdgeInsets.only(
|
||||
bottom: context.textScaleFactor *
|
||||
((widget.messageTheme.replies?.fontSize ?? 1) / 2),
|
||||
((widget.messageTheme.repliesStyle?.fontSize ?? 1) / 2),
|
||||
),
|
||||
child: CustomPaint(
|
||||
size: const Size(16, 32) * context.textScaleFactor,
|
||||
@@ -944,7 +945,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
||||
Container(
|
||||
margin: EdgeInsets.only(
|
||||
bottom: context.textScaleFactor *
|
||||
((widget.messageTheme.replies?.fontSize ?? 1) / 2),
|
||||
((widget.messageTheme.repliesStyle?.fontSize ?? 1) / 2),
|
||||
),
|
||||
child: CustomPaint(
|
||||
size: const Size(16, 32) * context.textScaleFactor,
|
||||
@@ -967,7 +968,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
||||
widget.message.user!.name,
|
||||
maxLines: 1,
|
||||
key: usernameKey,
|
||||
style: widget.messageTheme.messageAuthor,
|
||||
style: widget.messageTheme.messageAuthorStyle,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
);
|
||||
}
|
||||
@@ -1191,7 +1192,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
||||
}
|
||||
|
||||
Widget _buildSendingIndicator() {
|
||||
final style = widget.messageTheme.createdAt;
|
||||
final style = widget.messageTheme.createdAtStyle;
|
||||
final message = widget.message;
|
||||
|
||||
if (hasNonUrlAttachments &&
|
||||
@@ -1271,8 +1272,8 @@ class _MessageWidgetState extends State<MessageWidget>
|
||||
onMentionTap: widget.onMentionTap,
|
||||
messageTheme: isOnlyEmoji
|
||||
? widget.messageTheme.copyWith(
|
||||
messageText:
|
||||
widget.messageTheme.messageText!.copyWith(
|
||||
messageTextStyle:
|
||||
widget.messageTheme.messageTextStyle!.copyWith(
|
||||
fontSize: 42,
|
||||
))
|
||||
: widget.messageTheme,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/src/extension.dart';
|
||||
import 'package:stream_chat_flutter/src/theme/themes.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||
import 'package:video_player/video_player.dart';
|
||||
@@ -73,7 +74,7 @@ class QuotedMessageWidget extends StatelessWidget {
|
||||
final Message message;
|
||||
|
||||
/// The message theme
|
||||
final MessageTheme messageTheme;
|
||||
final MessageThemeData messageTheme;
|
||||
|
||||
/// If true the widget will be mirrored
|
||||
final bool reverse;
|
||||
@@ -138,11 +139,11 @@ class QuotedMessageWidget extends StatelessWidget {
|
||||
message: msg,
|
||||
messageTheme: isOnlyEmoji && _containsText
|
||||
? messageTheme.copyWith(
|
||||
messageText: messageTheme.messageText?.copyWith(
|
||||
messageTextStyle: messageTheme.messageTextStyle?.copyWith(
|
||||
fontSize: 32,
|
||||
))
|
||||
: messageTheme.copyWith(
|
||||
messageText: messageTheme.messageText?.copyWith(
|
||||
messageTextStyle: messageTheme.messageTextStyle?.copyWith(
|
||||
fontSize: 12,
|
||||
)),
|
||||
),
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,77 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// A style that overrides the default appearance of various avatar widgets.
|
||||
class AvatarThemeData with Diagnosticable {
|
||||
/// Creates an [AvatarThemeData].
|
||||
const AvatarThemeData({
|
||||
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 this [AvatarThemeData] to another.
|
||||
AvatarThemeData copyWith({
|
||||
BoxConstraints? constraints,
|
||||
BorderRadius? borderRadius,
|
||||
}) =>
|
||||
AvatarThemeData(
|
||||
constraints: constraints ?? _constraints,
|
||||
borderRadius: borderRadius ?? _borderRadius,
|
||||
);
|
||||
|
||||
/// Linearly interpolate between two [UserAvatar] themes.
|
||||
///
|
||||
/// All the properties must be non-null.
|
||||
AvatarThemeData lerp(
|
||||
AvatarThemeData a,
|
||||
AvatarThemeData b,
|
||||
double t,
|
||||
) =>
|
||||
AvatarThemeData(
|
||||
borderRadius: BorderRadius.lerp(a.borderRadius, b.borderRadius, t),
|
||||
constraints: BoxConstraints.lerp(a.constraints, b.constraints, t),
|
||||
);
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is AvatarThemeData &&
|
||||
runtimeType == other.runtimeType &&
|
||||
_constraints == other._constraints &&
|
||||
_borderRadius == other._borderRadius;
|
||||
|
||||
@override
|
||||
int get hashCode => _constraints.hashCode ^ _borderRadius.hashCode;
|
||||
|
||||
/// Merges one [AvatarThemeData] with the another
|
||||
AvatarThemeData merge(AvatarThemeData? other) {
|
||||
if (other == null) return this;
|
||||
return copyWith(
|
||||
constraints: other._constraints,
|
||||
borderRadius: other._borderRadius,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties
|
||||
..add(DiagnosticsProperty('borderRadius', borderRadius))
|
||||
..add(DiagnosticsProperty('constraints', constraints));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,149 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||
import 'package:stream_chat_flutter/src/theme/avatar_theme.dart';
|
||||
import 'package:stream_chat_flutter/src/theme/themes.dart';
|
||||
|
||||
/// Overrides the default style of [ChannelHeader] descendants.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [ChannelHeaderThemeData], which is used to configure this theme.
|
||||
class ChannelHeaderTheme extends InheritedTheme {
|
||||
/// Creates a [ChannelHeaderTheme].
|
||||
///
|
||||
/// The [data] parameter must not be null.
|
||||
const ChannelHeaderTheme({
|
||||
Key? key,
|
||||
required this.data,
|
||||
required Widget child,
|
||||
}) : super(key: key, child: child);
|
||||
|
||||
/// The configuration of this theme.
|
||||
final ChannelHeaderThemeData data;
|
||||
|
||||
/// The closest instance of this class that encloses the given context.
|
||||
///
|
||||
/// If there is no enclosing [ChannelHeaderTheme] widget, then
|
||||
/// [StreamChatThemeData.channelTheme.channelHeaderTheme] is used.
|
||||
///
|
||||
/// Typical usage is as follows:
|
||||
///
|
||||
/// ```dart
|
||||
/// final theme = ChannelHeaderTheme.of(context);
|
||||
/// ```
|
||||
static ChannelHeaderThemeData of(BuildContext context) {
|
||||
final channelHeaderTheme =
|
||||
context.dependOnInheritedWidgetOfExactType<ChannelHeaderTheme>();
|
||||
return channelHeaderTheme?.data ??
|
||||
StreamChatTheme.of(context).channelHeaderTheme;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget wrap(BuildContext context, Widget child) =>
|
||||
ChannelHeaderTheme(data: data, child: child);
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(ChannelHeaderTheme oldWidget) =>
|
||||
data != oldWidget.data;
|
||||
}
|
||||
|
||||
/// A style that overrides the default appearance of [ChannelHeader]s when used
|
||||
/// with [ChannelHeaderTheme] or with the overall [StreamChatTheme]'s
|
||||
/// [StreamChatThemeData.channelHeaderTheme].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [ChannelHeaderTheme], the theme which is configured with this class.
|
||||
/// * [StreamChatThemeData.channelHeaderTheme], which can be used to override
|
||||
/// the default style for [ChannelHeader]s below the overall [StreamChatTheme].
|
||||
class ChannelHeaderThemeData with Diagnosticable {
|
||||
/// Creates a [ChannelHeaderThemeData]
|
||||
const ChannelHeaderThemeData({
|
||||
this.titleStyle,
|
||||
this.subtitleStyle,
|
||||
this.avatarTheme,
|
||||
this.color,
|
||||
});
|
||||
|
||||
/// Theme for title
|
||||
final TextStyle? titleStyle;
|
||||
|
||||
/// Theme for subtitle
|
||||
final TextStyle? subtitleStyle;
|
||||
|
||||
/// Theme for avatar
|
||||
final AvatarThemeData? avatarTheme;
|
||||
|
||||
/// Color for [ChannelHeaderThemeData]
|
||||
final Color? color;
|
||||
|
||||
/// Copy with theme
|
||||
ChannelHeaderThemeData copyWith({
|
||||
TextStyle? titleStyle,
|
||||
TextStyle? subtitleStyle,
|
||||
AvatarThemeData? avatarTheme,
|
||||
Color? color,
|
||||
}) =>
|
||||
ChannelHeaderThemeData(
|
||||
titleStyle: titleStyle ?? this.titleStyle,
|
||||
subtitleStyle: subtitleStyle ?? this.subtitleStyle,
|
||||
avatarTheme: avatarTheme ?? this.avatarTheme,
|
||||
color: color ?? this.color,
|
||||
);
|
||||
|
||||
/// Linearly interpolate between two [ChannelHeaderThemeData].
|
||||
///
|
||||
/// All the properties must be non-null.
|
||||
ChannelHeaderThemeData lerp(
|
||||
ChannelHeaderThemeData a,
|
||||
ChannelHeaderThemeData b,
|
||||
double t,
|
||||
) =>
|
||||
ChannelHeaderThemeData(
|
||||
titleStyle: TextStyle.lerp(a.titleStyle, b.titleStyle, t),
|
||||
subtitleStyle: TextStyle.lerp(a.subtitleStyle, b.subtitleStyle, t),
|
||||
avatarTheme:
|
||||
const AvatarThemeData().lerp(a.avatarTheme!, b.avatarTheme!, t),
|
||||
color: Color.lerp(a.color, b.color, t),
|
||||
);
|
||||
|
||||
/// Merge with other [ChannelHeaderThemeData]
|
||||
ChannelHeaderThemeData merge(ChannelHeaderThemeData? other) {
|
||||
if (other == null) return this;
|
||||
return copyWith(
|
||||
titleStyle: titleStyle?.merge(other.titleStyle) ?? other.titleStyle,
|
||||
subtitleStyle:
|
||||
subtitleStyle?.merge(other.subtitleStyle) ?? other.subtitleStyle,
|
||||
avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme,
|
||||
color: other.color,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is ChannelHeaderThemeData &&
|
||||
runtimeType == other.runtimeType &&
|
||||
titleStyle == other.titleStyle &&
|
||||
subtitleStyle == other.subtitleStyle &&
|
||||
avatarTheme == other.avatarTheme &&
|
||||
color == other.color;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
titleStyle.hashCode ^
|
||||
subtitleStyle.hashCode ^
|
||||
avatarTheme.hashCode ^
|
||||
color.hashCode;
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties
|
||||
..add(DiagnosticsProperty('title', titleStyle))
|
||||
..add(DiagnosticsProperty('subtitle', subtitleStyle))
|
||||
..add(DiagnosticsProperty('avatarTheme', avatarTheme))
|
||||
..add(ColorProperty('color', color));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||
import 'package:stream_chat_flutter/src/theme/avatar_theme.dart';
|
||||
|
||||
/// Overrides the default style of [ChannelListHeader] descendants.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [ChannelListHeaderThemeData], which is used to configure this theme.
|
||||
class ChannelListHeaderTheme extends InheritedTheme {
|
||||
/// Creates a [ChannelListHeaderTheme].
|
||||
///
|
||||
/// The [data] parameter must not be null.
|
||||
const ChannelListHeaderTheme({
|
||||
Key? key,
|
||||
required this.data,
|
||||
required Widget child,
|
||||
}) : super(key: key, child: child);
|
||||
|
||||
/// The configuration of this theme.
|
||||
final ChannelListHeaderThemeData data;
|
||||
|
||||
/// The closest instance of this class that encloses the given context.
|
||||
///
|
||||
/// If there is no enclosing [ChannelListHeaderTheme] widget, then
|
||||
/// [StreamChatThemeData.channelListHeaderTheme] is used.
|
||||
///
|
||||
/// Typical usage is as follows:
|
||||
///
|
||||
/// ```dart
|
||||
/// final theme = ChannelListHeaderTheme.of(context);
|
||||
/// ```
|
||||
static ChannelListHeaderThemeData of(BuildContext context) {
|
||||
final channelListHeaderTheme =
|
||||
context.dependOnInheritedWidgetOfExactType<ChannelListHeaderTheme>();
|
||||
return channelListHeaderTheme?.data ??
|
||||
StreamChatTheme.of(context).channelListHeaderTheme;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget wrap(BuildContext context, Widget child) =>
|
||||
ChannelListHeaderTheme(data: data, child: child);
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(ChannelListHeaderTheme oldWidget) =>
|
||||
data != oldWidget.data;
|
||||
}
|
||||
|
||||
/// Theme dedicated to the [ChannelListHeader]
|
||||
class ChannelListHeaderThemeData with Diagnosticable {
|
||||
/// Returns a new [ChannelListHeaderThemeData]
|
||||
const ChannelListHeaderThemeData({
|
||||
this.titleStyle,
|
||||
this.avatarTheme,
|
||||
this.color,
|
||||
});
|
||||
|
||||
/// Style of the title text
|
||||
final TextStyle? titleStyle;
|
||||
|
||||
/// Theme dedicated to the userAvatar
|
||||
final AvatarThemeData? avatarTheme;
|
||||
|
||||
/// Background color of the appbar
|
||||
final Color? color;
|
||||
|
||||
/// Returns a new [ChannelListHeaderThemeData] replacing some of its
|
||||
/// properties
|
||||
ChannelListHeaderThemeData copyWith({
|
||||
TextStyle? titleStyle,
|
||||
AvatarThemeData? avatarTheme,
|
||||
Color? color,
|
||||
}) =>
|
||||
ChannelListHeaderThemeData(
|
||||
titleStyle: titleStyle ?? this.titleStyle,
|
||||
avatarTheme: avatarTheme ?? this.avatarTheme,
|
||||
color: color ?? this.color,
|
||||
);
|
||||
|
||||
/// Linearly interpolate from one [ChannelListHeaderThemeData] to another.
|
||||
ChannelListHeaderThemeData lerp(
|
||||
ChannelListHeaderThemeData a,
|
||||
ChannelListHeaderThemeData b,
|
||||
double t,
|
||||
) =>
|
||||
ChannelListHeaderThemeData(
|
||||
avatarTheme:
|
||||
const AvatarThemeData().lerp(a.avatarTheme!, b.avatarTheme!, t),
|
||||
color: Color.lerp(a.color, b.color, t),
|
||||
titleStyle: TextStyle.lerp(a.titleStyle, b.titleStyle, t),
|
||||
);
|
||||
|
||||
/// Merges [this] [ChannelListHeaderThemeData] with the [other]
|
||||
ChannelListHeaderThemeData merge(ChannelListHeaderThemeData? other) {
|
||||
if (other == null) return this;
|
||||
return copyWith(
|
||||
titleStyle: titleStyle?.merge(other.titleStyle) ?? other.titleStyle,
|
||||
avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme,
|
||||
color: other.color,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is ChannelListHeaderThemeData &&
|
||||
runtimeType == other.runtimeType &&
|
||||
titleStyle == other.titleStyle &&
|
||||
avatarTheme == other.avatarTheme &&
|
||||
color == other.color;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
titleStyle.hashCode ^ avatarTheme.hashCode ^ color.hashCode;
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties
|
||||
..add(DiagnosticsProperty('titleStyle', titleStyle))
|
||||
..add(DiagnosticsProperty('avatarTheme', avatarTheme))
|
||||
..add(ColorProperty('color', color));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||
|
||||
/// Overrides the default style of [ChannelListView] descendants.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [ChannelListViewThemeData], which is used to configure this theme.
|
||||
class ChannelListViewTheme extends InheritedTheme {
|
||||
/// Creates a [ChannelListViewTheme].
|
||||
///
|
||||
/// The [data] parameter must not be null.
|
||||
const ChannelListViewTheme({
|
||||
Key? key,
|
||||
required this.data,
|
||||
required Widget child,
|
||||
}) : super(key: key, child: child);
|
||||
|
||||
/// The configuration of this theme.
|
||||
final ChannelListViewThemeData data;
|
||||
|
||||
/// The closest instance of this class that encloses the given context.
|
||||
///
|
||||
/// If there is no enclosing [ChannelListViewTheme] widget, then
|
||||
/// [StreamChatThemeData.channelListViewTheme] is used.
|
||||
///
|
||||
/// Typical usage is as follows:
|
||||
///
|
||||
/// ```dart
|
||||
/// ChannelListViewTheme theme = ChannelListViewTheme.of(context);
|
||||
/// ```
|
||||
static ChannelListViewThemeData of(BuildContext context) {
|
||||
final channelListViewTheme =
|
||||
context.dependOnInheritedWidgetOfExactType<ChannelListViewTheme>();
|
||||
return channelListViewTheme?.data ??
|
||||
StreamChatTheme.of(context).channelListViewTheme;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget wrap(BuildContext context, Widget child) =>
|
||||
ChannelListViewTheme(data: data, child: child);
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(ChannelListViewTheme oldWidget) =>
|
||||
data != oldWidget.data;
|
||||
}
|
||||
|
||||
/// A style that overrides the default appearance of [ChannelListView]s when
|
||||
/// used with [ChannelListViewTheme] or with the overall [StreamChatTheme]'s
|
||||
/// [StreamChatThemeData.channelListViewTheme].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [ChannelListViewTheme], the theme which is configured with this class.
|
||||
/// * [StreamChatThemeData.channelListViewTheme], which can be used to override
|
||||
/// the default style for [ChannelListView]s below the overall
|
||||
/// [StreamChatTheme].
|
||||
class ChannelListViewThemeData with Diagnosticable {
|
||||
/// Creates a [ChannelListViewThemeData].
|
||||
const ChannelListViewThemeData({
|
||||
this.backgroundColor,
|
||||
});
|
||||
|
||||
/// The color of the [ChannelListView] background.
|
||||
final Color? backgroundColor;
|
||||
|
||||
/// Copies this [ChannelListViewThemeData] to another.
|
||||
ChannelListViewThemeData copyWith({
|
||||
Color? backgroundColor,
|
||||
}) =>
|
||||
ChannelListViewThemeData(
|
||||
backgroundColor: backgroundColor ?? this.backgroundColor,
|
||||
);
|
||||
|
||||
/// Linearly interpolate between two [ChannelListViewThemeData] themes.
|
||||
///
|
||||
/// All the properties must be non-null.
|
||||
ChannelListViewThemeData lerp(
|
||||
ChannelListViewThemeData a,
|
||||
ChannelListViewThemeData b,
|
||||
double t,
|
||||
) =>
|
||||
ChannelListViewThemeData(
|
||||
backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
|
||||
);
|
||||
|
||||
/// Merges one [ChannelListViewThemeData] with another.
|
||||
ChannelListViewThemeData merge(ChannelListViewThemeData? other) {
|
||||
if (other == null) return this;
|
||||
return copyWith(
|
||||
backgroundColor: other.backgroundColor,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is ChannelListViewThemeData &&
|
||||
runtimeType == other.runtimeType &&
|
||||
backgroundColor == other.backgroundColor;
|
||||
|
||||
@override
|
||||
int get hashCode => backgroundColor.hashCode;
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties.add(ColorProperty('backgroundColor', backgroundColor));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||
import 'package:stream_chat_flutter/src/theme/avatar_theme.dart';
|
||||
|
||||
/// Overrides the default style of [ChannelPreview] descendants.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [ChannelPreviewThemeData], which is used to configure this theme.
|
||||
class ChannelPreviewTheme extends InheritedTheme {
|
||||
/// Creates a [ChannelPreviewTheme].
|
||||
///
|
||||
/// The [data] parameter must not be null.
|
||||
const ChannelPreviewTheme({
|
||||
Key? key,
|
||||
required this.data,
|
||||
required Widget child,
|
||||
}) : super(key: key, child: child);
|
||||
|
||||
/// The configuration of this theme.
|
||||
final ChannelPreviewThemeData data;
|
||||
|
||||
/// The closest instance of this class that encloses the given context.
|
||||
///
|
||||
/// If there is no enclosing [ChannelPreviewTheme] widget, then
|
||||
/// [StreamChatThemeData.channelPreviewTheme] is used.
|
||||
///
|
||||
/// Typical usage is as follows:
|
||||
///
|
||||
/// ```dart
|
||||
/// final theme = ChannelPreviewTheme.of(context);
|
||||
/// ```
|
||||
static ChannelPreviewThemeData of(BuildContext context) {
|
||||
final channelPreviewTheme =
|
||||
context.dependOnInheritedWidgetOfExactType<ChannelPreviewTheme>();
|
||||
return channelPreviewTheme?.data ??
|
||||
StreamChatTheme.of(context).channelPreviewTheme;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget wrap(BuildContext context, Widget child) =>
|
||||
ChannelPreviewTheme(data: data, child: child);
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(ChannelPreviewTheme oldWidget) =>
|
||||
data != oldWidget.data;
|
||||
}
|
||||
|
||||
/// A style that overrides the default appearance of [ChannelPreview]s when used
|
||||
/// with [ChannelPreviewTheme] or with the overall [StreamChatTheme]'s
|
||||
/// [StreamChatThemeData.channelPreviewTheme].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [ChannelPreviewTheme], the theme which is configured with this class.
|
||||
/// * [StreamChatThemeData.channelPreviewTheme], which can be used to override
|
||||
/// the default style for [ChannelHeader]s below the overall [StreamChatTheme].
|
||||
class ChannelPreviewThemeData with Diagnosticable {
|
||||
/// Creates a [ChannelPreviewThemeData].
|
||||
const ChannelPreviewThemeData({
|
||||
this.titleStyle,
|
||||
this.subtitleStyle,
|
||||
this.lastMessageAtStyle,
|
||||
this.avatarTheme,
|
||||
this.unreadCounterColor,
|
||||
this.indicatorIconSize,
|
||||
});
|
||||
|
||||
/// Theme for title
|
||||
final TextStyle? titleStyle;
|
||||
|
||||
/// Theme for subtitle
|
||||
final TextStyle? subtitleStyle;
|
||||
|
||||
/// Theme of last message at
|
||||
final TextStyle? lastMessageAtStyle;
|
||||
|
||||
/// Avatar theme
|
||||
final AvatarThemeData? avatarTheme;
|
||||
|
||||
/// Unread counter color
|
||||
final Color? unreadCounterColor;
|
||||
|
||||
/// Indicator icon size
|
||||
final double? indicatorIconSize;
|
||||
|
||||
/// Copy with theme
|
||||
ChannelPreviewThemeData copyWith({
|
||||
TextStyle? titleStyle,
|
||||
TextStyle? subtitleStyle,
|
||||
TextStyle? lastMessageAtStyle,
|
||||
AvatarThemeData? avatarTheme,
|
||||
Color? unreadCounterColor,
|
||||
double? indicatorIconSize,
|
||||
}) =>
|
||||
ChannelPreviewThemeData(
|
||||
titleStyle: titleStyle ?? this.titleStyle,
|
||||
subtitleStyle: subtitleStyle ?? this.subtitleStyle,
|
||||
lastMessageAtStyle: lastMessageAtStyle ?? this.lastMessageAtStyle,
|
||||
avatarTheme: avatarTheme ?? this.avatarTheme,
|
||||
unreadCounterColor: unreadCounterColor ?? this.unreadCounterColor,
|
||||
indicatorIconSize: indicatorIconSize ?? this.indicatorIconSize,
|
||||
);
|
||||
|
||||
/// Linearly interpolate one [ChannelPreviewThemeData] to another.
|
||||
ChannelPreviewThemeData lerp(
|
||||
ChannelPreviewThemeData a,
|
||||
ChannelPreviewThemeData b,
|
||||
double t,
|
||||
) =>
|
||||
ChannelPreviewThemeData(
|
||||
avatarTheme:
|
||||
const AvatarThemeData().lerp(a.avatarTheme!, b.avatarTheme!, t),
|
||||
indicatorIconSize: a.indicatorIconSize,
|
||||
lastMessageAtStyle:
|
||||
TextStyle.lerp(a.lastMessageAtStyle, b.lastMessageAtStyle, t),
|
||||
subtitleStyle: TextStyle.lerp(a.subtitleStyle, b.subtitleStyle, t),
|
||||
titleStyle: TextStyle.lerp(a.titleStyle, b.titleStyle, t),
|
||||
unreadCounterColor:
|
||||
Color.lerp(a.unreadCounterColor, b.unreadCounterColor, t),
|
||||
);
|
||||
|
||||
/// Merge with theme
|
||||
ChannelPreviewThemeData merge(ChannelPreviewThemeData? other) {
|
||||
if (other == null) return this;
|
||||
return copyWith(
|
||||
titleStyle: titleStyle?.merge(other.titleStyle) ?? other.titleStyle,
|
||||
subtitleStyle:
|
||||
subtitleStyle?.merge(other.subtitleStyle) ?? other.subtitleStyle,
|
||||
lastMessageAtStyle: lastMessageAtStyle?.merge(other.lastMessageAtStyle) ??
|
||||
other.lastMessageAtStyle,
|
||||
avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme,
|
||||
unreadCounterColor: other.unreadCounterColor,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is ChannelPreviewThemeData &&
|
||||
runtimeType == other.runtimeType &&
|
||||
titleStyle == other.titleStyle &&
|
||||
subtitleStyle == other.subtitleStyle &&
|
||||
lastMessageAtStyle == other.lastMessageAtStyle &&
|
||||
avatarTheme == other.avatarTheme &&
|
||||
unreadCounterColor == other.unreadCounterColor &&
|
||||
indicatorIconSize == other.indicatorIconSize;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
titleStyle.hashCode ^
|
||||
subtitleStyle.hashCode ^
|
||||
lastMessageAtStyle.hashCode ^
|
||||
avatarTheme.hashCode ^
|
||||
unreadCounterColor.hashCode ^
|
||||
indicatorIconSize.hashCode;
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties
|
||||
..add(DiagnosticsProperty('titleStyle', titleStyle))
|
||||
..add(DiagnosticsProperty('subtitleStyle', subtitleStyle))
|
||||
..add(DiagnosticsProperty('lastMessageAtStyle', lastMessageAtStyle))
|
||||
..add(DiagnosticsProperty('avatarTheme', avatarTheme))
|
||||
..add(ColorProperty('unreadCounterColor', unreadCounterColor));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// Theme that holds colors
|
||||
class ColorTheme {
|
||||
/// Initialise with light theme
|
||||
ColorTheme.light({
|
||||
this.textHighEmphasis = const Color(0xff000000),
|
||||
this.textLowEmphasis = const Color(0xff7a7a7a),
|
||||
this.disabled = const Color(0xffdbdbdb),
|
||||
this.borders = const Color(0xffecebeb),
|
||||
this.inputBg = const Color(0xfff2f2f2),
|
||||
this.appBg = const Color(0xfffcfcfc),
|
||||
this.barsBg = const Color(0xffffffff),
|
||||
this.linkBg = const Color(0xffe9f2ff),
|
||||
this.accentPrimary = const Color(0xff005FFF),
|
||||
this.accentError = const Color(0xffFF3842),
|
||||
this.accentInfo = 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.textHighEmphasis = const Color(0xffffffff),
|
||||
this.textLowEmphasis = const Color(0xff7a7a7a),
|
||||
this.disabled = const Color(0xff2d2f2f),
|
||||
this.borders = const Color(0xff1c1e22),
|
||||
this.inputBg = const Color(0xff13151b),
|
||||
this.appBg = const Color(0xff070A0D),
|
||||
this.barsBg = const Color(0xff101418),
|
||||
this.linkBg = const Color(0xff00193D),
|
||||
this.accentPrimary = const Color(0xff005FFF),
|
||||
this.accentError = const Color(0xffFF3742),
|
||||
this.accentInfo = 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 textHighEmphasis;
|
||||
|
||||
///
|
||||
final Color textLowEmphasis;
|
||||
|
||||
///
|
||||
final Color disabled;
|
||||
|
||||
///
|
||||
final Color borders;
|
||||
|
||||
///
|
||||
final Color inputBg;
|
||||
|
||||
///
|
||||
final Color appBg;
|
||||
|
||||
///
|
||||
final Color barsBg;
|
||||
|
||||
///
|
||||
final Color linkBg;
|
||||
|
||||
///
|
||||
final Color accentPrimary;
|
||||
|
||||
///
|
||||
final Color accentError;
|
||||
|
||||
///
|
||||
final Color accentInfo;
|
||||
|
||||
///
|
||||
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? textHighEmphasis,
|
||||
Color? textLowEmphasis,
|
||||
Color? disabled,
|
||||
Color? borders,
|
||||
Color? inputBg,
|
||||
Color? appBg,
|
||||
Color? barsBg,
|
||||
Color? linkBg,
|
||||
Color? accentPrimary,
|
||||
Color? accentError,
|
||||
Color? accentInfo,
|
||||
Effect? borderTop,
|
||||
Effect? borderBottom,
|
||||
Effect? shadowIconButton,
|
||||
Effect? modalShadow,
|
||||
Color? highlight,
|
||||
Color? overlay,
|
||||
Color? overlayDark,
|
||||
Gradient? bgGradient,
|
||||
}) =>
|
||||
brightness == Brightness.light
|
||||
? ColorTheme.light(
|
||||
textHighEmphasis: textHighEmphasis ?? this.textHighEmphasis,
|
||||
textLowEmphasis: textLowEmphasis ?? this.textLowEmphasis,
|
||||
disabled: disabled ?? this.disabled,
|
||||
borders: borders ?? this.borders,
|
||||
inputBg: inputBg ?? this.inputBg,
|
||||
appBg: appBg ?? this.appBg,
|
||||
barsBg: barsBg ?? this.barsBg,
|
||||
linkBg: linkBg ?? this.linkBg,
|
||||
accentPrimary: accentPrimary ?? this.accentPrimary,
|
||||
accentError: accentError ?? this.accentError,
|
||||
accentInfo: accentInfo ?? this.accentInfo,
|
||||
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(
|
||||
textHighEmphasis: textHighEmphasis ?? this.textHighEmphasis,
|
||||
textLowEmphasis: textLowEmphasis ?? this.textLowEmphasis,
|
||||
disabled: disabled ?? this.disabled,
|
||||
borders: borders ?? this.borders,
|
||||
inputBg: inputBg ?? this.inputBg,
|
||||
appBg: appBg ?? this.appBg,
|
||||
barsBg: barsBg ?? this.barsBg,
|
||||
linkBg: linkBg ?? this.linkBg,
|
||||
accentPrimary: accentPrimary ?? this.accentPrimary,
|
||||
accentError: accentError ?? this.accentError,
|
||||
accentInfo: accentInfo ?? this.accentInfo,
|
||||
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(
|
||||
textHighEmphasis: other.textHighEmphasis,
|
||||
textLowEmphasis: other.textLowEmphasis,
|
||||
disabled: other.disabled,
|
||||
borders: other.borders,
|
||||
inputBg: other.inputBg,
|
||||
appBg: other.appBg,
|
||||
barsBg: other.barsBg,
|
||||
linkBg: other.linkBg,
|
||||
accentPrimary: other.accentPrimary,
|
||||
accentError: other.accentError,
|
||||
accentInfo: other.accentInfo,
|
||||
highlight: other.highlight,
|
||||
overlay: other.overlay,
|
||||
overlayDark: other.overlayDark,
|
||||
bgGradient: other.bgGradient,
|
||||
borderTop: other.borderTop,
|
||||
borderBottom: other.borderBottom,
|
||||
shadowIconButton: other.shadowIconButton,
|
||||
modalShadow: other.modalShadow,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// 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,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||
|
||||
/// Overrides the default style of [GalleryFooter] descendants.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [GalleryFooterThemeData], which is used to configure this theme.
|
||||
class GalleryFooterTheme extends InheritedTheme {
|
||||
/// Creates an [GalleryFooterTheme].
|
||||
///
|
||||
/// The [data] parameter must not be null.
|
||||
const GalleryFooterTheme({
|
||||
Key? key,
|
||||
required this.data,
|
||||
required Widget child,
|
||||
}) : super(key: key, child: child);
|
||||
|
||||
/// The configuration of this theme.
|
||||
final GalleryFooterThemeData data;
|
||||
|
||||
/// The closest instance of this class that encloses the given context.
|
||||
///
|
||||
/// If there is no enclosing [GalleryFooterTheme] widget, then
|
||||
/// [StreamChatThemeData.galleryFooterTheme] is used.
|
||||
///
|
||||
/// Typical usage is as follows:
|
||||
///
|
||||
/// ```dart
|
||||
/// ImageFooterTheme theme = ImageFooterTheme.of(context);
|
||||
/// ```
|
||||
static GalleryFooterThemeData of(BuildContext context) {
|
||||
final imageFooterTheme =
|
||||
context.dependOnInheritedWidgetOfExactType<GalleryFooterTheme>();
|
||||
return imageFooterTheme?.data ??
|
||||
StreamChatTheme.of(context).galleryFooterTheme;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget wrap(BuildContext context, Widget child) =>
|
||||
GalleryFooterTheme(data: data, child: child);
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(GalleryFooterTheme oldWidget) =>
|
||||
data != oldWidget.data;
|
||||
}
|
||||
|
||||
/// A style that overrides the default appearance of [GalleryFooter]s when used
|
||||
/// with [GalleryFooterTheme] or with the overall [StreamChatTheme]'s
|
||||
/// [StreamChatThemeData.galleryFooterTheme].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [GalleryFooterTheme], the theme which is configured with this class.
|
||||
/// * [StreamChatThemeData.galleryFooterTheme], which can be used to override
|
||||
/// the default style for [GalleryFooter]s below the overall [StreamChatTheme].
|
||||
class GalleryFooterThemeData with Diagnosticable {
|
||||
/// Creates an [GalleryFooterThemeData].
|
||||
const GalleryFooterThemeData({
|
||||
this.backgroundColor,
|
||||
this.shareIconColor,
|
||||
this.titleTextStyle,
|
||||
this.gridIconButtonColor,
|
||||
this.bottomSheetBarrierColor,
|
||||
this.bottomSheetBackgroundColor,
|
||||
this.bottomSheetPhotosTextStyle,
|
||||
this.bottomSheetCloseIconColor,
|
||||
});
|
||||
|
||||
/// The background color for the [GalleryFooter] widget.
|
||||
///
|
||||
/// Defaults to [ColorTheme.barsBg].
|
||||
final Color? backgroundColor;
|
||||
|
||||
/// The color for the "share" icon.
|
||||
///
|
||||
/// Defaults to [ColorTheme.textHighEmphasis].
|
||||
final Color? shareIconColor;
|
||||
|
||||
/// The [TextStyle] to use for the [GalleryFooter] title text.
|
||||
///
|
||||
/// Defaults to [TextTheme.headlineBold].
|
||||
final TextStyle? titleTextStyle;
|
||||
|
||||
/// The color to use for the "grid" icon.
|
||||
///
|
||||
/// Defaults to [ColorTheme.textHighEmphasis].
|
||||
final Color? gridIconButtonColor;
|
||||
|
||||
/// The color to use behind the bottom sheet.
|
||||
///
|
||||
/// Defaults to [ColorTheme.overlay].
|
||||
final Color? bottomSheetBarrierColor;
|
||||
|
||||
/// The background color to use for the bottom sheet.
|
||||
///
|
||||
/// Defaults to [ColorTheme.barsBg].
|
||||
final Color? bottomSheetBackgroundColor;
|
||||
|
||||
/// The [TextStyle] to use for the "photos" text in the bottom sheet.
|
||||
///
|
||||
/// Defaults to [TextTheme.headlineBold].
|
||||
final TextStyle? bottomSheetPhotosTextStyle;
|
||||
|
||||
/// The color to use for the "close" icon.
|
||||
///
|
||||
/// Defaults to [ColorTheme.textHighEmphasis].
|
||||
final Color? bottomSheetCloseIconColor;
|
||||
|
||||
/// Copies this [GalleryFooterThemeData] to another.
|
||||
GalleryFooterThemeData copyWith({
|
||||
Color? backgroundColor,
|
||||
Color? shareIconColor,
|
||||
TextStyle? titleTextStyle,
|
||||
Color? gridIconButtonColor,
|
||||
Color? bottomSheetBarrierColor,
|
||||
Color? bottomSheetBackgroundColor,
|
||||
TextStyle? bottomSheetPhotosTextStyle,
|
||||
Color? bottomSheetCloseIconColor,
|
||||
}) =>
|
||||
GalleryFooterThemeData(
|
||||
backgroundColor: backgroundColor ?? this.backgroundColor,
|
||||
shareIconColor: shareIconColor ?? this.shareIconColor,
|
||||
titleTextStyle: titleTextStyle ?? this.titleTextStyle,
|
||||
gridIconButtonColor: gridIconButtonColor ?? this.gridIconButtonColor,
|
||||
bottomSheetBarrierColor:
|
||||
bottomSheetBarrierColor ?? this.bottomSheetBarrierColor,
|
||||
bottomSheetBackgroundColor:
|
||||
bottomSheetBackgroundColor ?? this.bottomSheetBackgroundColor,
|
||||
bottomSheetPhotosTextStyle:
|
||||
bottomSheetPhotosTextStyle ?? this.bottomSheetPhotosTextStyle,
|
||||
bottomSheetCloseIconColor:
|
||||
bottomSheetCloseIconColor ?? this.bottomSheetCloseIconColor,
|
||||
);
|
||||
|
||||
/// Linearly interpolate between two [GalleryFooter] themes.
|
||||
///
|
||||
/// All the properties must be non-null.
|
||||
GalleryFooterThemeData lerp(
|
||||
GalleryFooterThemeData a,
|
||||
GalleryFooterThemeData b,
|
||||
double t,
|
||||
) =>
|
||||
GalleryFooterThemeData(
|
||||
backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
|
||||
shareIconColor: Color.lerp(a.shareIconColor, b.shareIconColor, t),
|
||||
titleTextStyle: TextStyle.lerp(a.titleTextStyle, b.titleTextStyle, t),
|
||||
gridIconButtonColor:
|
||||
Color.lerp(a.gridIconButtonColor, b.gridIconButtonColor, t),
|
||||
bottomSheetBarrierColor:
|
||||
Color.lerp(a.bottomSheetBarrierColor, b.bottomSheetBarrierColor, t),
|
||||
bottomSheetBackgroundColor: Color.lerp(
|
||||
a.bottomSheetBackgroundColor, b.bottomSheetBackgroundColor, t),
|
||||
bottomSheetPhotosTextStyle: TextStyle.lerp(
|
||||
a.bottomSheetPhotosTextStyle, b.bottomSheetPhotosTextStyle, t),
|
||||
bottomSheetCloseIconColor: Color.lerp(
|
||||
a.bottomSheetCloseIconColor, b.bottomSheetCloseIconColor, t),
|
||||
);
|
||||
|
||||
/// Merges one [GalleryFooterThemeData] with another.
|
||||
GalleryFooterThemeData merge(GalleryFooterThemeData? other) {
|
||||
if (other == null) return this;
|
||||
return copyWith(
|
||||
backgroundColor: other.backgroundColor,
|
||||
bottomSheetBarrierColor: other.bottomSheetBarrierColor,
|
||||
bottomSheetBackgroundColor: other.bottomSheetBackgroundColor,
|
||||
bottomSheetCloseIconColor: other.bottomSheetCloseIconColor,
|
||||
bottomSheetPhotosTextStyle: other.bottomSheetPhotosTextStyle,
|
||||
gridIconButtonColor: other.gridIconButtonColor,
|
||||
titleTextStyle: other.titleTextStyle,
|
||||
shareIconColor: other.shareIconColor,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is GalleryFooterThemeData &&
|
||||
runtimeType == other.runtimeType &&
|
||||
backgroundColor == other.backgroundColor &&
|
||||
shareIconColor == other.shareIconColor &&
|
||||
titleTextStyle == other.titleTextStyle &&
|
||||
gridIconButtonColor == other.gridIconButtonColor &&
|
||||
bottomSheetBarrierColor == other.bottomSheetBarrierColor &&
|
||||
bottomSheetBackgroundColor == other.bottomSheetBackgroundColor &&
|
||||
bottomSheetPhotosTextStyle == other.bottomSheetPhotosTextStyle &&
|
||||
bottomSheetCloseIconColor == other.bottomSheetCloseIconColor;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
backgroundColor.hashCode ^
|
||||
shareIconColor.hashCode ^
|
||||
titleTextStyle.hashCode ^
|
||||
gridIconButtonColor.hashCode ^
|
||||
bottomSheetBarrierColor.hashCode ^
|
||||
bottomSheetBackgroundColor.hashCode ^
|
||||
bottomSheetPhotosTextStyle.hashCode ^
|
||||
bottomSheetCloseIconColor.hashCode;
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties
|
||||
..add(ColorProperty('backgroundColor', backgroundColor))
|
||||
..add(ColorProperty('shareIconColor', shareIconColor))
|
||||
..add(DiagnosticsProperty('titleTextStyle', titleTextStyle))
|
||||
..add(ColorProperty('gridIconButtonColor', gridIconButtonColor))
|
||||
..add(ColorProperty('bottomSheetBarrierColor', bottomSheetBarrierColor))
|
||||
..add(ColorProperty(
|
||||
'bottomSheetBackgroundColor', bottomSheetBackgroundColor))
|
||||
..add(DiagnosticsProperty(
|
||||
'bottomSheetPhotosTextStyle', bottomSheetPhotosTextStyle))
|
||||
..add(ColorProperty(
|
||||
'bottomSheetCloseIconColor', bottomSheetCloseIconColor));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||
|
||||
/// Overrides the default style of [GalleryHeader] descendants.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [GalleryHeaderThemeData], which is used to configure this theme.
|
||||
class GalleryHeaderTheme extends InheritedTheme {
|
||||
/// Creates a [GalleryHeaderTheme].
|
||||
///
|
||||
/// The [data] parameter must not be null.
|
||||
const GalleryHeaderTheme({
|
||||
Key? key,
|
||||
required this.data,
|
||||
required Widget child,
|
||||
}) : super(key: key, child: child);
|
||||
|
||||
/// The configuration of this theme.
|
||||
final GalleryHeaderThemeData data;
|
||||
|
||||
/// The closest instance of this class that encloses the given context.
|
||||
///
|
||||
/// If there is no enclosing [GalleryHeaderTheme] widget, then
|
||||
/// [StreamChatThemeData.galleryHeaderTheme] is used.
|
||||
///
|
||||
/// Typical usage is as follows:
|
||||
///
|
||||
/// ```dart
|
||||
/// ImageHeaderTheme theme = ImageHeaderTheme.of(context);
|
||||
/// ```
|
||||
static GalleryHeaderThemeData of(BuildContext context) {
|
||||
final galleryHeaderTheme =
|
||||
context.dependOnInheritedWidgetOfExactType<GalleryHeaderTheme>();
|
||||
return galleryHeaderTheme?.data ??
|
||||
StreamChatTheme.of(context).galleryHeaderTheme;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget wrap(BuildContext context, Widget child) =>
|
||||
GalleryHeaderTheme(data: data, child: child);
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(GalleryHeaderTheme oldWidget) =>
|
||||
data != oldWidget.data;
|
||||
}
|
||||
|
||||
/// A style that overrides the default appearance of [GalleryHeader]s when used
|
||||
/// with [GalleryHeaderTheme] or with the overall [StreamChatTheme]'s
|
||||
/// [StreamChatThemeData.galleryHeaderTheme].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [GalleryHeaderTheme], the theme which is configured with this class.
|
||||
/// * [StreamChatThemeData.galleryHeaderTheme], which can be used to override
|
||||
/// the default style for [GalleryHeader]s below the overall [StreamChatTheme].
|
||||
class GalleryHeaderThemeData with Diagnosticable {
|
||||
/// Creates an [GalleryHeaderThemeData].
|
||||
const GalleryHeaderThemeData({
|
||||
this.closeButtonColor,
|
||||
this.backgroundColor,
|
||||
this.iconMenuPointColor,
|
||||
this.titleTextStyle,
|
||||
this.subtitleTextStyle,
|
||||
this.bottomSheetBarrierColor,
|
||||
});
|
||||
|
||||
/// The color of the "close" button.
|
||||
///
|
||||
/// Defaults to [ColorTheme.textHighEmphasis].
|
||||
final Color? closeButtonColor;
|
||||
|
||||
/// The background color of the [GalleryHeader] widget.
|
||||
///
|
||||
/// Defaults to [ChannelHeaderTheme.color].
|
||||
final Color? backgroundColor;
|
||||
|
||||
/// Defaults to [ColorTheme.textHighEmphasis].
|
||||
final Color? iconMenuPointColor;
|
||||
|
||||
/// The [TextStyle] to use for the [GalleryHeader] title text.
|
||||
///
|
||||
/// Defaults to [TextTheme.headlineBold].
|
||||
final TextStyle? titleTextStyle;
|
||||
|
||||
/// The [TextStyle] to use for the [GalleryHeader] subtitle text.
|
||||
///
|
||||
/// Defaults to [ChannelPreviewTheme.subtitleStyle].
|
||||
final TextStyle? subtitleTextStyle;
|
||||
|
||||
///
|
||||
final Color? bottomSheetBarrierColor;
|
||||
|
||||
/// Copies this [GalleryHeaderThemeData] to another.
|
||||
GalleryHeaderThemeData copyWith({
|
||||
Color? closeButtonColor,
|
||||
Color? backgroundColor,
|
||||
Color? iconMenuPointColor,
|
||||
TextStyle? titleTextStyle,
|
||||
TextStyle? subtitleTextStyle,
|
||||
Color? bottomSheetBarrierColor,
|
||||
}) =>
|
||||
GalleryHeaderThemeData(
|
||||
closeButtonColor: closeButtonColor ?? this.closeButtonColor,
|
||||
backgroundColor: backgroundColor ?? this.backgroundColor,
|
||||
iconMenuPointColor: iconMenuPointColor ?? this.iconMenuPointColor,
|
||||
titleTextStyle: titleTextStyle ?? this.titleTextStyle,
|
||||
subtitleTextStyle: subtitleTextStyle ?? this.subtitleTextStyle,
|
||||
bottomSheetBarrierColor:
|
||||
bottomSheetBarrierColor ?? this.bottomSheetBarrierColor,
|
||||
);
|
||||
|
||||
/// Linearly interpolate between two [GalleryHeader] themes.
|
||||
///
|
||||
/// All the properties must be non-null.
|
||||
GalleryHeaderThemeData lerp(
|
||||
GalleryHeaderThemeData a,
|
||||
GalleryHeaderThemeData b,
|
||||
double t,
|
||||
) =>
|
||||
GalleryHeaderThemeData(
|
||||
closeButtonColor: Color.lerp(a.closeButtonColor, b.closeButtonColor, t),
|
||||
backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
|
||||
iconMenuPointColor:
|
||||
Color.lerp(a.iconMenuPointColor, b.iconMenuPointColor, t),
|
||||
titleTextStyle: TextStyle.lerp(a.titleTextStyle, b.titleTextStyle, t),
|
||||
subtitleTextStyle:
|
||||
TextStyle.lerp(a.subtitleTextStyle, b.subtitleTextStyle, t),
|
||||
bottomSheetBarrierColor:
|
||||
Color.lerp(a.bottomSheetBarrierColor, b.bottomSheetBarrierColor, t),
|
||||
);
|
||||
|
||||
/// Merges one [GalleryHeaderThemeData] with the another
|
||||
GalleryHeaderThemeData merge(GalleryHeaderThemeData? other) {
|
||||
if (other == null) return this;
|
||||
return copyWith(
|
||||
closeButtonColor: other.closeButtonColor,
|
||||
backgroundColor: other.backgroundColor,
|
||||
iconMenuPointColor: other.iconMenuPointColor,
|
||||
titleTextStyle: other.titleTextStyle,
|
||||
subtitleTextStyle: other.subtitleTextStyle,
|
||||
bottomSheetBarrierColor: other.bottomSheetBarrierColor,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is GalleryHeaderThemeData &&
|
||||
runtimeType == other.runtimeType &&
|
||||
closeButtonColor == other.closeButtonColor &&
|
||||
backgroundColor == other.backgroundColor &&
|
||||
iconMenuPointColor == other.iconMenuPointColor &&
|
||||
titleTextStyle == other.titleTextStyle &&
|
||||
subtitleTextStyle == other.subtitleTextStyle &&
|
||||
bottomSheetBarrierColor == other.bottomSheetBarrierColor;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
closeButtonColor.hashCode ^
|
||||
backgroundColor.hashCode ^
|
||||
iconMenuPointColor.hashCode ^
|
||||
titleTextStyle.hashCode ^
|
||||
subtitleTextStyle.hashCode ^
|
||||
bottomSheetBarrierColor.hashCode;
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties
|
||||
..add(ColorProperty('closeButtonColor', closeButtonColor))
|
||||
..add(ColorProperty('backgroundColor', backgroundColor))
|
||||
..add(ColorProperty('iconMenuPointColor', iconMenuPointColor))
|
||||
..add(DiagnosticsProperty('titleTextStyle', titleTextStyle))
|
||||
..add(DiagnosticsProperty('subtitleTextStyle', subtitleTextStyle))
|
||||
..add(ColorProperty('bottomSheetBarrierColor', bottomSheetBarrierColor));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,237 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/src/extension.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||
|
||||
/// Overrides the default style of [MessageInput] descendants.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [MessageInputThemeData], which is used to configure this theme.
|
||||
class MessageInputTheme extends InheritedTheme {
|
||||
/// Creates a [MessageInputTheme].
|
||||
///
|
||||
/// The [data] parameter must not be null.
|
||||
const MessageInputTheme({
|
||||
Key? key,
|
||||
required this.data,
|
||||
required Widget child,
|
||||
}) : super(key: key, child: child);
|
||||
|
||||
/// The configuration of this theme.
|
||||
final MessageInputThemeData data;
|
||||
|
||||
/// The closest instance of this class that encloses the given context.
|
||||
///
|
||||
/// If there is no enclosing [MessageInputTheme] widget, then
|
||||
/// [StreamChatThemeData.messageInputTheme] is used.
|
||||
///
|
||||
/// Typical usage is as follows:
|
||||
///
|
||||
/// ```dart
|
||||
/// final theme = MessageInputTheme.of(context);
|
||||
/// ```
|
||||
static MessageInputThemeData of(BuildContext context) {
|
||||
final messageInputTheme =
|
||||
context.dependOnInheritedWidgetOfExactType<MessageInputTheme>();
|
||||
return messageInputTheme?.data ??
|
||||
StreamChatTheme.of(context).messageInputTheme;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget wrap(BuildContext context, Widget child) =>
|
||||
MessageInputTheme(data: data, child: child);
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(MessageInputTheme oldWidget) =>
|
||||
data != oldWidget.data;
|
||||
}
|
||||
|
||||
/// A style that overrides the default appearance of [MessageInput] widgets
|
||||
/// when used with [MessageInputTheme] or with the overall [StreamChatTheme]'s
|
||||
/// [StreamChatThemeData.messageInputTheme].
|
||||
class MessageInputThemeData with Diagnosticable {
|
||||
/// Creates a [MessageInputThemeData].
|
||||
const MessageInputThemeData({
|
||||
this.sendAnimationDuration,
|
||||
this.actionButtonColor,
|
||||
this.sendButtonColor,
|
||||
this.actionButtonIdleColor,
|
||||
this.sendButtonIdleColor,
|
||||
this.inputBackgroundColor,
|
||||
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? inputBackgroundColor;
|
||||
|
||||
/// 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 [MessageInputThemeData] replacing some of its properties
|
||||
MessageInputThemeData copyWith({
|
||||
Duration? sendAnimationDuration,
|
||||
Color? inputBackgroundColor,
|
||||
Color? actionButtonColor,
|
||||
Color? sendButtonColor,
|
||||
Color? actionButtonIdleColor,
|
||||
Color? sendButtonIdleColor,
|
||||
Color? expandButtonColor,
|
||||
TextStyle? inputTextStyle,
|
||||
InputDecoration? inputDecoration,
|
||||
Gradient? activeBorderGradient,
|
||||
Gradient? idleBorderGradient,
|
||||
BorderRadius? borderRadius,
|
||||
}) =>
|
||||
MessageInputThemeData(
|
||||
sendAnimationDuration:
|
||||
sendAnimationDuration ?? this.sendAnimationDuration,
|
||||
inputBackgroundColor: inputBackgroundColor ?? this.inputBackgroundColor,
|
||||
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,
|
||||
);
|
||||
|
||||
/// Linearly interpolate from one [MessageInputThemeData] to another.
|
||||
MessageInputThemeData lerp(
|
||||
MessageInputThemeData a,
|
||||
MessageInputThemeData b,
|
||||
double t,
|
||||
) =>
|
||||
MessageInputThemeData(
|
||||
actionButtonColor:
|
||||
Color.lerp(a.actionButtonColor, b.actionButtonColor, t),
|
||||
actionButtonIdleColor:
|
||||
Color.lerp(a.actionButtonIdleColor, b.actionButtonIdleColor, t),
|
||||
activeBorderGradient:
|
||||
Gradient.lerp(a.activeBorderGradient, b.activeBorderGradient, t),
|
||||
borderRadius: BorderRadius.lerp(a.borderRadius, b.borderRadius, t),
|
||||
expandButtonColor:
|
||||
Color.lerp(a.expandButtonColor, b.expandButtonColor, t),
|
||||
idleBorderGradient:
|
||||
Gradient.lerp(a.idleBorderGradient, b.idleBorderGradient, t),
|
||||
inputBackgroundColor:
|
||||
Color.lerp(a.inputBackgroundColor, b.inputBackgroundColor, t),
|
||||
inputTextStyle: TextStyle.lerp(a.inputTextStyle, b.inputTextStyle, t),
|
||||
sendButtonColor: Color.lerp(a.sendButtonColor, b.sendButtonColor, t),
|
||||
sendButtonIdleColor:
|
||||
Color.lerp(a.sendButtonIdleColor, b.sendButtonIdleColor, t),
|
||||
sendAnimationDuration: a.sendAnimationDuration,
|
||||
inputDecoration: a.inputDecoration,
|
||||
);
|
||||
|
||||
/// Merges [this] [MessageInputThemeData] with the [other]
|
||||
MessageInputThemeData merge(MessageInputThemeData? other) {
|
||||
if (other == null) return this;
|
||||
return copyWith(
|
||||
sendAnimationDuration: other.sendAnimationDuration,
|
||||
inputBackgroundColor: other.inputBackgroundColor,
|
||||
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,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is MessageInputThemeData &&
|
||||
runtimeType == other.runtimeType &&
|
||||
sendAnimationDuration == other.sendAnimationDuration &&
|
||||
sendButtonColor == other.sendButtonColor &&
|
||||
actionButtonColor == other.actionButtonColor &&
|
||||
sendButtonIdleColor == other.sendButtonIdleColor &&
|
||||
actionButtonIdleColor == other.actionButtonIdleColor &&
|
||||
expandButtonColor == other.expandButtonColor &&
|
||||
inputBackgroundColor == other.inputBackgroundColor &&
|
||||
inputTextStyle == other.inputTextStyle &&
|
||||
inputDecoration == other.inputDecoration &&
|
||||
idleBorderGradient == other.idleBorderGradient &&
|
||||
activeBorderGradient == other.activeBorderGradient &&
|
||||
borderRadius == other.borderRadius;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
sendAnimationDuration.hashCode ^
|
||||
sendButtonColor.hashCode ^
|
||||
actionButtonColor.hashCode ^
|
||||
sendButtonIdleColor.hashCode ^
|
||||
actionButtonIdleColor.hashCode ^
|
||||
expandButtonColor.hashCode ^
|
||||
inputBackgroundColor.hashCode ^
|
||||
inputTextStyle.hashCode ^
|
||||
inputDecoration.hashCode ^
|
||||
idleBorderGradient.hashCode ^
|
||||
activeBorderGradient.hashCode ^
|
||||
borderRadius.hashCode;
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties
|
||||
..add(DiagnosticsProperty('sendAnimationDuration', sendAnimationDuration))
|
||||
..add(ColorProperty('inputBackgroundColor', inputBackgroundColor))
|
||||
..add(ColorProperty('actionButtonColor', actionButtonColor))
|
||||
..add(ColorProperty('actionButtonIdleColor', actionButtonIdleColor))
|
||||
..add(ColorProperty('sendButtonColor', sendButtonColor))
|
||||
..add(ColorProperty('sendButtonIdleColor', sendButtonIdleColor))
|
||||
..add(DiagnosticsProperty('inputTextStyle', inputTextStyle))
|
||||
..add(DiagnosticsProperty('inputDecoration', inputDecoration))
|
||||
..add(DiagnosticsProperty('activeBorderGradient', activeBorderGradient))
|
||||
..add(DiagnosticsProperty('idleBorderGradient', idleBorderGradient))
|
||||
..add(DiagnosticsProperty('borderRadius', borderRadius))
|
||||
..add(ColorProperty('expandButtonColor', expandButtonColor));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||
|
||||
/// Overrides the default style of [MessageListView] descendants.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [MessageListViewThemeData], which is used to configure this theme.
|
||||
class MessageListViewTheme extends InheritedTheme {
|
||||
/// Creates a [MessageListViewTheme].
|
||||
///
|
||||
/// The [data] parameter must not be null.
|
||||
const MessageListViewTheme({
|
||||
Key? key,
|
||||
required this.data,
|
||||
required Widget child,
|
||||
}) : super(key: key, child: child);
|
||||
|
||||
/// The configuration of this theme.
|
||||
final MessageListViewThemeData data;
|
||||
|
||||
/// The closest instance of this class that encloses the given context.
|
||||
///
|
||||
/// If there is no enclosing [MessageListViewTheme] widget, then
|
||||
/// [StreamChatThemeData.messageListViewTheme] is used.
|
||||
///
|
||||
/// Typical usage is as follows:
|
||||
///
|
||||
/// ```dart
|
||||
/// MessageListViewTheme theme = MessageListViewTheme.of(context);
|
||||
/// ```
|
||||
static MessageListViewThemeData of(BuildContext context) {
|
||||
final messageListViewTheme =
|
||||
context.dependOnInheritedWidgetOfExactType<MessageListViewTheme>();
|
||||
return messageListViewTheme?.data ??
|
||||
StreamChatTheme.of(context).messageListViewTheme;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget wrap(BuildContext context, Widget child) =>
|
||||
MessageListViewTheme(data: data, child: child);
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(MessageListViewTheme oldWidget) =>
|
||||
data != oldWidget.data;
|
||||
}
|
||||
|
||||
/// A style that overrides the default appearance of [MessageListView]s when
|
||||
/// used with [MessageListViewTheme] or with the overall [StreamChatTheme]'s
|
||||
/// [StreamChatThemeData.messageListViewTheme].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [MessageListViewTheme], the theme which is configured with this class.
|
||||
/// * [StreamChatThemeData.messageListViewTheme], which can be used to override
|
||||
/// the default style for [MessageListView]s below the overall
|
||||
/// [StreamChatTheme].
|
||||
class MessageListViewThemeData with Diagnosticable {
|
||||
/// Creates a [MessageListViewThemeData].
|
||||
const MessageListViewThemeData({
|
||||
this.backgroundColor,
|
||||
});
|
||||
|
||||
/// The color of the [MessageListView] background.
|
||||
final Color? backgroundColor;
|
||||
|
||||
/// Copies this [MessageListViewThemeData] to another.
|
||||
MessageListViewThemeData copyWith({
|
||||
Color? backgroundColor,
|
||||
}) =>
|
||||
MessageListViewThemeData(
|
||||
backgroundColor: backgroundColor ?? this.backgroundColor,
|
||||
);
|
||||
|
||||
/// Linearly interpolate between two [MessageListView] themes.
|
||||
///
|
||||
/// All the properties must be non-null.
|
||||
MessageListViewThemeData lerp(
|
||||
MessageListViewThemeData a,
|
||||
MessageListViewThemeData b,
|
||||
double t,
|
||||
) =>
|
||||
MessageListViewThemeData(
|
||||
backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
|
||||
);
|
||||
|
||||
/// Merges one [MessageListViewThemeData] with another.
|
||||
MessageListViewThemeData merge(MessageListViewThemeData? other) {
|
||||
if (other == null) return this;
|
||||
return copyWith(
|
||||
backgroundColor: other.backgroundColor,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is MessageListViewThemeData &&
|
||||
runtimeType == other.runtimeType &&
|
||||
backgroundColor == other.backgroundColor;
|
||||
|
||||
@override
|
||||
int get hashCode => backgroundColor.hashCode;
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties.add(ColorProperty('backgroundColor', backgroundColor));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||
|
||||
/// Overrides the default style of [MessageSearchListView] descendants.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [UserListViewThemeData], which is used to configure this theme.
|
||||
class MessageSearchListViewTheme extends InheritedTheme {
|
||||
/// Creates a [UserListViewTheme].
|
||||
///
|
||||
/// The [data] parameter must not be null.
|
||||
const MessageSearchListViewTheme({
|
||||
Key? key,
|
||||
required this.data,
|
||||
required Widget child,
|
||||
}) : super(key: key, child: child);
|
||||
|
||||
/// The configuration of this theme.
|
||||
final MessageSearchListViewThemeData data;
|
||||
|
||||
/// The closest instance of this class that encloses the given context.
|
||||
///
|
||||
/// If there is no enclosing [MessageSearchListView] widget, then
|
||||
/// [StreamChatThemeData.messageSearchListViewTheme] is used.
|
||||
///
|
||||
/// Typical usage is as follows:
|
||||
///
|
||||
/// ```dart
|
||||
/// MessageSearchListViewTheme theme = MessageSearchListViewTheme.of(context);
|
||||
/// ```
|
||||
static MessageSearchListViewThemeData of(BuildContext context) {
|
||||
final messageSearchListViewTheme = context
|
||||
.dependOnInheritedWidgetOfExactType<MessageSearchListViewTheme>();
|
||||
return messageSearchListViewTheme?.data ??
|
||||
StreamChatTheme.of(context).messageSearchListViewTheme;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget wrap(BuildContext context, Widget child) =>
|
||||
MessageSearchListViewTheme(data: data, child: child);
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(MessageSearchListViewTheme oldWidget) =>
|
||||
data != oldWidget.data;
|
||||
}
|
||||
|
||||
/// A style that overrides the default appearance of [MessageSearchListView]s
|
||||
/// when used with [MessageSearchListView] or with the overall
|
||||
/// [StreamChatTheme]'s [StreamChatThemeData.messageSearchListViewTheme].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [MessageSearchListViewTheme], the theme which is configured with this
|
||||
/// class.
|
||||
/// * [StreamChatThemeData.messageSearchListViewTheme], which can be used to
|
||||
/// override the default style for [UserListView]s below the overall
|
||||
/// [StreamChatTheme].
|
||||
class MessageSearchListViewThemeData with Diagnosticable {
|
||||
/// Creates a [MessageSearchListViewThemeData].
|
||||
const MessageSearchListViewThemeData({
|
||||
this.backgroundColor,
|
||||
});
|
||||
|
||||
/// The color of the [MessageSearchListView] background.
|
||||
final Color? backgroundColor;
|
||||
|
||||
/// Copies this [MessageSearchListViewThemeData] to another.
|
||||
MessageSearchListViewThemeData copyWith({
|
||||
Color? backgroundColor,
|
||||
}) =>
|
||||
MessageSearchListViewThemeData(
|
||||
backgroundColor: backgroundColor ?? this.backgroundColor,
|
||||
);
|
||||
|
||||
/// Linearly interpolate between two [UserListViewThemeData] themes.
|
||||
///
|
||||
/// All the properties must be non-null.
|
||||
MessageSearchListViewThemeData lerp(
|
||||
MessageSearchListViewThemeData a,
|
||||
MessageSearchListViewThemeData b,
|
||||
double t,
|
||||
) =>
|
||||
MessageSearchListViewThemeData(
|
||||
backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
|
||||
);
|
||||
|
||||
/// Merges one [MessageSearchListViewThemeData] with another.
|
||||
MessageSearchListViewThemeData merge(MessageSearchListViewThemeData? other) {
|
||||
if (other == null) return this;
|
||||
return copyWith(
|
||||
backgroundColor: other.backgroundColor,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is MessageSearchListViewThemeData &&
|
||||
runtimeType == other.runtimeType &&
|
||||
backgroundColor == other.backgroundColor;
|
||||
|
||||
@override
|
||||
int get hashCode => backgroundColor.hashCode;
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties.add(ColorProperty('backgroundColor', backgroundColor));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/src/theme/avatar_theme.dart';
|
||||
|
||||
/// Class for getting message theme
|
||||
class MessageThemeData with Diagnosticable {
|
||||
/// Creates a [MessageThemeData].
|
||||
const MessageThemeData({
|
||||
this.repliesStyle,
|
||||
this.messageTextStyle,
|
||||
this.messageAuthorStyle,
|
||||
this.messageLinksStyle,
|
||||
this.messageBackgroundColor,
|
||||
this.messageBorderColor,
|
||||
this.reactionsBackgroundColor,
|
||||
this.reactionsBorderColor,
|
||||
this.reactionsMaskColor,
|
||||
this.avatarTheme,
|
||||
this.createdAtStyle,
|
||||
});
|
||||
|
||||
/// Text style for message text
|
||||
final TextStyle? messageTextStyle;
|
||||
|
||||
/// Text style for message author
|
||||
final TextStyle? messageAuthorStyle;
|
||||
|
||||
/// Text style for message links
|
||||
final TextStyle? messageLinksStyle;
|
||||
|
||||
/// Text style for created at text
|
||||
final TextStyle? createdAtStyle;
|
||||
|
||||
/// Text style for replies
|
||||
final TextStyle? repliesStyle;
|
||||
|
||||
/// 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 AvatarThemeData? avatarTheme;
|
||||
|
||||
/// Copy with a theme
|
||||
MessageThemeData copyWith({
|
||||
TextStyle? messageTextStyle,
|
||||
TextStyle? messageAuthorStyle,
|
||||
TextStyle? messageLinksStyle,
|
||||
TextStyle? createdAtStyle,
|
||||
TextStyle? repliesStyle,
|
||||
Color? messageBackgroundColor,
|
||||
Color? messageBorderColor,
|
||||
AvatarThemeData? avatarTheme,
|
||||
Color? reactionsBackgroundColor,
|
||||
Color? reactionsBorderColor,
|
||||
Color? reactionsMaskColor,
|
||||
}) =>
|
||||
MessageThemeData(
|
||||
messageTextStyle: messageTextStyle ?? this.messageTextStyle,
|
||||
messageAuthorStyle: messageAuthorStyle ?? this.messageAuthorStyle,
|
||||
messageLinksStyle: messageLinksStyle ?? this.messageLinksStyle,
|
||||
createdAtStyle: createdAtStyle ?? this.createdAtStyle,
|
||||
messageBackgroundColor:
|
||||
messageBackgroundColor ?? this.messageBackgroundColor,
|
||||
messageBorderColor: messageBorderColor ?? this.messageBorderColor,
|
||||
avatarTheme: avatarTheme ?? this.avatarTheme,
|
||||
repliesStyle: repliesStyle ?? this.repliesStyle,
|
||||
reactionsBackgroundColor:
|
||||
reactionsBackgroundColor ?? this.reactionsBackgroundColor,
|
||||
reactionsBorderColor: reactionsBorderColor ?? this.reactionsBorderColor,
|
||||
reactionsMaskColor: reactionsMaskColor ?? this.reactionsMaskColor,
|
||||
);
|
||||
|
||||
/// Linearly interpolate from one [MessageThemeData] to another.
|
||||
MessageThemeData lerp(MessageThemeData a, MessageThemeData b, double t) =>
|
||||
MessageThemeData(
|
||||
avatarTheme:
|
||||
const AvatarThemeData().lerp(a.avatarTheme!, b.avatarTheme!, t),
|
||||
createdAtStyle: TextStyle.lerp(a.createdAtStyle, b.createdAtStyle, t),
|
||||
messageAuthorStyle:
|
||||
TextStyle.lerp(a.messageAuthorStyle, b.messageAuthorStyle, t),
|
||||
messageBackgroundColor:
|
||||
Color.lerp(a.messageBackgroundColor, b.messageBackgroundColor, t),
|
||||
messageBorderColor:
|
||||
Color.lerp(a.messageBorderColor, b.messageBorderColor, t),
|
||||
messageLinksStyle:
|
||||
TextStyle.lerp(a.messageLinksStyle, b.messageLinksStyle, t),
|
||||
messageTextStyle:
|
||||
TextStyle.lerp(a.messageTextStyle, b.messageTextStyle, t),
|
||||
reactionsBackgroundColor: Color.lerp(
|
||||
a.reactionsBackgroundColor, b.reactionsBackgroundColor, t),
|
||||
reactionsBorderColor:
|
||||
Color.lerp(a.messageBorderColor, b.reactionsBorderColor, t),
|
||||
reactionsMaskColor:
|
||||
Color.lerp(a.reactionsMaskColor, b.reactionsMaskColor, t),
|
||||
repliesStyle: TextStyle.lerp(a.repliesStyle, b.repliesStyle, t),
|
||||
);
|
||||
|
||||
/// Merge with a theme
|
||||
MessageThemeData merge(MessageThemeData? other) {
|
||||
if (other == null) return this;
|
||||
return copyWith(
|
||||
messageTextStyle: messageTextStyle?.merge(other.messageTextStyle) ??
|
||||
other.messageTextStyle,
|
||||
messageAuthorStyle: messageAuthorStyle?.merge(other.messageAuthorStyle) ??
|
||||
other.messageAuthorStyle,
|
||||
messageLinksStyle: messageLinksStyle?.merge(other.messageLinksStyle) ??
|
||||
other.messageLinksStyle,
|
||||
createdAtStyle:
|
||||
createdAtStyle?.merge(other.createdAtStyle) ?? other.createdAtStyle,
|
||||
repliesStyle:
|
||||
repliesStyle?.merge(other.repliesStyle) ?? other.repliesStyle,
|
||||
messageBackgroundColor: other.messageBackgroundColor,
|
||||
messageBorderColor: other.messageBorderColor,
|
||||
avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme,
|
||||
reactionsBackgroundColor: other.reactionsBackgroundColor,
|
||||
reactionsBorderColor: other.reactionsBorderColor,
|
||||
reactionsMaskColor: other.reactionsMaskColor,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is MessageThemeData &&
|
||||
runtimeType == other.runtimeType &&
|
||||
messageTextStyle == other.messageTextStyle &&
|
||||
messageAuthorStyle == other.messageAuthorStyle &&
|
||||
messageLinksStyle == other.messageLinksStyle &&
|
||||
createdAtStyle == other.createdAtStyle &&
|
||||
repliesStyle == other.repliesStyle &&
|
||||
messageBackgroundColor == other.messageBackgroundColor &&
|
||||
messageBorderColor == other.messageBorderColor &&
|
||||
reactionsBackgroundColor == other.reactionsBackgroundColor &&
|
||||
reactionsBorderColor == other.reactionsBorderColor &&
|
||||
reactionsMaskColor == other.reactionsMaskColor &&
|
||||
avatarTheme == other.avatarTheme;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
messageTextStyle.hashCode ^
|
||||
messageAuthorStyle.hashCode ^
|
||||
messageLinksStyle.hashCode ^
|
||||
createdAtStyle.hashCode ^
|
||||
repliesStyle.hashCode ^
|
||||
messageBackgroundColor.hashCode ^
|
||||
messageBorderColor.hashCode ^
|
||||
reactionsBackgroundColor.hashCode ^
|
||||
reactionsBorderColor.hashCode ^
|
||||
reactionsMaskColor.hashCode ^
|
||||
avatarTheme.hashCode;
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties
|
||||
..add(DiagnosticsProperty('messageTextStyle', messageTextStyle))
|
||||
..add(DiagnosticsProperty('messageAuthorStyle', messageAuthorStyle))
|
||||
..add(DiagnosticsProperty('messageLinksStyle', messageLinksStyle))
|
||||
..add(DiagnosticsProperty('createdAtStyle', createdAtStyle))
|
||||
..add(DiagnosticsProperty('repliesStyle', repliesStyle))
|
||||
..add(ColorProperty('messageBackgroundColor', messageBackgroundColor))
|
||||
..add(ColorProperty('messageBorderColor', messageBorderColor))
|
||||
..add(DiagnosticsProperty('avatarTheme', avatarTheme))
|
||||
..add(ColorProperty('reactionsBackgroundColor', reactionsBackgroundColor))
|
||||
..add(ColorProperty('reactionsBorderColor', reactionsBorderColor))
|
||||
..add(ColorProperty('reactionsMaskColor', reactionsMaskColor));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
/// 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),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
export 'avatar_theme.dart';
|
||||
export 'channel_header_theme.dart';
|
||||
export 'channel_list_header_theme.dart';
|
||||
export 'channel_list_view_theme.dart';
|
||||
export 'channel_preview_theme.dart';
|
||||
export 'color_theme.dart';
|
||||
export 'gallery_footer_theme.dart';
|
||||
export 'gallery_header_theme.dart';
|
||||
export 'message_input_theme.dart';
|
||||
export 'message_list_view_theme.dart';
|
||||
export 'message_search_list_view_theme.dart';
|
||||
export 'message_theme.dart';
|
||||
export 'text_theme.dart';
|
||||
export 'user_list_view_theme.dart';
|
||||
@@ -0,0 +1,111 @@
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:stream_chat_flutter/src/stream_chat_theme.dart';
|
||||
|
||||
/// Overrides the default style of [UserListView] descendants.
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [UserListViewThemeData], which is used to configure this theme.
|
||||
class UserListViewTheme extends InheritedTheme {
|
||||
/// Creates a [UserListViewTheme].
|
||||
///
|
||||
/// The [data] parameter must not be null.
|
||||
const UserListViewTheme({
|
||||
Key? key,
|
||||
required this.data,
|
||||
required Widget child,
|
||||
}) : super(key: key, child: child);
|
||||
|
||||
/// The configuration of this theme.
|
||||
final UserListViewThemeData data;
|
||||
|
||||
/// The closest instance of this class that encloses the given context.
|
||||
///
|
||||
/// If there is no enclosing [UserListViewTheme] widget, then
|
||||
/// [StreamChatThemeData.userListViewTheme] is used.
|
||||
///
|
||||
/// Typical usage is as follows:
|
||||
///
|
||||
/// ```dart
|
||||
/// UserListViewTheme theme = UserListViewTheme.of(context);
|
||||
/// ```
|
||||
static UserListViewThemeData of(BuildContext context) {
|
||||
final userListViewTheme =
|
||||
context.dependOnInheritedWidgetOfExactType<UserListViewTheme>();
|
||||
return userListViewTheme?.data ??
|
||||
StreamChatTheme.of(context).userListViewTheme;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget wrap(BuildContext context, Widget child) =>
|
||||
UserListViewTheme(data: data, child: child);
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(UserListViewTheme oldWidget) =>
|
||||
data != oldWidget.data;
|
||||
}
|
||||
|
||||
/// A style that overrides the default appearance of [UserListView]s when
|
||||
/// used with [UserListViewTheme] or with the overall [StreamChatTheme]'s
|
||||
/// [StreamChatThemeData.userListViewTheme].
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [UserListViewTheme], the theme which is configured with this class.
|
||||
/// * [StreamChatThemeData.userListViewTheme], which can be used to override
|
||||
/// the default style for [UserListView]s below the overall
|
||||
/// [StreamChatTheme].
|
||||
class UserListViewThemeData with Diagnosticable {
|
||||
/// Creates a [UserListViewThemeData].
|
||||
const UserListViewThemeData({
|
||||
this.backgroundColor,
|
||||
});
|
||||
|
||||
/// The color of the [ChannelListView] background.
|
||||
final Color? backgroundColor;
|
||||
|
||||
/// Copies this [ChannelListViewThemeData] to another.
|
||||
UserListViewThemeData copyWith({
|
||||
Color? backgroundColor,
|
||||
}) =>
|
||||
UserListViewThemeData(
|
||||
backgroundColor: backgroundColor ?? this.backgroundColor,
|
||||
);
|
||||
|
||||
/// Linearly interpolate between two [UserListViewThemeData] themes.
|
||||
///
|
||||
/// All the properties must be non-null.
|
||||
UserListViewThemeData lerp(
|
||||
UserListViewThemeData a,
|
||||
UserListViewThemeData b,
|
||||
double t,
|
||||
) =>
|
||||
UserListViewThemeData(
|
||||
backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
|
||||
);
|
||||
|
||||
/// Merges one [UserListViewThemeData] with another.
|
||||
UserListViewThemeData merge(UserListViewThemeData? other) {
|
||||
if (other == null) return this;
|
||||
return copyWith(
|
||||
backgroundColor: other.backgroundColor,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is UserListViewThemeData &&
|
||||
runtimeType == other.runtimeType &&
|
||||
backgroundColor == other.backgroundColor;
|
||||
|
||||
@override
|
||||
int get hashCode => backgroundColor.hashCode;
|
||||
|
||||
@override
|
||||
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
|
||||
super.debugFillProperties(properties);
|
||||
properties.add(ColorProperty('backgroundColor', backgroundColor));
|
||||
}
|
||||
}
|
||||
@@ -104,7 +104,7 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final chatThemeData = StreamChatTheme.of(context);
|
||||
final channelHeaderTheme = ChannelHeaderTheme.of(context);
|
||||
|
||||
final defaultSubtitle = subtitle ??
|
||||
Row(
|
||||
@@ -113,12 +113,11 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
children: [
|
||||
Text(
|
||||
'${context.translations.withText} ',
|
||||
style: chatThemeData.channelTheme.channelHeaderTheme.subtitle,
|
||||
style: channelHeaderTheme.subtitleStyle,
|
||||
),
|
||||
Flexible(
|
||||
child: ChannelName(
|
||||
textStyle:
|
||||
chatThemeData.channelTheme.channelHeaderTheme.subtitle,
|
||||
textStyle: channelHeaderTheme.subtitleStyle,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -137,7 +136,7 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
showUnreads: true,
|
||||
)
|
||||
: const SizedBox()),
|
||||
backgroundColor: chatThemeData.channelTheme.channelHeaderTheme.color,
|
||||
backgroundColor: channelHeaderTheme.color,
|
||||
centerTitle: true,
|
||||
actions: actions,
|
||||
title: InkWell(
|
||||
@@ -151,14 +150,14 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||
title ??
|
||||
Text(
|
||||
context.translations.threadReplyLabel,
|
||||
style: chatThemeData.channelTheme.channelHeaderTheme.title,
|
||||
style: channelHeaderTheme.titleStyle,
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
if (showTypingIndicator)
|
||||
TypingIndicator(
|
||||
alignment: Alignment.center,
|
||||
channel: StreamChannel.of(context).channel,
|
||||
style: chatThemeData.channelTheme.channelHeaderTheme.subtitle,
|
||||
style: channelHeaderTheme.subtitleStyle,
|
||||
parentId: parent.id,
|
||||
alternativeWidget: defaultSubtitle,
|
||||
)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:stream_chat_flutter/src/theme/themes.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';
|
||||
|
||||
@@ -36,13 +36,12 @@ export 'src/stream_chat_theme.dart';
|
||||
export 'src/stream_neumorphic_button.dart';
|
||||
export 'src/stream_svg_icon.dart';
|
||||
export 'src/system_message.dart';
|
||||
export 'src/theme/themes.dart';
|
||||
export 'src/thread_header.dart';
|
||||
export 'src/typing_indicator.dart';
|
||||
export 'src/unread_indicator.dart';
|
||||
export 'src/user_avatar.dart';
|
||||
export 'src/user_item.dart';
|
||||
export 'src/user_item.dart';
|
||||
export 'src/user_list_view.dart';
|
||||
export 'src/user_list_view.dart';
|
||||
export 'src/utils.dart';
|
||||
export 'src/visible_footnote.dart';
|
||||
|
||||
@@ -21,11 +21,11 @@ void main() {
|
||||
client: client,
|
||||
child: const Scaffold(
|
||||
body: DeletedMessage(
|
||||
messageTheme: MessageTheme(
|
||||
createdAt: TextStyle(
|
||||
messageTheme: MessageThemeData(
|
||||
createdAtStyle: TextStyle(
|
||||
color: Colors.black,
|
||||
),
|
||||
messageText: TextStyle(),
|
||||
messageTextStyle: TextStyle(),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -84,7 +84,7 @@ void main() {
|
||||
final clientState = MockClientState();
|
||||
final channel = MockChannel();
|
||||
final channelState = MockChannelState();
|
||||
const messageTheme = MessageTheme();
|
||||
const messageTheme = MessageThemeData();
|
||||
|
||||
final currentUser = OwnUser(
|
||||
id: 'sahil',
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
void main() {
|
||||
test('AvatarThemeData copyWith, ==, hashCode basics', () {
|
||||
expect(const AvatarThemeData(), const AvatarThemeData().copyWith());
|
||||
expect(const AvatarThemeData().hashCode,
|
||||
const AvatarThemeData().copyWith().hashCode);
|
||||
});
|
||||
|
||||
group('AvatarThemeData lerps correctly', () {
|
||||
test('Lerp completely', () {
|
||||
expect(
|
||||
const AvatarThemeData()
|
||||
.lerp(_avatarThemeDataControl1, _avatarThemeDataControl2, 1),
|
||||
_avatarThemeDataControl2);
|
||||
});
|
||||
|
||||
test('Lerp halfway', () {
|
||||
expect(
|
||||
const AvatarThemeData()
|
||||
.lerp(_avatarThemeDataControl1, _avatarThemeDataControl2, 0.5),
|
||||
_avatarThemeDataControlMidLerp);
|
||||
});
|
||||
});
|
||||
|
||||
test('Merging two AvatarThemeData results in the latter', () {
|
||||
expect(_avatarThemeDataControl1.merge(_avatarThemeDataControl2),
|
||||
_avatarThemeDataControl2);
|
||||
});
|
||||
}
|
||||
|
||||
const _avatarThemeDataControl1 = AvatarThemeData();
|
||||
|
||||
final _avatarThemeDataControlMidLerp = AvatarThemeData(
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
constraints: const BoxConstraints.tightFor(
|
||||
height: 33,
|
||||
width: 33,
|
||||
),
|
||||
);
|
||||
|
||||
final _avatarThemeDataControl2 = AvatarThemeData(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
constraints: const BoxConstraints.tightFor(
|
||||
height: 34,
|
||||
width: 34,
|
||||
),
|
||||
);
|
||||
@@ -0,0 +1,97 @@
|
||||
import 'package:flutter/material.dart' hide TextTheme;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
void main() {
|
||||
test('ChannelHeaderThemeData copyWith, ==, hashCode basics', () {
|
||||
expect(const ChannelHeaderThemeData(),
|
||||
const ChannelHeaderThemeData().copyWith());
|
||||
expect(const ChannelHeaderThemeData().hashCode,
|
||||
const ChannelHeaderThemeData().copyWith().hashCode);
|
||||
});
|
||||
|
||||
group('ChannelHeaderThemeData lerps', () {
|
||||
test(
|
||||
'''Light ChannelHeaderThemeData lerps completely to dark ChannelHeaderThemeData''',
|
||||
() {
|
||||
expect(
|
||||
const ChannelHeaderThemeData()
|
||||
.lerp(_channelThemeControl, _channelThemeControlDark, 1),
|
||||
_channelThemeControlDark);
|
||||
});
|
||||
|
||||
test(
|
||||
'''Light ChannelHeaderThemeData lerps halfway to dark ChannelHeaderThemeData''',
|
||||
() {
|
||||
expect(
|
||||
const ChannelHeaderThemeData()
|
||||
.lerp(_channelThemeControl, _channelThemeControlDark, 0.5),
|
||||
_channelThemeControlMidLerp);
|
||||
});
|
||||
|
||||
test(
|
||||
'''Dark ChannelHeaderThemeData lerps completely to light ChannelHeaderThemeData''',
|
||||
() {
|
||||
expect(
|
||||
const ChannelHeaderThemeData()
|
||||
.lerp(_channelThemeControlDark, _channelThemeControl, 1),
|
||||
_channelThemeControl);
|
||||
});
|
||||
});
|
||||
|
||||
test('Merging dark and light themes results in a dark theme', () {
|
||||
expect(_channelThemeControl.merge(_channelThemeControlDark),
|
||||
_channelThemeControlDark);
|
||||
});
|
||||
}
|
||||
|
||||
final _channelThemeControl = ChannelHeaderThemeData(
|
||||
avatarTheme: AvatarThemeData(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
constraints: const BoxConstraints.tightFor(
|
||||
height: 40,
|
||||
width: 40,
|
||||
),
|
||||
),
|
||||
color: const Color(0xff101418),
|
||||
titleStyle: TextTheme.light().headlineBold.copyWith(
|
||||
color: const Color(0xffffffff),
|
||||
),
|
||||
subtitleStyle: TextTheme.light().footnote.copyWith(
|
||||
color: const Color(0xff7a7a7a),
|
||||
),
|
||||
);
|
||||
|
||||
final _channelThemeControlMidLerp = ChannelHeaderThemeData(
|
||||
avatarTheme: AvatarThemeData(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
constraints: const BoxConstraints.tightFor(
|
||||
height: 40,
|
||||
width: 40,
|
||||
),
|
||||
),
|
||||
color: const Color(0xff101418),
|
||||
titleStyle: const TextStyle(
|
||||
color: Color(0xffffffff),
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
),
|
||||
subtitleStyle: TextTheme.light().footnote.copyWith(
|
||||
color: const Color(0xff7a7a7a),
|
||||
),
|
||||
);
|
||||
|
||||
final _channelThemeControlDark = ChannelHeaderThemeData(
|
||||
avatarTheme: AvatarThemeData(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
constraints: const BoxConstraints.tightFor(
|
||||
height: 40,
|
||||
width: 40,
|
||||
),
|
||||
),
|
||||
color: ColorTheme.dark().barsBg,
|
||||
titleStyle: TextTheme.dark().headlineBold,
|
||||
subtitleStyle: TextTheme.dark().footnote.copyWith(
|
||||
color: const Color(0xff7A7A7A),
|
||||
),
|
||||
);
|
||||
@@ -0,0 +1,94 @@
|
||||
import 'package:flutter/material.dart' hide TextTheme;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
void main() {
|
||||
test('ChannelListHeaderThemeData copyWith, ==, hashCode basics', () {
|
||||
expect(const ChannelListHeaderThemeData(),
|
||||
const ChannelListHeaderThemeData().copyWith());
|
||||
expect(const ChannelListHeaderThemeData().hashCode,
|
||||
const ChannelListHeaderThemeData().copyWith().hashCode);
|
||||
});
|
||||
|
||||
group('ChannelListHeaderThemeData lerps', () {
|
||||
test(
|
||||
'''Light ChannelListHeaderThemeData lerps completely to dark ChannelListHeaderThemeData''',
|
||||
() {
|
||||
expect(
|
||||
const ChannelListHeaderThemeData().lerp(
|
||||
_channelListHeaderThemeControl,
|
||||
_channelListHeaderThemeControlDark,
|
||||
1),
|
||||
_channelListHeaderThemeControlDark);
|
||||
});
|
||||
|
||||
test(
|
||||
'''Light ChannelListHeaderThemeData lerps halfway to dark ChannelListHeaderThemeData''',
|
||||
() {
|
||||
expect(
|
||||
const ChannelListHeaderThemeData().lerp(
|
||||
_channelListHeaderThemeControl,
|
||||
_channelListHeaderThemeControlDark,
|
||||
0.5),
|
||||
_channelListHeaderThemeControlMidLerp);
|
||||
});
|
||||
|
||||
test(
|
||||
'''Dark ChannelListHeaderThemeData lerps completely to light ChannelListHeaderThemeData''',
|
||||
() {
|
||||
expect(
|
||||
const ChannelListHeaderThemeData().lerp(
|
||||
_channelListHeaderThemeControlDark,
|
||||
_channelListHeaderThemeControl,
|
||||
1),
|
||||
_channelListHeaderThemeControl);
|
||||
});
|
||||
});
|
||||
|
||||
test('Merging dark and light themes results in a dark theme', () {
|
||||
expect(
|
||||
_channelListHeaderThemeControl
|
||||
.merge(_channelListHeaderThemeControlDark),
|
||||
_channelListHeaderThemeControlDark);
|
||||
});
|
||||
}
|
||||
|
||||
final _channelListHeaderThemeControl = ChannelListHeaderThemeData(
|
||||
avatarTheme: AvatarThemeData(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
constraints: const BoxConstraints.tightFor(
|
||||
height: 40,
|
||||
width: 40,
|
||||
),
|
||||
),
|
||||
color: ColorTheme.light().barsBg,
|
||||
titleStyle: TextTheme.light().headlineBold,
|
||||
);
|
||||
|
||||
final _channelListHeaderThemeControlMidLerp = ChannelListHeaderThemeData(
|
||||
avatarTheme: AvatarThemeData(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
constraints: const BoxConstraints.tightFor(
|
||||
height: 40,
|
||||
width: 40,
|
||||
),
|
||||
),
|
||||
color: const Color(0xff87898b),
|
||||
titleStyle: const TextStyle(
|
||||
color: Color(0xff7f7f7f),
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
);
|
||||
|
||||
final _channelListHeaderThemeControlDark = ChannelListHeaderThemeData(
|
||||
avatarTheme: AvatarThemeData(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
constraints: const BoxConstraints.tightFor(
|
||||
height: 40,
|
||||
width: 40,
|
||||
),
|
||||
),
|
||||
color: ColorTheme.dark().barsBg,
|
||||
titleStyle: TextTheme.dark().headlineBold,
|
||||
);
|
||||
+1
-1
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
import 'mocks.dart';
|
||||
import '../mocks.dart';
|
||||
|
||||
void main() {
|
||||
test('ChannelListViewThemeData copyWith, ==, hashCode basics', () {
|
||||
@@ -0,0 +1,108 @@
|
||||
import 'package:flutter/material.dart' hide TextTheme;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
void main() {
|
||||
test('ChannelPreviewThemeData copyWith, ==, hashCode basics', () {
|
||||
expect(const ChannelPreviewThemeData(),
|
||||
const ChannelPreviewThemeData().copyWith());
|
||||
expect(const ChannelPreviewThemeData().hashCode,
|
||||
const ChannelPreviewThemeData().copyWith().hashCode);
|
||||
});
|
||||
|
||||
group('ChannelPreviewThemeData lerps', () {
|
||||
test(
|
||||
'''Light ChannelPreviewThemeData lerps completely to dark ChannelPreviewThemeData''',
|
||||
() {
|
||||
expect(
|
||||
const ChannelPreviewThemeData().lerp(
|
||||
_channelPreviewThemeControl, _channelPreviewThemeControlDark, 1),
|
||||
_channelPreviewThemeControlDark);
|
||||
});
|
||||
|
||||
test(
|
||||
'''Light ChannelPreviewThemeData lerps halfway to dark ChannelPreviewThemeData''',
|
||||
() {
|
||||
expect(
|
||||
const ChannelPreviewThemeData().lerp(_channelPreviewThemeControl,
|
||||
_channelPreviewThemeControlDark, 0.5),
|
||||
_channelPreviewThemeControlMidLerp);
|
||||
});
|
||||
|
||||
test(
|
||||
'''Dark ChannelPreviewThemeData lerps completely to light ChannelPreviewThemeData''',
|
||||
() {
|
||||
expect(
|
||||
const ChannelPreviewThemeData().lerp(
|
||||
_channelPreviewThemeControlDark, _channelPreviewThemeControl, 1),
|
||||
_channelPreviewThemeControl);
|
||||
});
|
||||
});
|
||||
|
||||
test('Merging dark and light themes results in a dark theme', () {
|
||||
expect(_channelPreviewThemeControl.merge(_channelPreviewThemeControlDark),
|
||||
_channelPreviewThemeControlDark);
|
||||
});
|
||||
}
|
||||
|
||||
final _channelPreviewThemeControl = ChannelPreviewThemeData(
|
||||
unreadCounterColor: ColorTheme.light().accentError,
|
||||
avatarTheme: AvatarThemeData(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
constraints: const BoxConstraints.tightFor(
|
||||
height: 40,
|
||||
width: 40,
|
||||
),
|
||||
),
|
||||
titleStyle: TextTheme.light().bodyBold,
|
||||
subtitleStyle: TextTheme.light().footnote.copyWith(
|
||||
color: const Color(0xff7A7A7A),
|
||||
),
|
||||
lastMessageAtStyle: TextTheme.light().footnote.copyWith(
|
||||
color: ColorTheme.light().textHighEmphasis.withOpacity(.5),
|
||||
),
|
||||
indicatorIconSize: 16,
|
||||
);
|
||||
|
||||
final _channelPreviewThemeControlMidLerp = ChannelPreviewThemeData(
|
||||
unreadCounterColor: const Color(0xffff3742),
|
||||
avatarTheme: AvatarThemeData(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
constraints: const BoxConstraints.tightFor(
|
||||
height: 40,
|
||||
width: 40,
|
||||
),
|
||||
),
|
||||
titleStyle: const TextStyle(
|
||||
color: Color(0xff7f7f7f),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
subtitleStyle: const TextStyle(
|
||||
color: Color(0xff7a7a7a),
|
||||
fontSize: 12,
|
||||
),
|
||||
lastMessageAtStyle: TextTheme.light().footnote.copyWith(
|
||||
color: const Color(0x807f7f7f).withOpacity(.5),
|
||||
),
|
||||
indicatorIconSize: 16,
|
||||
);
|
||||
|
||||
final _channelPreviewThemeControlDark = ChannelPreviewThemeData(
|
||||
unreadCounterColor: ColorTheme.dark().accentError,
|
||||
avatarTheme: AvatarThemeData(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
constraints: const BoxConstraints.tightFor(
|
||||
height: 40,
|
||||
width: 40,
|
||||
),
|
||||
),
|
||||
titleStyle: TextTheme.dark().bodyBold,
|
||||
subtitleStyle: TextTheme.dark().footnote.copyWith(
|
||||
color: const Color(0xff7A7A7A),
|
||||
),
|
||||
lastMessageAtStyle: TextTheme.dark().footnote.copyWith(
|
||||
color: ColorTheme.dark().textHighEmphasis.withOpacity(.5),
|
||||
),
|
||||
indicatorIconSize: 16,
|
||||
);
|
||||
@@ -0,0 +1,122 @@
|
||||
import 'package:flutter/material.dart' hide TextTheme;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
void main() {
|
||||
test('MessageInputThemeData copyWith, ==, hashCode basics', () {
|
||||
expect(const MessageInputThemeData(),
|
||||
const MessageInputThemeData().copyWith());
|
||||
expect(const MessageInputThemeData().hashCode,
|
||||
const MessageInputThemeData().copyWith().hashCode);
|
||||
});
|
||||
|
||||
group('MessageInputThemeData lerps correctly', () {
|
||||
test('Lerp completely from light to dark', () {
|
||||
expect(
|
||||
const MessageInputThemeData().lerp(
|
||||
_messageInputThemeControl, _messageInputThemeControlDark, 1),
|
||||
_messageInputThemeControlDark);
|
||||
});
|
||||
|
||||
test('Lerp halfway from light to dark', () {
|
||||
expect(
|
||||
const MessageInputThemeData().lerp(
|
||||
_messageInputThemeControl, _messageInputThemeControlDark, 0.5),
|
||||
_messageInputThemeControlMidLerp);
|
||||
});
|
||||
|
||||
test('Lerp completely from dark to light', () {
|
||||
expect(
|
||||
const MessageInputThemeData().lerp(
|
||||
_messageInputThemeControlDark, _messageInputThemeControl, 1),
|
||||
_messageInputThemeControl);
|
||||
});
|
||||
});
|
||||
|
||||
test('Merging two MessageInputThemeData results in the latter', () {
|
||||
expect(_messageInputThemeControl.merge(_messageInputThemeControlDark),
|
||||
_messageInputThemeControlDark);
|
||||
});
|
||||
}
|
||||
|
||||
final _messageInputThemeControl = MessageInputThemeData(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
sendAnimationDuration: const Duration(milliseconds: 300),
|
||||
actionButtonColor: ColorTheme.light().accentPrimary,
|
||||
actionButtonIdleColor: ColorTheme.light().textLowEmphasis,
|
||||
expandButtonColor: ColorTheme.light().accentPrimary,
|
||||
sendButtonColor: ColorTheme.light().accentPrimary,
|
||||
sendButtonIdleColor: ColorTheme.light().disabled,
|
||||
inputBackgroundColor: ColorTheme.light().barsBg,
|
||||
inputTextStyle: TextTheme.light().body,
|
||||
idleBorderGradient: LinearGradient(
|
||||
stops: const [0.0, 1.0],
|
||||
colors: [
|
||||
ColorTheme.light().disabled,
|
||||
ColorTheme.light().disabled,
|
||||
],
|
||||
),
|
||||
activeBorderGradient: LinearGradient(
|
||||
stops: const [0.0, 1.0],
|
||||
colors: [
|
||||
ColorTheme.light().disabled,
|
||||
ColorTheme.light().disabled,
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
final _messageInputThemeControlMidLerp = MessageInputThemeData(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
sendAnimationDuration: const Duration(milliseconds: 300),
|
||||
inputBackgroundColor: const Color(0xff87898b),
|
||||
actionButtonColor: const Color(0xff005fff),
|
||||
actionButtonIdleColor: const Color(0xff7a7a7a),
|
||||
sendButtonColor: const Color(0xff005fff),
|
||||
sendButtonIdleColor: const Color(0xff848585),
|
||||
expandButtonColor: const Color(0xff005fff),
|
||||
inputTextStyle: const TextStyle(
|
||||
color: Color(0xff7f7f7f),
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
idleBorderGradient: const LinearGradient(
|
||||
stops: [0.0, 1.0],
|
||||
colors: [
|
||||
Color(0xff848585),
|
||||
Color(0xff848585),
|
||||
],
|
||||
),
|
||||
activeBorderGradient: const LinearGradient(
|
||||
stops: [0.0, 1.0],
|
||||
colors: [
|
||||
Color(0xff848585),
|
||||
Color(0xff848585),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
final _messageInputThemeControlDark = MessageInputThemeData(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
sendAnimationDuration: const Duration(milliseconds: 300),
|
||||
actionButtonColor: ColorTheme.dark().accentPrimary,
|
||||
actionButtonIdleColor: ColorTheme.dark().textLowEmphasis,
|
||||
expandButtonColor: ColorTheme.dark().accentPrimary,
|
||||
sendButtonColor: ColorTheme.dark().accentPrimary,
|
||||
sendButtonIdleColor: ColorTheme.dark().disabled,
|
||||
inputBackgroundColor: ColorTheme.dark().barsBg,
|
||||
inputTextStyle: TextTheme.dark().body,
|
||||
idleBorderGradient: LinearGradient(
|
||||
stops: const [0.0, 1.0],
|
||||
colors: [
|
||||
ColorTheme.dark().disabled,
|
||||
ColorTheme.dark().disabled,
|
||||
],
|
||||
),
|
||||
activeBorderGradient: LinearGradient(
|
||||
stops: const [0.0, 1.0],
|
||||
colors: [
|
||||
ColorTheme.dark().disabled,
|
||||
ColorTheme.dark().disabled,
|
||||
],
|
||||
),
|
||||
);
|
||||
+1
-1
@@ -3,7 +3,7 @@ import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:mocktail/mocktail.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
import 'mocks.dart';
|
||||
import '../mocks.dart';
|
||||
|
||||
class MockStreamChatClient extends Mock implements StreamChatClient {}
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
import 'mocks.dart';
|
||||
import '../mocks.dart';
|
||||
|
||||
void main() {
|
||||
test('MessageSearchListViewThemeData copyWith, ==, hashCode basics', () {
|
||||
@@ -0,0 +1,90 @@
|
||||
import 'package:flutter/material.dart' hide TextTheme;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
void main() {
|
||||
test('MessageThemeData copyWith, ==, hashCode basics', () {
|
||||
expect(const MessageThemeData(), const MessageThemeData().copyWith());
|
||||
expect(const MessageThemeData().hashCode,
|
||||
const MessageThemeData().copyWith().hashCode);
|
||||
});
|
||||
|
||||
group('MessageThemeData lerps', () {
|
||||
test('''Light MessageThemeData lerps completely to dark MessageThemeData''',
|
||||
() {
|
||||
expect(
|
||||
const MessageThemeData()
|
||||
.lerp(_messageThemeControl, _messageThemeControlDark, 1),
|
||||
_messageThemeControlDark);
|
||||
});
|
||||
|
||||
test('''Dark MessageThemeData lerps completely to light MessageThemeData''',
|
||||
() {
|
||||
expect(
|
||||
const MessageThemeData()
|
||||
.lerp(_messageThemeControlDark, _messageThemeControl, 1),
|
||||
_messageThemeControl);
|
||||
});
|
||||
});
|
||||
|
||||
test('Merging dark and light themes results in a dark theme', () {
|
||||
expect(_messageThemeControl.merge(_messageThemeControlDark),
|
||||
_messageThemeControlDark);
|
||||
});
|
||||
}
|
||||
|
||||
final _messageThemeControl = MessageThemeData(
|
||||
messageAuthorStyle: TextTheme.light().footnote.copyWith(
|
||||
color: ColorTheme.light().textLowEmphasis,
|
||||
),
|
||||
messageTextStyle: TextTheme.light().body,
|
||||
createdAtStyle: TextTheme.light().footnote.copyWith(
|
||||
color: ColorTheme.light().textLowEmphasis,
|
||||
),
|
||||
repliesStyle: TextTheme.light().footnoteBold.copyWith(
|
||||
color: ColorTheme.light().accentPrimary,
|
||||
),
|
||||
messageBackgroundColor: ColorTheme.light().disabled,
|
||||
reactionsBackgroundColor: ColorTheme.light().barsBg,
|
||||
reactionsBorderColor: ColorTheme.light().borders,
|
||||
reactionsMaskColor: ColorTheme.light().appBg,
|
||||
messageBorderColor: ColorTheme.light().disabled,
|
||||
avatarTheme: AvatarThemeData(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
constraints: const BoxConstraints.tightFor(
|
||||
height: 32,
|
||||
width: 32,
|
||||
),
|
||||
),
|
||||
messageLinksStyle: TextStyle(
|
||||
color: ColorTheme.light().accentPrimary,
|
||||
),
|
||||
);
|
||||
|
||||
final _messageThemeControlDark = MessageThemeData(
|
||||
messageAuthorStyle: TextTheme.dark().footnote.copyWith(
|
||||
color: ColorTheme.dark().textLowEmphasis,
|
||||
),
|
||||
messageTextStyle: TextTheme.dark().body,
|
||||
createdAtStyle: TextTheme.dark().footnote.copyWith(
|
||||
color: ColorTheme.dark().textLowEmphasis,
|
||||
),
|
||||
repliesStyle: TextTheme.dark().footnoteBold.copyWith(
|
||||
color: ColorTheme.dark().accentPrimary,
|
||||
),
|
||||
messageBackgroundColor: ColorTheme.dark().disabled,
|
||||
reactionsBackgroundColor: ColorTheme.dark().barsBg,
|
||||
reactionsBorderColor: ColorTheme.dark().borders,
|
||||
reactionsMaskColor: ColorTheme.dark().appBg,
|
||||
messageBorderColor: ColorTheme.dark().disabled,
|
||||
avatarTheme: AvatarThemeData(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
constraints: const BoxConstraints.tightFor(
|
||||
height: 32,
|
||||
width: 32,
|
||||
),
|
||||
),
|
||||
messageLinksStyle: TextStyle(
|
||||
color: ColorTheme.dark().accentPrimary,
|
||||
),
|
||||
);
|
||||
+1
-1
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||
|
||||
import 'mocks.dart';
|
||||
import '../mocks.dart';
|
||||
|
||||
void main() {
|
||||
test('UserListViewThemeData copyWith, ==, hashCode basics', () {
|
||||
Reference in New Issue
Block a user