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
|
## 2.1.2
|
||||||
|
|
||||||
🐞 Fixed
|
🐞 Fixed
|
||||||
@@ -531,6 +549,7 @@ Widget build(BuildContext context) {
|
|||||||
},
|
},
|
||||||
home: ChannelListPage(),
|
home: ChannelListPage(),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- Fix reaction bubble going below previous message on iOS
|
- Fix reaction bubble going below previous message on iOS
|
||||||
|
|||||||
@@ -118,13 +118,12 @@ class ChannelListPage extends StatelessWidget {
|
|||||||
channel: channel,
|
channel: channel,
|
||||||
),
|
),
|
||||||
title: ChannelName(
|
title: ChannelName(
|
||||||
textStyle:
|
textStyle: ChannelPreviewTheme.of(context).titleStyle!.copyWith(
|
||||||
StreamChatTheme.of(context).channelPreviewTheme.title!.copyWith(
|
color: StreamChatTheme.of(context)
|
||||||
color: StreamChatTheme.of(context)
|
.colorTheme
|
||||||
.colorTheme
|
.textHighEmphasis
|
||||||
.textHighEmphasis
|
.withOpacity(opacity),
|
||||||
.withOpacity(opacity),
|
),
|
||||||
),
|
|
||||||
),
|
),
|
||||||
subtitle: Text(subtitle),
|
subtitle: Text(subtitle),
|
||||||
trailing: channel.state!.unreadCount > 0
|
trailing: channel.state!.unreadCount > 0
|
||||||
|
|||||||
@@ -58,17 +58,17 @@ class MyApp extends StatelessWidget {
|
|||||||
final defaultTheme = StreamChatThemeData.fromTheme(themeData);
|
final defaultTheme = StreamChatThemeData.fromTheme(themeData);
|
||||||
final colorTheme = defaultTheme.colorTheme;
|
final colorTheme = defaultTheme.colorTheme;
|
||||||
final customTheme = defaultTheme.merge(StreamChatThemeData(
|
final customTheme = defaultTheme.merge(StreamChatThemeData(
|
||||||
channelPreviewTheme: ChannelPreviewTheme(
|
channelPreviewTheme: ChannelPreviewThemeData(
|
||||||
avatarTheme: AvatarTheme(
|
avatarTheme: AvatarThemeData(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
otherMessageTheme: MessageTheme(
|
otherMessageTheme: MessageThemeData(
|
||||||
messageBackgroundColor: colorTheme.textHighEmphasis,
|
messageBackgroundColor: colorTheme.textHighEmphasis,
|
||||||
messageText: TextStyle(
|
messageTextStyle: TextStyle(
|
||||||
color: colorTheme.barsBg,
|
color: colorTheme.barsBg,
|
||||||
),
|
),
|
||||||
avatarTheme: AvatarTheme(
|
avatarTheme: AvatarThemeData(
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
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/stream_chat_flutter.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
|
||||||
@@ -12,7 +13,7 @@ class AttachmentTitle extends StatelessWidget {
|
|||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
/// Theme to apply to text
|
/// Theme to apply to text
|
||||||
final MessageTheme messageTheme;
|
final MessageThemeData messageTheme;
|
||||||
|
|
||||||
/// Attachment data to display
|
/// Attachment data to display
|
||||||
final Attachment attachment;
|
final Attachment attachment;
|
||||||
@@ -34,7 +35,7 @@ class AttachmentTitle extends StatelessWidget {
|
|||||||
Text(
|
Text(
|
||||||
attachment.title!,
|
attachment.title!,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: messageTheme.messageText?.copyWith(
|
style: messageTheme.messageTextStyle?.copyWith(
|
||||||
color: StreamChatTheme.of(context).colorTheme.accentPrimary,
|
color: StreamChatTheme.of(context).colorTheme.accentPrimary,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
@@ -50,7 +51,7 @@ class AttachmentTitle extends StatelessWidget {
|
|||||||
.toList()
|
.toList()
|
||||||
.reversed
|
.reversed
|
||||||
.join('.'),
|
.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_title.dart';
|
||||||
import 'package:stream_chat_flutter/src/attachment/attachment_upload_state_builder.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/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/stream_chat_flutter.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
|
||||||
@@ -27,8 +28,8 @@ class ImageAttachment extends AttachmentWidget {
|
|||||||
size: size,
|
size: size,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// [MessageTheme] for showing image title
|
/// [MessageThemeData] for showing image title
|
||||||
final MessageTheme messageTheme;
|
final MessageThemeData messageTheme;
|
||||||
|
|
||||||
/// Flag for showing title
|
/// Flag for showing title
|
||||||
final bool showTitle;
|
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_title.dart';
|
||||||
import 'package:stream_chat_flutter/src/attachment/attachment_widget.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/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/src/video_thumbnail_image.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
@@ -24,8 +25,8 @@ class VideoAttachment extends AttachmentWidget {
|
|||||||
size: size,
|
size: size,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// [MessageTheme] for showing title
|
/// [MessageThemeData] for showing title
|
||||||
final MessageTheme messageTheme;
|
final MessageThemeData messageTheme;
|
||||||
|
|
||||||
/// Callback when show message is tapped
|
/// Callback when show message is tapped
|
||||||
final ShowMessageCallback? onShowMessage;
|
final ShowMessageCallback? onShowMessage;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
|||||||
bool _showActions = true;
|
bool _showActions = true;
|
||||||
|
|
||||||
late StreamChannelState _streamChannelState;
|
late StreamChannelState _streamChannelState;
|
||||||
|
late ChannelPreviewThemeData _channelPreviewThemeData;
|
||||||
late StreamChatThemeData _streamChatThemeData;
|
late StreamChatThemeData _streamChatThemeData;
|
||||||
late StreamChatState _streamChatState;
|
late StreamChatState _streamChatState;
|
||||||
|
|
||||||
@@ -64,8 +65,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
|||||||
child: ChannelInfo(
|
child: ChannelInfo(
|
||||||
showTypingIndicator: false,
|
showTypingIndicator: false,
|
||||||
channel: _streamChannelState.channel,
|
channel: _streamChannelState.channel,
|
||||||
textStyle:
|
textStyle: _channelPreviewThemeData.subtitleStyle,
|
||||||
_streamChatThemeData.channelPreviewTheme.subtitle,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(
|
const SizedBox(
|
||||||
@@ -213,6 +213,7 @@ class _ChannelBottomSheetState extends State<ChannelBottomSheet> {
|
|||||||
void didChangeDependencies() {
|
void didChangeDependencies() {
|
||||||
_streamChannelState = StreamChannel.of(context);
|
_streamChannelState = StreamChannel.of(context);
|
||||||
_streamChatThemeData = StreamChatTheme.of(context);
|
_streamChatThemeData = StreamChatTheme.of(context);
|
||||||
|
_channelPreviewThemeData = ChannelPreviewTheme.of(context);
|
||||||
_streamChatState = StreamChat.of(context);
|
_streamChatState = StreamChat.of(context);
|
||||||
super.didChangeDependencies();
|
super.didChangeDependencies();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final channel = StreamChannel.of(context).channel;
|
final channel = StreamChannel.of(context).channel;
|
||||||
final chatThemeData = StreamChatTheme.of(context);
|
final channelHeaderTheme = ChannelHeaderTheme.of(context);
|
||||||
|
|
||||||
final leadingWidget = leading ??
|
final leadingWidget = leading ??
|
||||||
(showBackButton
|
(showBackButton
|
||||||
@@ -141,18 +141,17 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
brightness: Theme.of(context).brightness,
|
brightness: Theme.of(context).brightness,
|
||||||
elevation: 1,
|
elevation: 1,
|
||||||
leading: leadingWidget,
|
leading: leadingWidget,
|
||||||
backgroundColor:
|
backgroundColor: channelHeaderTheme.color,
|
||||||
chatThemeData.channelTheme.channelHeaderTheme.color,
|
|
||||||
actions: actions ??
|
actions: actions ??
|
||||||
<Widget>[
|
<Widget>[
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(right: 10),
|
padding: const EdgeInsets.only(right: 10),
|
||||||
child: Center(
|
child: Center(
|
||||||
child: ChannelAvatar(
|
child: ChannelAvatar(
|
||||||
borderRadius: chatThemeData.channelTheme
|
borderRadius:
|
||||||
.channelHeaderTheme.avatarTheme?.borderRadius,
|
channelHeaderTheme.avatarTheme?.borderRadius,
|
||||||
constraints: chatThemeData.channelTheme
|
constraints:
|
||||||
.channelHeaderTheme.avatarTheme?.constraints,
|
channelHeaderTheme.avatarTheme?.constraints,
|
||||||
onTap: onImageTap,
|
onTap: onImageTap,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -169,16 +168,14 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
title ??
|
title ??
|
||||||
ChannelName(
|
ChannelName(
|
||||||
textStyle: chatThemeData
|
textStyle: channelHeaderTheme.titleStyle,
|
||||||
.channelTheme.channelHeaderTheme.title,
|
|
||||||
),
|
),
|
||||||
const SizedBox(height: 2),
|
const SizedBox(height: 2),
|
||||||
subtitle ??
|
subtitle ??
|
||||||
ChannelInfo(
|
ChannelInfo(
|
||||||
showTypingIndicator: showTypingIndicator,
|
showTypingIndicator: showTypingIndicator,
|
||||||
channel: channel,
|
channel: channel,
|
||||||
textStyle: chatThemeData
|
textStyle: channelHeaderTheme.subtitleStyle,
|
||||||
.channelTheme.channelHeaderTheme.subtitle,
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -65,10 +65,7 @@ class ChannelInfo extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
alternativeWidget = Text(
|
alternativeWidget = Text(
|
||||||
text,
|
text,
|
||||||
style: StreamChatTheme.of(context)
|
style: ChannelHeaderTheme.of(context).subtitleStyle,
|
||||||
.channelTheme
|
|
||||||
.channelHeaderTheme
|
|
||||||
.subtitle,
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
final userId = StreamChat.of(context).currentUser?.id;
|
final userId = StreamChat.of(context).currentUser?.id;
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ import 'dart:ui';
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.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/src/stream_neumorphic_button.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.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_core/stream_chat_flutter_core.dart';
|
||||||
import 'package:stream_chat_flutter/src/extension.dart';
|
|
||||||
|
|
||||||
/// Widget builder for title
|
/// Widget builder for title
|
||||||
typedef TitleBuilder = Widget Function(
|
typedef TitleBuilder = Widget Function(
|
||||||
@@ -46,7 +46,7 @@ typedef TitleBuilder = Widget Function(
|
|||||||
/// if you don't have it in the widget tree.
|
/// if you don't have it in the widget tree.
|
||||||
///
|
///
|
||||||
/// The widget components render the ui based on the first ancestor of type
|
/// 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.
|
/// Modify it to change the widget appearance.
|
||||||
class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
||||||
/// Instantiates a ChannelListHeader
|
/// Instantiates a ChannelListHeader
|
||||||
@@ -116,6 +116,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final chatThemeData = StreamChatTheme.of(context);
|
final chatThemeData = StreamChatTheme.of(context);
|
||||||
|
final channelListHeaderThemeData = ChannelListHeaderTheme.of(context);
|
||||||
return InfoTile(
|
return InfoTile(
|
||||||
showMessage: showConnectionStateTile && showStatus,
|
showMessage: showConnectionStateTile && showStatus,
|
||||||
message: statusString,
|
message: statusString,
|
||||||
@@ -123,7 +124,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
textTheme: Theme.of(context).textTheme,
|
textTheme: Theme.of(context).textTheme,
|
||||||
brightness: Theme.of(context).brightness,
|
brightness: Theme.of(context).brightness,
|
||||||
elevation: 1,
|
elevation: 1,
|
||||||
backgroundColor: chatThemeData.channelListHeaderTheme.color,
|
backgroundColor: channelListHeaderThemeData.color,
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
leading: leading ??
|
leading: leading ??
|
||||||
Center(
|
Center(
|
||||||
@@ -138,10 +139,10 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
}
|
}
|
||||||
Scaffold.of(context).openDrawer();
|
Scaffold.of(context).openDrawer();
|
||||||
},
|
},
|
||||||
borderRadius: chatThemeData
|
borderRadius: channelListHeaderThemeData
|
||||||
.channelListHeaderTheme.avatarTheme?.borderRadius,
|
.avatarTheme?.borderRadius,
|
||||||
constraints: chatThemeData
|
constraints: channelListHeaderThemeData
|
||||||
.channelListHeaderTheme.avatarTheme?.constraints,
|
.avatarTheme?.constraints,
|
||||||
)
|
)
|
||||||
: const Offstage(),
|
: const Offstage(),
|
||||||
),
|
),
|
||||||
@@ -227,10 +228,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
Text(
|
Text(
|
||||||
context.translations.searchingForNetworkText,
|
context.translations.searchingForNetworkText,
|
||||||
style: StreamChatTheme.of(context)
|
style: ChannelListHeaderTheme.of(context).titleStyle?.copyWith(
|
||||||
.channelListHeaderTheme
|
|
||||||
.title
|
|
||||||
?.copyWith(
|
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
@@ -243,12 +241,13 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
StreamChatClient client,
|
StreamChatClient client,
|
||||||
) {
|
) {
|
||||||
final chatThemeData = StreamChatTheme.of(context);
|
final chatThemeData = StreamChatTheme.of(context);
|
||||||
|
final channelListHeaderTheme = ChannelListHeaderTheme.of(context);
|
||||||
return Row(
|
return Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
context.translations.offlineLabel,
|
context.translations.offlineLabel,
|
||||||
style: chatThemeData.channelListHeaderTheme.title?.copyWith(
|
style: channelListHeaderTheme.titleStyle?.copyWith(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
),
|
),
|
||||||
@@ -259,7 +258,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
..openConnection(),
|
..openConnection(),
|
||||||
child: Text(
|
child: Text(
|
||||||
context.translations.tryAgainLabel,
|
context.translations.tryAgainLabel,
|
||||||
style: chatThemeData.channelListHeaderTheme.title?.copyWith(
|
style: channelListHeaderTheme.titleStyle?.copyWith(
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: chatThemeData.colorTheme.accentPrimary,
|
color: chatThemeData.colorTheme.accentPrimary,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import 'package:flutter_slidable/flutter_slidable.dart';
|
|||||||
import 'package:shimmer/shimmer.dart';
|
import 'package:shimmer/shimmer.dart';
|
||||||
import 'package:stream_chat_flutter/src/channel_bottom_sheet.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/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/stream_chat_flutter.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
import 'package:stream_chat_flutter/src/extension.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/material.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:jiffy/jiffy.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/src/stream_svg_icon.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.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_core/stream_chat_flutter_core.dart';
|
||||||
import 'package:stream_chat_flutter/src/extension.dart';
|
|
||||||
|
|
||||||
/// 
|
/// 
|
||||||
/// 
|
/// 
|
||||||
@@ -69,7 +69,7 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final channelPreviewTheme = StreamChatTheme.of(context).channelPreviewTheme;
|
final channelPreviewTheme = ChannelPreviewTheme.of(context);
|
||||||
final streamChatState = StreamChat.of(context);
|
final streamChatState = StreamChat.of(context);
|
||||||
return BetterStreamBuilder<bool>(
|
return BetterStreamBuilder<bool>(
|
||||||
stream: channel.isMutedStream,
|
stream: channel.isMutedStream,
|
||||||
@@ -91,7 +91,7 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
Flexible(
|
Flexible(
|
||||||
child: title ??
|
child: title ??
|
||||||
ChannelName(
|
ChannelName(
|
||||||
textStyle: channelPreviewTheme.title,
|
textStyle: channelPreviewTheme.titleStyle,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
BetterStreamBuilder<List<Member>?>(
|
BetterStreamBuilder<List<Member>?>(
|
||||||
@@ -183,14 +183,13 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
|
|
||||||
return Text(
|
return Text(
|
||||||
stringDate,
|
stringDate,
|
||||||
style:
|
style: ChannelPreviewTheme.of(context).lastMessageAtStyle,
|
||||||
StreamChatTheme.of(context).channelPreviewTheme.lastMessageAt,
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget _buildSubtitle(BuildContext context) {
|
Widget _buildSubtitle(BuildContext context) {
|
||||||
final chatThemeData = StreamChatTheme.of(context);
|
final channelPreviewTheme = ChannelPreviewTheme.of(context);
|
||||||
if (channel.isMuted) {
|
if (channel.isMuted) {
|
||||||
return Row(
|
return Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
@@ -200,7 +199,7 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
' ${context.translations.channelIsMutedText}',
|
' ${context.translations.channelIsMutedText}',
|
||||||
style: chatThemeData.channelPreviewTheme.subtitle,
|
style: channelPreviewTheme.subtitleStyle,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@@ -208,7 +207,7 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
return TypingIndicator(
|
return TypingIndicator(
|
||||||
channel: channel,
|
channel: channel,
|
||||||
alternativeWidget: _buildLastMessage(context),
|
alternativeWidget: _buildLastMessage(context),
|
||||||
style: chatThemeData.channelPreviewTheme.subtitle,
|
style: channelPreviewTheme.subtitleStyle,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,19 +242,19 @@ class ChannelPreview extends StatelessWidget {
|
|||||||
|
|
||||||
text = parts.join(' ');
|
text = parts.join(' ');
|
||||||
|
|
||||||
final chatThemeData = StreamChatTheme.of(context);
|
final channelPreviewTheme = ChannelPreviewTheme.of(context);
|
||||||
return Text.rich(
|
return Text.rich(
|
||||||
_getDisplayText(
|
_getDisplayText(
|
||||||
text,
|
text,
|
||||||
lastMessage.mentionedUsers,
|
lastMessage.mentionedUsers,
|
||||||
lastMessage.attachments,
|
lastMessage.attachments,
|
||||||
chatThemeData.channelPreviewTheme.subtitle?.copyWith(
|
channelPreviewTheme.subtitleStyle?.copyWith(
|
||||||
color: chatThemeData.channelPreviewTheme.subtitle?.color,
|
color: channelPreviewTheme.subtitleStyle?.color,
|
||||||
fontStyle: (lastMessage.isSystem || lastMessage.isDeleted)
|
fontStyle: (lastMessage.isSystem || lastMessage.isDeleted)
|
||||||
? FontStyle.italic
|
? FontStyle.italic
|
||||||
: FontStyle.normal),
|
: FontStyle.normal),
|
||||||
chatThemeData.channelPreviewTheme.subtitle?.copyWith(
|
channelPreviewTheme.subtitleStyle?.copyWith(
|
||||||
color: chatThemeData.channelPreviewTheme.subtitle?.color,
|
color: channelPreviewTheme.subtitleStyle?.color,
|
||||||
fontStyle: (lastMessage.isSystem || lastMessage.isDeleted)
|
fontStyle: (lastMessage.isSystem || lastMessage.isDeleted)
|
||||||
? FontStyle.italic
|
? FontStyle.italic
|
||||||
: FontStyle.normal,
|
: FontStyle.normal,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
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/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
|
/// Widget to display deleted message
|
||||||
class DeletedMessage extends StatelessWidget {
|
class DeletedMessage extends StatelessWidget {
|
||||||
@@ -15,7 +16,7 @@ class DeletedMessage extends StatelessWidget {
|
|||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
/// The theme of the message
|
/// The theme of the message
|
||||||
final MessageTheme messageTheme;
|
final MessageThemeData messageTheme;
|
||||||
|
|
||||||
/// The border radius of the message text
|
/// The border radius of the message text
|
||||||
final BorderRadiusGeometry? borderRadiusGeometry;
|
final BorderRadiusGeometry? borderRadiusGeometry;
|
||||||
@@ -51,9 +52,9 @@ class DeletedMessage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
context.translations.messageDeletedLabel,
|
context.translations.messageDeletedLabel,
|
||||||
style: messageTheme.messageText?.copyWith(
|
style: messageTheme.messageTextStyle?.copyWith(
|
||||||
fontStyle: FontStyle.italic,
|
fontStyle: FontStyle.italic,
|
||||||
color: messageTheme.createdAt?.color,
|
color: messageTheme.createdAtStyle?.color,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -124,10 +124,7 @@ class _FullScreenMediaState extends State<FullScreenMedia>
|
|||||||
),
|
),
|
||||||
backgroundDecoration: BoxDecoration(
|
backgroundDecoration: BoxDecoration(
|
||||||
color: ColorTween(
|
color: ColorTween(
|
||||||
begin: StreamChatTheme.of(context)
|
begin: ChannelHeaderTheme.of(context).color,
|
||||||
.channelTheme
|
|
||||||
.channelHeaderTheme
|
|
||||||
.color,
|
|
||||||
end: Colors.black,
|
end: Colors.black,
|
||||||
).lerp(_controller.value),
|
).lerp(_controller.value),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:share_plus/share_plus.dart';
|
import 'package:share_plus/share_plus.dart';
|
||||||
import 'package:stream_chat_flutter/src/stream_chat_theme.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/src/video_thumbnail_image.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.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_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/attachment_actions_modal.dart';
|
||||||
import 'package:stream_chat_flutter/src/stream_chat_theme.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/stream_svg_icon.dart';
|
||||||
|
import 'package:stream_chat_flutter/src/theme/themes.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
|
|
||||||
/// Header/AppBar widget for media display screen
|
/// Header/AppBar widget for media display screen
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/src/full_screen_media.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/stream_chat_flutter.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.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
|
/// Message which images are attached to
|
||||||
final Message message;
|
final Message message;
|
||||||
|
|
||||||
/// [MessageTheme] to apply to message
|
/// [MessageThemeData] to apply to message
|
||||||
final MessageTheme messageTheme;
|
final MessageThemeData messageTheme;
|
||||||
|
|
||||||
/// Size of iamges
|
/// Size of iamges
|
||||||
final Size size;
|
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/message_action.dart';
|
||||||
import 'package:stream_chat_flutter/src/reaction_picker.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/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/src/utils.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
@@ -49,8 +50,8 @@ class MessageActionsModal extends StatefulWidget {
|
|||||||
/// Message in focus for actions
|
/// Message in focus for actions
|
||||||
final Message message;
|
final Message message;
|
||||||
|
|
||||||
/// [MessageTheme] for message
|
/// [MessageThemeData] for message
|
||||||
final MessageTheme messageTheme;
|
final MessageThemeData messageTheme;
|
||||||
|
|
||||||
/// Flag for showing reactions
|
/// Flag for showing reactions
|
||||||
final bool showReactions;
|
final bool showReactions;
|
||||||
@@ -116,7 +117,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
final roughSentenceSize = messageTextLength *
|
final roughSentenceSize = messageTextLength *
|
||||||
(widget.messageTheme.messageText?.fontSize ?? 1) *
|
(widget.messageTheme.messageTextStyle?.fontSize ?? 1) *
|
||||||
1.2;
|
1.2;
|
||||||
final divFactor = widget.message.attachments.isNotEmpty == true
|
final divFactor = widget.message.attachments.isNotEmpty == true
|
||||||
? 1
|
? 1
|
||||||
@@ -565,7 +566,7 @@ class _MessageActionsModalState extends State<MessageActionsModal> {
|
|||||||
elevation: 2,
|
elevation: 2,
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
backgroundColor: streamChatThemeData.messageInputTheme.inputBackground,
|
backgroundColor: MessageInputTheme.of(context).inputBackgroundColor,
|
||||||
shape: const RoundedRectangleBorder(
|
shape: const RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: BorderRadius.only(
|
||||||
topLeft: Radius.circular(16),
|
topLeft: Radius.circular(16),
|
||||||
|
|||||||
@@ -288,6 +288,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
late final TextEditingController textEditingController;
|
late final TextEditingController textEditingController;
|
||||||
|
|
||||||
late StreamChatThemeData _streamChatTheme;
|
late StreamChatThemeData _streamChatTheme;
|
||||||
|
late MessageInputThemeData _messageInputTheme;
|
||||||
|
|
||||||
bool get _hasQuotedMessage => widget.quotedMessage != null;
|
bool get _hasQuotedMessage => widget.quotedMessage != null;
|
||||||
|
|
||||||
@@ -328,7 +329,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Widget child = DecoratedBox(
|
Widget child = DecoratedBox(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: _streamChatTheme.messageInputTheme.inputBackground,
|
color: _messageInputTheme.inputBackgroundColor,
|
||||||
),
|
),
|
||||||
child: SafeArea(
|
child: SafeArea(
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
@@ -484,7 +485,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
: CrossFadeState.showSecond,
|
: CrossFadeState.showSecond,
|
||||||
firstChild: sendButton,
|
firstChild: sendButton,
|
||||||
secondChild: widget.idleSendButton ?? _buildIdleSendButton(context),
|
secondChild: widget.idleSendButton ?? _buildIdleSendButton(context),
|
||||||
duration: _streamChatTheme.messageInputTheme.sendAnimationDuration!,
|
duration: _messageInputTheme.sendAnimationDuration!,
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -509,7 +510,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
? pi
|
? pi
|
||||||
: 0,
|
: 0,
|
||||||
child: StreamSvgIcon.emptyCircleLeft(
|
child: StreamSvgIcon.emptyCircleLeft(
|
||||||
color: _streamChatTheme.messageInputTheme.expandButtonColor,
|
color: _messageInputTheme.expandButtonColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.all(0),
|
padding: const EdgeInsets.all(0),
|
||||||
@@ -555,17 +556,17 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
margin: margin,
|
margin: margin,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: _streamChatTheme.messageInputTheme.borderRadius,
|
borderRadius: _messageInputTheme.borderRadius,
|
||||||
gradient: _focusNode.hasFocus
|
gradient: _focusNode.hasFocus
|
||||||
? _streamChatTheme.messageInputTheme.activeBorderGradient
|
? _messageInputTheme.activeBorderGradient
|
||||||
: _streamChatTheme.messageInputTheme.idleBorderGradient,
|
: _messageInputTheme.idleBorderGradient,
|
||||||
),
|
),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(1.5),
|
padding: const EdgeInsets.all(1.5),
|
||||||
child: DecoratedBox(
|
child: DecoratedBox(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: _streamChatTheme.messageInputTheme.borderRadius,
|
borderRadius: _messageInputTheme.borderRadius,
|
||||||
color: _streamChatTheme.messageInputTheme.inputBackground,
|
color: _messageInputTheme.inputBackgroundColor,
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
@@ -583,7 +584,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
keyboardType: widget.keyboardType,
|
keyboardType: widget.keyboardType,
|
||||||
controller: textEditingController,
|
controller: textEditingController,
|
||||||
focusNode: _focusNode,
|
focusNode: _focusNode,
|
||||||
style: _streamChatTheme.messageInputTheme.inputTextStyle,
|
style: _messageInputTheme.inputTextStyle,
|
||||||
autofocus: widget.autofocus,
|
autofocus: widget.autofocus,
|
||||||
textAlignVertical: TextAlignVertical.center,
|
textAlignVertical: TextAlignVertical.center,
|
||||||
decoration: _getInputDecoration(context),
|
decoration: _getInputDecoration(context),
|
||||||
@@ -599,11 +600,11 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
InputDecoration _getInputDecoration(BuildContext context) {
|
InputDecoration _getInputDecoration(BuildContext context) {
|
||||||
final passedDecoration = _streamChatTheme.messageInputTheme.inputDecoration;
|
final passedDecoration = _messageInputTheme.inputDecoration;
|
||||||
return InputDecoration(
|
return InputDecoration(
|
||||||
isDense: true,
|
isDense: true,
|
||||||
hintText: _getHint(context),
|
hintText: _getHint(context),
|
||||||
hintStyle: _streamChatTheme.messageInputTheme.inputTextStyle!.copyWith(
|
hintStyle: _messageInputTheme.inputTextStyle!.copyWith(
|
||||||
color: _streamChatTheme.colorTheme.textLowEmphasis,
|
color: _streamChatTheme.colorTheme.textLowEmphasis,
|
||||||
),
|
),
|
||||||
border: const OutlineInputBorder(
|
border: const OutlineInputBorder(
|
||||||
@@ -1688,8 +1689,8 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
color: s.isNotEmpty
|
color: s.isNotEmpty
|
||||||
? _streamChatTheme.colorTheme.disabled
|
? _streamChatTheme.colorTheme.disabled
|
||||||
: (_commandsOverlay != null
|
: (_commandsOverlay != null
|
||||||
? _streamChatTheme.messageInputTheme.actionButtonColor
|
? _messageInputTheme.actionButtonColor
|
||||||
: _streamChatTheme.messageInputTheme.actionButtonIdleColor),
|
: _messageInputTheme.actionButtonIdleColor),
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.all(0),
|
padding: const EdgeInsets.all(0),
|
||||||
constraints: const BoxConstraints.tightFor(
|
constraints: const BoxConstraints.tightFor(
|
||||||
@@ -1726,8 +1727,8 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
Widget _buildAttachmentButton() => IconButton(
|
Widget _buildAttachmentButton() => IconButton(
|
||||||
icon: StreamSvgIcon.attach(
|
icon: StreamSvgIcon.attach(
|
||||||
color: _openFilePickerSection
|
color: _openFilePickerSection
|
||||||
? _streamChatTheme.messageInputTheme.actionButtonColor
|
? _messageInputTheme.actionButtonColor
|
||||||
: _streamChatTheme.messageInputTheme.actionButtonIdleColor,
|
: _messageInputTheme.actionButtonIdleColor,
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.all(0),
|
padding: const EdgeInsets.all(0),
|
||||||
constraints: const BoxConstraints.tightFor(
|
constraints: const BoxConstraints.tightFor(
|
||||||
@@ -1963,7 +1964,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
child: StreamSvgIcon(
|
child: StreamSvgIcon(
|
||||||
assetName: _getIdleSendIcon(),
|
assetName: _getIdleSendIcon(),
|
||||||
color: _streamChatTheme.messageInputTheme.sendButtonIdleColor,
|
color: _messageInputTheme.sendButtonIdleColor,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1979,7 +1980,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
),
|
),
|
||||||
icon: StreamSvgIcon(
|
icon: StreamSvgIcon(
|
||||||
assetName: _getSendIcon(),
|
assetName: _getSendIcon(),
|
||||||
color: _streamChatTheme.messageInputTheme.sendButtonColor,
|
color: _messageInputTheme.sendButtonColor,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -2186,6 +2187,7 @@ class MessageInputState extends State<MessageInput> {
|
|||||||
@override
|
@override
|
||||||
void didChangeDependencies() {
|
void didChangeDependencies() {
|
||||||
_streamChatTheme = StreamChatTheme.of(context);
|
_streamChatTheme = StreamChatTheme.of(context);
|
||||||
|
_messageInputTheme = MessageInputTheme.of(context);
|
||||||
if (widget.editMessage != null && !_initialized) {
|
if (widget.editMessage != null && !_initialized) {
|
||||||
FocusScope.of(context).requestFocus(_focusNode);
|
FocusScope.of(context).requestFocus(_focusNode);
|
||||||
_initialized = true;
|
_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/stream_svg_icon.dart';
|
||||||
import 'package:stream_chat_flutter/src/swipeable.dart';
|
import 'package:stream_chat_flutter/src/swipeable.dart';
|
||||||
import 'package:stream_chat_flutter/src/system_message.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/stream_chat_flutter.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
import 'package:visibility_detector/visibility_detector.dart';
|
import 'package:visibility_detector/visibility_detector.dart';
|
||||||
@@ -628,7 +629,7 @@ class _MessageListViewState extends State<MessageListView> {
|
|||||||
child: Text(
|
child: Text(
|
||||||
context.translations.threadSeparatorText(replyCount),
|
context.translations.threadSeparatorText(replyCount),
|
||||||
textAlign: TextAlign.center,
|
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_bubble.dart';
|
||||||
import 'package:stream_chat_flutter/src/reaction_picker.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/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/src/user_avatar.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.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_core/stream_chat_flutter_core.dart';
|
||||||
@@ -28,8 +29,8 @@ class MessageReactionsModal extends StatelessWidget {
|
|||||||
/// Message to display reactions of
|
/// Message to display reactions of
|
||||||
final Message message;
|
final Message message;
|
||||||
|
|
||||||
/// [MessageTheme] to apply to [message]
|
/// [MessageThemeData] to apply to [message]
|
||||||
final MessageTheme messageTheme;
|
final MessageThemeData messageTheme;
|
||||||
|
|
||||||
/// Flag to reverse message
|
/// Flag to reverse message
|
||||||
final bool reverse;
|
final bool reverse;
|
||||||
@@ -56,8 +57,9 @@ class MessageReactionsModal extends StatelessWidget {
|
|||||||
messageTextLength = quotedMessageLength;
|
messageTextLength = quotedMessageLength;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
final roughSentenceSize =
|
final roughSentenceSize = messageTextLength *
|
||||||
messageTextLength * (messageTheme.messageText?.fontSize ?? 1) * 1.2;
|
(messageTheme.messageTextStyle?.fontSize ?? 1) *
|
||||||
|
1.2;
|
||||||
final divFactor = message.attachments.isNotEmpty == true
|
final divFactor = message.attachments.isNotEmpty == true
|
||||||
? 1
|
? 1
|
||||||
: (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize));
|
: (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize));
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ class MessageSearchItem extends StatelessWidget {
|
|||||||
final channel = getMessageResponse.channel;
|
final channel = getMessageResponse.channel;
|
||||||
final channelName = channel?.extraData['name'];
|
final channelName = channel?.extraData['name'];
|
||||||
final user = message.user!;
|
final user = message.user!;
|
||||||
final chatThemeData = StreamChatTheme.of(context);
|
final channelPreviewTheme = ChannelPreviewTheme.of(context);
|
||||||
return ListTile(
|
return ListTile(
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
leading: UserAvatar(
|
leading: UserAvatar(
|
||||||
@@ -53,18 +53,18 @@ class MessageSearchItem extends StatelessWidget {
|
|||||||
user.id == StreamChat.of(context).currentUser?.id
|
user.id == StreamChat.of(context).currentUser?.id
|
||||||
? context.translations.youText
|
? context.translations.youText
|
||||||
: user.name,
|
: user.name,
|
||||||
style: chatThemeData.channelPreviewTheme.title,
|
style: channelPreviewTheme.titleStyle,
|
||||||
),
|
),
|
||||||
if (channelName != null) ...[
|
if (channelName != null) ...[
|
||||||
Text(
|
Text(
|
||||||
' ${context.translations.inText} ',
|
' ${context.translations.inText} ',
|
||||||
style: chatThemeData.channelPreviewTheme.title?.copyWith(
|
style: channelPreviewTheme.titleStyle?.copyWith(
|
||||||
fontWeight: FontWeight.normal,
|
fontWeight: FontWeight.normal,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
channelName as String,
|
channelName as String,
|
||||||
style: chatThemeData.channelPreviewTheme.title,
|
style: channelPreviewTheme.titleStyle,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
@@ -94,7 +94,7 @@ class MessageSearchItem extends StatelessWidget {
|
|||||||
|
|
||||||
return Text(
|
return Text(
|
||||||
stringDate,
|
stringDate,
|
||||||
style: StreamChatTheme.of(context).channelPreviewTheme.lastMessageAt,
|
style: StreamChatTheme.of(context).channelPreviewTheme.lastMessageAtStyle,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,18 +122,18 @@ class MessageSearchItem extends StatelessWidget {
|
|||||||
text = parts.join(' ');
|
text = parts.join(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
final chatThemeData = StreamChatTheme.of(context);
|
final channelPreviewTheme = ChannelPreviewTheme.of(context);
|
||||||
return Text.rich(
|
return Text.rich(
|
||||||
_getDisplayText(
|
_getDisplayText(
|
||||||
text!,
|
text!,
|
||||||
message.mentionedUsers,
|
message.mentionedUsers,
|
||||||
message.attachments,
|
message.attachments,
|
||||||
chatThemeData.channelPreviewTheme.subtitle?.copyWith(
|
channelPreviewTheme.subtitleStyle?.copyWith(
|
||||||
fontStyle: (message.isSystem || message.isDeleted)
|
fontStyle: (message.isSystem || message.isDeleted)
|
||||||
? FontStyle.italic
|
? FontStyle.italic
|
||||||
: FontStyle.normal,
|
: FontStyle.normal,
|
||||||
),
|
),
|
||||||
chatThemeData.channelPreviewTheme.subtitle?.copyWith(
|
channelPreviewTheme.subtitleStyle?.copyWith(
|
||||||
fontStyle: (message.isSystem || message.isDeleted)
|
fontStyle: (message.isSystem || message.isDeleted)
|
||||||
? FontStyle.italic
|
? FontStyle.italic
|
||||||
: FontStyle.normal,
|
: FontStyle.normal,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/src/info_tile.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/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/stream_chat_flutter.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
import 'package:stream_chat_flutter/src/extension.dart';
|
import 'package:stream_chat_flutter/src/extension.dart';
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:collection/collection.dart' show IterableExtension;
|
import 'package:collection/collection.dart' show IterableExtension;
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_markdown/flutter_markdown.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/stream_chat_flutter.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.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
|
/// Callback for when link is tapped
|
||||||
final void Function(String)? onLinkTap;
|
final void Function(String)? onLinkTap;
|
||||||
|
|
||||||
/// [MessageTheme] whose text theme is to be applied
|
/// [MessageThemeData] whose text theme is to be applied
|
||||||
final MessageTheme messageTheme;
|
final MessageThemeData messageTheme;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@@ -66,16 +67,16 @@ class MessageText extends StatelessWidget {
|
|||||||
styleSheet: MarkdownStyleSheet.fromTheme(
|
styleSheet: MarkdownStyleSheet.fromTheme(
|
||||||
themeData.copyWith(
|
themeData.copyWith(
|
||||||
textTheme: themeData.textTheme.apply(
|
textTheme: themeData.textTheme.apply(
|
||||||
bodyColor: messageTheme.messageText?.color,
|
bodyColor: messageTheme.messageTextStyle?.color,
|
||||||
decoration: messageTheme.messageText?.decoration,
|
decoration: messageTheme.messageTextStyle?.decoration,
|
||||||
decorationColor: messageTheme.messageText?.decorationColor,
|
decorationColor: messageTheme.messageTextStyle?.decorationColor,
|
||||||
decorationStyle: messageTheme.messageText?.decorationStyle,
|
decorationStyle: messageTheme.messageTextStyle?.decorationStyle,
|
||||||
fontFamily: messageTheme.messageText?.fontFamily,
|
fontFamily: messageTheme.messageTextStyle?.fontFamily,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
).copyWith(
|
).copyWith(
|
||||||
a: messageTheme.messageLinks,
|
a: messageTheme.messageLinksStyle,
|
||||||
p: messageTheme.messageText,
|
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/message_reactions_modal.dart';
|
||||||
import 'package:stream_chat_flutter/src/quoted_message_widget.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/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/src/url_attachment.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
@@ -290,7 +291,7 @@ class MessageWidget extends StatefulWidget {
|
|||||||
final Message message;
|
final Message message;
|
||||||
|
|
||||||
/// The message theme
|
/// The message theme
|
||||||
final MessageTheme messageTheme;
|
final MessageThemeData messageTheme;
|
||||||
|
|
||||||
/// If true the widget will be mirrored
|
/// If true the widget will be mirrored
|
||||||
final bool reverse;
|
final bool reverse;
|
||||||
@@ -422,7 +423,7 @@ class MessageWidget extends StatefulWidget {
|
|||||||
Widget Function(BuildContext, Message)? deletedBottomRowBuilder,
|
Widget Function(BuildContext, Message)? deletedBottomRowBuilder,
|
||||||
void Function(BuildContext, Message)? onMessageActions,
|
void Function(BuildContext, Message)? onMessageActions,
|
||||||
Message? message,
|
Message? message,
|
||||||
MessageTheme? messageTheme,
|
MessageThemeData? messageTheme,
|
||||||
bool? reverse,
|
bool? reverse,
|
||||||
ShapeBorder? shape,
|
ShapeBorder? shape,
|
||||||
ShapeBorder? attachmentShape,
|
ShapeBorder? attachmentShape,
|
||||||
@@ -893,14 +894,14 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
),
|
),
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: widget.onThreadTap != null ? onThreadTap : null,
|
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 (showUsername) _buildUsername(usernameKey),
|
||||||
if (showTimeStamp)
|
if (showTimeStamp)
|
||||||
Text(
|
Text(
|
||||||
Jiffy(widget.message.createdAt.toLocal()).jm,
|
Jiffy(widget.message.createdAt.toLocal()).jm,
|
||||||
style: widget.messageTheme.createdAt,
|
style: widget.messageTheme.createdAtStyle,
|
||||||
),
|
),
|
||||||
if (showSendingIndicator) _buildSendingIndicator(),
|
if (showSendingIndicator) _buildSendingIndicator(),
|
||||||
]);
|
]);
|
||||||
@@ -917,7 +918,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
Container(
|
Container(
|
||||||
margin: EdgeInsets.only(
|
margin: EdgeInsets.only(
|
||||||
bottom: context.textScaleFactor *
|
bottom: context.textScaleFactor *
|
||||||
((widget.messageTheme.replies?.fontSize ?? 1) / 2),
|
((widget.messageTheme.repliesStyle?.fontSize ?? 1) / 2),
|
||||||
),
|
),
|
||||||
child: CustomPaint(
|
child: CustomPaint(
|
||||||
size: const Size(16, 32) * context.textScaleFactor,
|
size: const Size(16, 32) * context.textScaleFactor,
|
||||||
@@ -944,7 +945,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
Container(
|
Container(
|
||||||
margin: EdgeInsets.only(
|
margin: EdgeInsets.only(
|
||||||
bottom: context.textScaleFactor *
|
bottom: context.textScaleFactor *
|
||||||
((widget.messageTheme.replies?.fontSize ?? 1) / 2),
|
((widget.messageTheme.repliesStyle?.fontSize ?? 1) / 2),
|
||||||
),
|
),
|
||||||
child: CustomPaint(
|
child: CustomPaint(
|
||||||
size: const Size(16, 32) * context.textScaleFactor,
|
size: const Size(16, 32) * context.textScaleFactor,
|
||||||
@@ -967,7 +968,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
widget.message.user!.name,
|
widget.message.user!.name,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
key: usernameKey,
|
key: usernameKey,
|
||||||
style: widget.messageTheme.messageAuthor,
|
style: widget.messageTheme.messageAuthorStyle,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1191,7 +1192,7 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildSendingIndicator() {
|
Widget _buildSendingIndicator() {
|
||||||
final style = widget.messageTheme.createdAt;
|
final style = widget.messageTheme.createdAtStyle;
|
||||||
final message = widget.message;
|
final message = widget.message;
|
||||||
|
|
||||||
if (hasNonUrlAttachments &&
|
if (hasNonUrlAttachments &&
|
||||||
@@ -1271,8 +1272,8 @@ class _MessageWidgetState extends State<MessageWidget>
|
|||||||
onMentionTap: widget.onMentionTap,
|
onMentionTap: widget.onMentionTap,
|
||||||
messageTheme: isOnlyEmoji
|
messageTheme: isOnlyEmoji
|
||||||
? widget.messageTheme.copyWith(
|
? widget.messageTheme.copyWith(
|
||||||
messageText:
|
messageTextStyle:
|
||||||
widget.messageTheme.messageText!.copyWith(
|
widget.messageTheme.messageTextStyle!.copyWith(
|
||||||
fontSize: 42,
|
fontSize: 42,
|
||||||
))
|
))
|
||||||
: widget.messageTheme,
|
: widget.messageTheme,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:cached_network_image/cached_network_image.dart';
|
import 'package:cached_network_image/cached_network_image.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:stream_chat_flutter/src/extension.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/stream_chat_flutter.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
import 'package:video_player/video_player.dart';
|
import 'package:video_player/video_player.dart';
|
||||||
@@ -73,7 +74,7 @@ class QuotedMessageWidget extends StatelessWidget {
|
|||||||
final Message message;
|
final Message message;
|
||||||
|
|
||||||
/// The message theme
|
/// The message theme
|
||||||
final MessageTheme messageTheme;
|
final MessageThemeData messageTheme;
|
||||||
|
|
||||||
/// If true the widget will be mirrored
|
/// If true the widget will be mirrored
|
||||||
final bool reverse;
|
final bool reverse;
|
||||||
@@ -138,11 +139,11 @@ class QuotedMessageWidget extends StatelessWidget {
|
|||||||
message: msg,
|
message: msg,
|
||||||
messageTheme: isOnlyEmoji && _containsText
|
messageTheme: isOnlyEmoji && _containsText
|
||||||
? messageTheme.copyWith(
|
? messageTheme.copyWith(
|
||||||
messageText: messageTheme.messageText?.copyWith(
|
messageTextStyle: messageTheme.messageTextStyle?.copyWith(
|
||||||
fontSize: 32,
|
fontSize: 32,
|
||||||
))
|
))
|
||||||
: messageTheme.copyWith(
|
: messageTheme.copyWith(
|
||||||
messageText: messageTheme.messageText?.copyWith(
|
messageTextStyle: messageTheme.messageTextStyle?.copyWith(
|
||||||
fontSize: 12,
|
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final chatThemeData = StreamChatTheme.of(context);
|
final channelHeaderTheme = ChannelHeaderTheme.of(context);
|
||||||
|
|
||||||
final defaultSubtitle = subtitle ??
|
final defaultSubtitle = subtitle ??
|
||||||
Row(
|
Row(
|
||||||
@@ -113,12 +113,11 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'${context.translations.withText} ',
|
'${context.translations.withText} ',
|
||||||
style: chatThemeData.channelTheme.channelHeaderTheme.subtitle,
|
style: channelHeaderTheme.subtitleStyle,
|
||||||
),
|
),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: ChannelName(
|
child: ChannelName(
|
||||||
textStyle:
|
textStyle: channelHeaderTheme.subtitleStyle,
|
||||||
chatThemeData.channelTheme.channelHeaderTheme.subtitle,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -137,7 +136,7 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
showUnreads: true,
|
showUnreads: true,
|
||||||
)
|
)
|
||||||
: const SizedBox()),
|
: const SizedBox()),
|
||||||
backgroundColor: chatThemeData.channelTheme.channelHeaderTheme.color,
|
backgroundColor: channelHeaderTheme.color,
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
actions: actions,
|
actions: actions,
|
||||||
title: InkWell(
|
title: InkWell(
|
||||||
@@ -151,14 +150,14 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
title ??
|
title ??
|
||||||
Text(
|
Text(
|
||||||
context.translations.threadReplyLabel,
|
context.translations.threadReplyLabel,
|
||||||
style: chatThemeData.channelTheme.channelHeaderTheme.title,
|
style: channelHeaderTheme.titleStyle,
|
||||||
),
|
),
|
||||||
const SizedBox(height: 2),
|
const SizedBox(height: 2),
|
||||||
if (showTypingIndicator)
|
if (showTypingIndicator)
|
||||||
TypingIndicator(
|
TypingIndicator(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
channel: StreamChannel.of(context).channel,
|
channel: StreamChannel.of(context).channel,
|
||||||
style: chatThemeData.channelTheme.channelHeaderTheme.subtitle,
|
style: channelHeaderTheme.subtitleStyle,
|
||||||
parentId: parent.id,
|
parentId: parent.id,
|
||||||
alternativeWidget: defaultSubtitle,
|
alternativeWidget: defaultSubtitle,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
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/stream_chat_flutter.dart';
|
||||||
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
|
||||||
import 'package:stream_chat_flutter/src/extension.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_neumorphic_button.dart';
|
||||||
export 'src/stream_svg_icon.dart';
|
export 'src/stream_svg_icon.dart';
|
||||||
export 'src/system_message.dart';
|
export 'src/system_message.dart';
|
||||||
|
export 'src/theme/themes.dart';
|
||||||
export 'src/thread_header.dart';
|
export 'src/thread_header.dart';
|
||||||
export 'src/typing_indicator.dart';
|
export 'src/typing_indicator.dart';
|
||||||
export 'src/unread_indicator.dart';
|
export 'src/unread_indicator.dart';
|
||||||
export 'src/user_avatar.dart';
|
export 'src/user_avatar.dart';
|
||||||
export 'src/user_item.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/user_list_view.dart';
|
||||||
export 'src/utils.dart';
|
export 'src/utils.dart';
|
||||||
export 'src/visible_footnote.dart';
|
export 'src/visible_footnote.dart';
|
||||||
|
|||||||
@@ -21,11 +21,11 @@ void main() {
|
|||||||
client: client,
|
client: client,
|
||||||
child: const Scaffold(
|
child: const Scaffold(
|
||||||
body: DeletedMessage(
|
body: DeletedMessage(
|
||||||
messageTheme: MessageTheme(
|
messageTheme: MessageThemeData(
|
||||||
createdAt: TextStyle(
|
createdAtStyle: TextStyle(
|
||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
),
|
),
|
||||||
messageText: TextStyle(),
|
messageTextStyle: TextStyle(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ void main() {
|
|||||||
final clientState = MockClientState();
|
final clientState = MockClientState();
|
||||||
final channel = MockChannel();
|
final channel = MockChannel();
|
||||||
final channelState = MockChannelState();
|
final channelState = MockChannelState();
|
||||||
const messageTheme = MessageTheme();
|
const messageTheme = MessageThemeData();
|
||||||
|
|
||||||
final currentUser = OwnUser(
|
final currentUser = OwnUser(
|
||||||
id: 'sahil',
|
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:flutter_test/flutter_test.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
import 'mocks.dart';
|
import '../mocks.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test('ChannelListViewThemeData copyWith, ==, hashCode basics', () {
|
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:mocktail/mocktail.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
import 'mocks.dart';
|
import '../mocks.dart';
|
||||||
|
|
||||||
class MockStreamChatClient extends Mock implements StreamChatClient {}
|
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:flutter_test/flutter_test.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
import 'mocks.dart';
|
import '../mocks.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test('MessageSearchListViewThemeData copyWith, ==, hashCode basics', () {
|
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:flutter_test/flutter_test.dart';
|
||||||
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
||||||
|
|
||||||
import 'mocks.dart';
|
import '../mocks.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test('UserListViewThemeData copyWith, ==, hashCode basics', () {
|
test('UserListViewThemeData copyWith, ==, hashCode basics', () {
|
||||||
Reference in New Issue
Block a user