From bcabbf12db5bb532116cd4d231d5284a8a851c16 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Mon, 26 Jul 2021 14:46:14 -0400 Subject: [PATCH 01/42] chore: refactor most theme related classes into a /theme folder stream_chat_theme.dart remains in /src because I feel it will cause too much of a mess if moved. --- .../lib/src/attachment/attachment_title.dart | 1 + .../lib/src/attachment/image_attachment.dart | 1 + .../lib/src/attachment/video_attachment.dart | 1 + .../lib/src/channel_list_view.dart | 1 + .../lib/src/deleted_message.dart | 1 + .../lib/src/gallery_footer.dart | 1 + .../lib/src/gallery_header.dart | 1 + .../lib/src/image_group.dart | 1 + .../lib/src/message_actions_modal.dart | 1 + .../lib/src/message_list_view.dart | 1 + .../lib/src/message_reactions_modal.dart | 1 + .../lib/src/message_search_list_view.dart | 1 + .../lib/src/message_text.dart | 1 + .../lib/src/message_widget.dart | 1 + .../lib/src/quoted_message_widget.dart | 1 + .../lib/src/stream_chat_theme.dart | 1704 +---------------- .../lib/src/theme/avatar_theme.dart | 44 + .../lib/src/theme/channel_header_theme.dart | 50 + .../src/theme/channel_list_header_theme.dart | 43 + .../src/theme/channel_list_view_theme.dart | 111 ++ .../lib/src/theme/channel_preview_theme.dart | 64 + .../lib/src/theme/channel_theme.dart | 28 + .../lib/src/theme/color_theme.dart | 286 +++ .../lib/src/theme/gallery_footer_theme.dart | 217 +++ .../lib/src/theme/gallery_header_theme.dart | 179 ++ .../lib/src/theme/message_input_theme.dart | 110 ++ .../src/theme/message_list_view_theme.dart | 111 ++ .../theme/message_search_list_view_theme.dart | 112 ++ .../lib/src/theme/message_theme.dart | 103 + .../lib/src/theme/text_theme.dart | 163 ++ .../lib/src/theme/themes.dart | 15 + .../lib/src/theme/user_list_view_theme.dart | 111 ++ .../lib/src/user_list_view.dart | 1 + .../lib/stream_chat_flutter.dart | 1 + 34 files changed, 1766 insertions(+), 1702 deletions(-) create mode 100644 packages/stream_chat_flutter/lib/src/theme/avatar_theme.dart create mode 100644 packages/stream_chat_flutter/lib/src/theme/channel_header_theme.dart create mode 100644 packages/stream_chat_flutter/lib/src/theme/channel_list_header_theme.dart create mode 100644 packages/stream_chat_flutter/lib/src/theme/channel_list_view_theme.dart create mode 100644 packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart create mode 100644 packages/stream_chat_flutter/lib/src/theme/channel_theme.dart create mode 100644 packages/stream_chat_flutter/lib/src/theme/color_theme.dart create mode 100644 packages/stream_chat_flutter/lib/src/theme/gallery_footer_theme.dart create mode 100644 packages/stream_chat_flutter/lib/src/theme/gallery_header_theme.dart create mode 100644 packages/stream_chat_flutter/lib/src/theme/message_input_theme.dart create mode 100644 packages/stream_chat_flutter/lib/src/theme/message_list_view_theme.dart create mode 100644 packages/stream_chat_flutter/lib/src/theme/message_search_list_view_theme.dart create mode 100644 packages/stream_chat_flutter/lib/src/theme/message_theme.dart create mode 100644 packages/stream_chat_flutter/lib/src/theme/text_theme.dart create mode 100644 packages/stream_chat_flutter/lib/src/theme/themes.dart create mode 100644 packages/stream_chat_flutter/lib/src/theme/user_list_view_theme.dart diff --git a/packages/stream_chat_flutter/lib/src/attachment/attachment_title.dart b/packages/stream_chat_flutter/lib/src/attachment/attachment_title.dart index b068a8f9..d0f45aad 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/attachment_title.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/attachment_title.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/src/theme/themes.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; diff --git a/packages/stream_chat_flutter/lib/src/attachment/image_attachment.dart b/packages/stream_chat_flutter/lib/src/attachment/image_attachment.dart index 20174567..f912f282 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/image_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/image_attachment.dart @@ -4,6 +4,7 @@ import 'package:shimmer/shimmer.dart'; import 'package:stream_chat_flutter/src/attachment/attachment_title.dart'; import 'package:stream_chat_flutter/src/attachment/attachment_upload_state_builder.dart'; import 'package:stream_chat_flutter/src/attachment/attachment_widget.dart'; +import 'package:stream_chat_flutter/src/theme/themes.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; diff --git a/packages/stream_chat_flutter/lib/src/attachment/video_attachment.dart b/packages/stream_chat_flutter/lib/src/attachment/video_attachment.dart index b743cda1..b976532a 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/video_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/video_attachment.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/attachment/attachment_title.dart'; import 'package:stream_chat_flutter/src/attachment/attachment_widget.dart'; import 'package:stream_chat_flutter/src/full_screen_media.dart'; +import 'package:stream_chat_flutter/src/theme/themes.dart'; import 'package:stream_chat_flutter/src/video_thumbnail_image.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; diff --git a/packages/stream_chat_flutter/lib/src/channel_list_view.dart b/packages/stream_chat_flutter/lib/src/channel_list_view.dart index 32dde4b6..ba086f41 100644 --- a/packages/stream_chat_flutter/lib/src/channel_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/channel_list_view.dart @@ -5,6 +5,7 @@ import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:shimmer/shimmer.dart'; import 'package:stream_chat_flutter/src/channel_bottom_sheet.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; +import 'package:stream_chat_flutter/src/theme/themes.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; diff --git a/packages/stream_chat_flutter/lib/src/deleted_message.dart b/packages/stream_chat_flutter/lib/src/deleted_message.dart index 011b0c72..a973deb7 100644 --- a/packages/stream_chat_flutter/lib/src/deleted_message.dart +++ b/packages/stream_chat_flutter/lib/src/deleted_message.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; +import 'package:stream_chat_flutter/src/theme/themes.dart'; /// Widget to display deleted message class DeletedMessage extends StatelessWidget { diff --git a/packages/stream_chat_flutter/lib/src/gallery_footer.dart b/packages/stream_chat_flutter/lib/src/gallery_footer.dart index c26c8dbc..53b20675 100644 --- a/packages/stream_chat_flutter/lib/src/gallery_footer.dart +++ b/packages/stream_chat_flutter/lib/src/gallery_footer.dart @@ -8,6 +8,7 @@ import 'package:flutter/material.dart'; import 'package:path_provider/path_provider.dart'; import 'package:share_plus/share_plus.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; +import 'package:stream_chat_flutter/src/theme/themes.dart'; import 'package:stream_chat_flutter/src/video_thumbnail_image.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; diff --git a/packages/stream_chat_flutter/lib/src/gallery_header.dart b/packages/stream_chat_flutter/lib/src/gallery_header.dart index 6c4ecfee..ad2969cb 100644 --- a/packages/stream_chat_flutter/lib/src/gallery_header.dart +++ b/packages/stream_chat_flutter/lib/src/gallery_header.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/attachment_actions_modal.dart'; import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; +import 'package:stream_chat_flutter/src/theme/themes.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; /// Header/AppBar widget for media display screen diff --git a/packages/stream_chat_flutter/lib/src/image_group.dart b/packages/stream_chat_flutter/lib/src/image_group.dart index 4647fe57..ec50f294 100644 --- a/packages/stream_chat_flutter/lib/src/image_group.dart +++ b/packages/stream_chat_flutter/lib/src/image_group.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/full_screen_media.dart'; +import 'package:stream_chat_flutter/src/theme/themes.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; diff --git a/packages/stream_chat_flutter/lib/src/message_actions_modal.dart b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart index 128918ad..efaf0ded 100644 --- a/packages/stream_chat_flutter/lib/src/message_actions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart @@ -6,6 +6,7 @@ import 'package:stream_chat_flutter/src/extension.dart'; import 'package:stream_chat_flutter/src/message_action.dart'; import 'package:stream_chat_flutter/src/reaction_picker.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; +import 'package:stream_chat_flutter/src/theme/themes.dart'; import 'package:stream_chat_flutter/src/utils.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index 635e86c1..e7279579 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -14,6 +14,7 @@ import 'package:stream_chat_flutter/src/message_widget.dart'; import 'package:stream_chat_flutter/src/stream_svg_icon.dart'; import 'package:stream_chat_flutter/src/swipeable.dart'; import 'package:stream_chat_flutter/src/system_message.dart'; +import 'package:stream_chat_flutter/src/theme/themes.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:visibility_detector/visibility_detector.dart'; diff --git a/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart b/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart index fadef6ff..669af376 100644 --- a/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/reaction_bubble.dart'; import 'package:stream_chat_flutter/src/reaction_picker.dart'; import 'package:stream_chat_flutter/src/stream_chat.dart'; +import 'package:stream_chat_flutter/src/theme/themes.dart'; import 'package:stream_chat_flutter/src/user_avatar.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; diff --git a/packages/stream_chat_flutter/lib/src/message_search_list_view.dart b/packages/stream_chat_flutter/lib/src/message_search_list_view.dart index 13f5ea55..59e09507 100644 --- a/packages/stream_chat_flutter/lib/src/message_search_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_search_list_view.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/info_tile.dart'; import 'package:stream_chat_flutter/src/message_search_item.dart'; +import 'package:stream_chat_flutter/src/theme/themes.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; diff --git a/packages/stream_chat_flutter/lib/src/message_text.dart b/packages/stream_chat_flutter/lib/src/message_text.dart index 6d006085..c11dc2fc 100644 --- a/packages/stream_chat_flutter/lib/src/message_text.dart +++ b/packages/stream_chat_flutter/lib/src/message_text.dart @@ -1,6 +1,7 @@ import 'package:collection/collection.dart' show IterableExtension; import 'package:flutter/material.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; +import 'package:stream_chat_flutter/src/theme/themes.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; diff --git a/packages/stream_chat_flutter/lib/src/message_widget.dart b/packages/stream_chat_flutter/lib/src/message_widget.dart index e73f3a6d..133b5dc7 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget.dart @@ -14,6 +14,7 @@ import 'package:stream_chat_flutter/src/message_actions_modal.dart'; import 'package:stream_chat_flutter/src/message_reactions_modal.dart'; import 'package:stream_chat_flutter/src/quoted_message_widget.dart'; import 'package:stream_chat_flutter/src/reaction_bubble.dart'; +import 'package:stream_chat_flutter/src/theme/themes.dart'; import 'package:stream_chat_flutter/src/url_attachment.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; diff --git a/packages/stream_chat_flutter/lib/src/quoted_message_widget.dart b/packages/stream_chat_flutter/lib/src/quoted_message_widget.dart index 22ca4d4c..5cf53a65 100644 --- a/packages/stream_chat_flutter/lib/src/quoted_message_widget.dart +++ b/packages/stream_chat_flutter/lib/src/quoted_message_widget.dart @@ -1,6 +1,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/extension.dart'; +import 'package:stream_chat_flutter/src/theme/themes.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; import 'package:video_player/video_player.dart'; diff --git a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart index 9d2df266..4336325b 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart @@ -1,11 +1,10 @@ import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:stream_chat_flutter/src/channel_header.dart'; +import 'package:flutter/material.dart' hide TextTheme; import 'package:stream_chat_flutter/src/channel_preview.dart'; -import 'package:stream_chat_flutter/src/extension.dart'; import 'package:stream_chat_flutter/src/gradient_avatar.dart'; import 'package:stream_chat_flutter/src/message_input.dart'; import 'package:stream_chat_flutter/src/reaction_icon.dart'; +import 'package:stream_chat_flutter/src/theme/themes.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; @@ -492,1702 +491,3 @@ class StreamChatThemeData { } } -/// Class for holding text theme -class TextTheme { - /// Initialise light text theme - TextTheme.light({ - this.title = const TextStyle( - fontSize: 22, - fontWeight: FontWeight.bold, - color: Colors.black, - ), - this.headlineBold = const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.black, - ), - this.headline = const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: Colors.black, - ), - this.bodyBold = const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: Colors.black, - ), - this.body = const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Colors.black, - ), - this.footnoteBold = const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: Colors.black, - ), - this.footnote = const TextStyle( - fontSize: 12, - color: Colors.black, - ), - this.captionBold = const TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: Colors.black, - ), - }); - - /// Initialise with dark theme - TextTheme.dark({ - this.title = const TextStyle( - fontSize: 22, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - this.headlineBold = const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - this.headline = const TextStyle( - fontSize: 16, - fontWeight: FontWeight.w500, - color: Colors.white, - ), - this.bodyBold = const TextStyle( - fontSize: 14, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - this.body = const TextStyle( - fontSize: 14, - fontWeight: FontWeight.w500, - color: Colors.white, - ), - this.footnoteBold = const TextStyle( - fontSize: 12, - fontWeight: FontWeight.w500, - color: Colors.white, - ), - this.footnote = const TextStyle( - fontSize: 12, - color: Colors.white, - ), - this.captionBold = const TextStyle( - fontSize: 10, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - }); - - /// Text theme for title - final TextStyle title; - - /// Body Text theme for headline - final TextStyle headlineBold; - - /// Text theme for headline - final TextStyle headline; - - /// Bold Text theme for body - final TextStyle bodyBold; - - /// Text theme body - final TextStyle body; - - /// Bold Text theme for footnote - final TextStyle footnoteBold; - - /// Text theme for footnote - final TextStyle footnote; - - /// Bold Text theme for caption - final TextStyle captionBold; - - /// Copy with theme - TextTheme copyWith({ - Brightness brightness = Brightness.light, - TextStyle? body, - TextStyle? title, - TextStyle? headlineBold, - TextStyle? headline, - TextStyle? bodyBold, - TextStyle? footnoteBold, - TextStyle? footnote, - TextStyle? captionBold, - }) => - brightness == Brightness.light - ? TextTheme.light( - body: body ?? this.body, - title: title ?? this.title, - headlineBold: headlineBold ?? this.headlineBold, - headline: headline ?? this.headline, - bodyBold: bodyBold ?? this.bodyBold, - footnoteBold: footnoteBold ?? this.footnoteBold, - footnote: footnote ?? this.footnote, - captionBold: captionBold ?? this.captionBold, - ) - : TextTheme.dark( - body: body ?? this.body, - title: title ?? this.title, - headlineBold: headlineBold ?? this.headlineBold, - headline: headline ?? this.headline, - bodyBold: bodyBold ?? this.bodyBold, - footnoteBold: footnoteBold ?? this.footnoteBold, - footnote: footnote ?? this.footnote, - captionBold: captionBold ?? this.captionBold, - ); - - /// Merge text theme - TextTheme merge(TextTheme? other) { - if (other == null) return this; - return copyWith( - body: body.merge(other.body), - title: title.merge(other.title), - headlineBold: headlineBold.merge(other.headlineBold), - headline: headline.merge(other.headline), - bodyBold: bodyBold.merge(other.bodyBold), - footnoteBold: footnoteBold.merge(other.footnoteBold), - footnote: footnote.merge(other.footnote), - captionBold: captionBold.merge(other.captionBold), - ); - } -} - -/// Theme that holds colors -class ColorTheme { - /// Initialise with light theme - ColorTheme.light({ - this.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, - ); - } -} - -/// Channel theme data -class ChannelTheme { - /// Constructor for creating [ChannelTheme] - ChannelTheme({ - required this.channelHeaderTheme, - }); - - /// Theme of the [ChannelHeader] widget - final ChannelHeaderTheme channelHeaderTheme; - - /// Creates a copy of [ChannelTheme] with specified attributes overridden. - ChannelTheme copyWith({ - ChannelHeaderTheme? channelHeaderTheme, - }) => - ChannelTheme( - channelHeaderTheme: channelHeaderTheme ?? this.channelHeaderTheme, - ); - - /// Merge with theme - ChannelTheme merge(ChannelTheme? other) { - if (other == null) return this; - return copyWith( - channelHeaderTheme: channelHeaderTheme.merge(other.channelHeaderTheme), - ); - } -} - -/// Theme for avatar -class AvatarTheme { - /// Constructor for creating [AvatarTheme] - AvatarTheme({ - BoxConstraints? constraints, - BorderRadius? borderRadius, - }) : _constraints = constraints, - _borderRadius = borderRadius; - - final BoxConstraints? _constraints; - final BorderRadius? _borderRadius; - - /// Get constraints for avatar - BoxConstraints get constraints => - _constraints ?? - const BoxConstraints.tightFor( - height: 32, - width: 32, - ); - - /// Get border radius - BorderRadius get borderRadius => _borderRadius ?? BorderRadius.circular(20); - - /// Copy with another theme - AvatarTheme copyWith({ - BoxConstraints? constraints, - BorderRadius? borderRadius, - }) => - AvatarTheme( - constraints: constraints ?? _constraints, - borderRadius: borderRadius ?? _borderRadius, - ); - - /// Merge with another AvatarTheme - AvatarTheme merge(AvatarTheme? other) { - if (other == null) return this; - return copyWith( - constraints: other._constraints, - borderRadius: other._borderRadius, - ); - } -} - -/// Class for getting message theme -class MessageTheme { - /// Constructor into [MessageTheme] - const MessageTheme({ - this.replies, - this.messageText, - this.messageAuthor, - this.messageLinks, - this.messageBackgroundColor, - this.messageBorderColor, - this.reactionsBackgroundColor, - this.reactionsBorderColor, - this.reactionsMaskColor, - this.avatarTheme, - this.createdAt, - }); - - /// Text style for message text - final TextStyle? messageText; - - /// Text style for message author - final TextStyle? messageAuthor; - - /// Text style for message links - final TextStyle? messageLinks; - - /// Text style for created at text - final TextStyle? createdAt; - - /// Text style for replies - final TextStyle? replies; - - /// Color for messageBackgroundColor - final Color? messageBackgroundColor; - - /// Color for message border color - final Color? messageBorderColor; - - /// Color for reactions - final Color? reactionsBackgroundColor; - - /// Colors reaction border - final Color? reactionsBorderColor; - - /// Color for reaction mask - final Color? reactionsMaskColor; - - /// Theme of the avatar - final AvatarTheme? avatarTheme; - - /// Copy with a theme - MessageTheme copyWith({ - TextStyle? messageText, - TextStyle? messageAuthor, - TextStyle? messageLinks, - TextStyle? createdAt, - TextStyle? replies, - Color? messageBackgroundColor, - Color? messageBorderColor, - AvatarTheme? avatarTheme, - Color? reactionsBackgroundColor, - Color? reactionsBorderColor, - Color? reactionsMaskColor, - }) => - MessageTheme( - messageText: messageText ?? this.messageText, - messageAuthor: messageAuthor ?? this.messageAuthor, - messageLinks: messageLinks ?? this.messageLinks, - createdAt: createdAt ?? this.createdAt, - messageBackgroundColor: - messageBackgroundColor ?? this.messageBackgroundColor, - messageBorderColor: messageBorderColor ?? this.messageBorderColor, - avatarTheme: avatarTheme ?? this.avatarTheme, - replies: replies ?? this.replies, - reactionsBackgroundColor: - reactionsBackgroundColor ?? this.reactionsBackgroundColor, - reactionsBorderColor: reactionsBorderColor ?? this.reactionsBorderColor, - reactionsMaskColor: reactionsMaskColor ?? this.reactionsMaskColor, - ); - - /// Merge with a theme - MessageTheme merge(MessageTheme? other) { - if (other == null) return this; - return copyWith( - messageText: messageText?.merge(other.messageText) ?? other.messageText, - messageAuthor: - messageAuthor?.merge(other.messageAuthor) ?? other.messageAuthor, - messageLinks: - messageLinks?.merge(other.messageLinks) ?? other.messageLinks, - createdAt: createdAt?.merge(other.createdAt) ?? other.createdAt, - replies: replies?.merge(other.replies) ?? other.replies, - messageBackgroundColor: other.messageBackgroundColor, - messageBorderColor: other.messageBorderColor, - avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, - reactionsBackgroundColor: other.reactionsBackgroundColor, - reactionsBorderColor: other.reactionsBorderColor, - reactionsMaskColor: other.reactionsMaskColor, - ); - } -} - -/// Theme for channel preview -class ChannelPreviewTheme { - /// Constructor for creating [ChannelPreviewTheme] - const ChannelPreviewTheme({ - this.title, - this.subtitle, - this.lastMessageAt, - this.avatarTheme, - this.unreadCounterColor, - this.indicatorIconSize, - }); - - /// Theme for title - final TextStyle? title; - - /// Theme for subtitle - final TextStyle? subtitle; - - /// Theme of last message at - final TextStyle? lastMessageAt; - - /// Avatar theme - final AvatarTheme? avatarTheme; - - /// Unread counter color - final Color? unreadCounterColor; - - /// Indicator icon size - final double? indicatorIconSize; - - /// Copy with theme - ChannelPreviewTheme copyWith({ - TextStyle? title, - TextStyle? subtitle, - TextStyle? lastMessageAt, - AvatarTheme? avatarTheme, - Color? unreadCounterColor, - double? indicatorIconSize, - }) => - ChannelPreviewTheme( - title: title ?? this.title, - subtitle: subtitle ?? this.subtitle, - lastMessageAt: lastMessageAt ?? this.lastMessageAt, - avatarTheme: avatarTheme ?? this.avatarTheme, - unreadCounterColor: unreadCounterColor ?? this.unreadCounterColor, - indicatorIconSize: indicatorIconSize ?? this.indicatorIconSize, - ); - - /// Merge with theme - ChannelPreviewTheme merge(ChannelPreviewTheme? other) { - if (other == null) return this; - return copyWith( - title: title?.merge(other.title) ?? other.title, - subtitle: subtitle?.merge(other.subtitle) ?? other.subtitle, - lastMessageAt: - lastMessageAt?.merge(other.lastMessageAt) ?? other.lastMessageAt, - avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, - unreadCounterColor: other.unreadCounterColor, - ); - } -} - -/// Theme for [ChannelHeader] -class ChannelHeaderTheme { - /// Constructor for creating a [ChannelHeaderTheme] - const ChannelHeaderTheme({ - this.title, - this.subtitle, - this.avatarTheme, - this.color, - }); - - /// Theme for title - final TextStyle? title; - - /// Theme for subtitle - final TextStyle? subtitle; - - /// Theme for avatar - final AvatarTheme? avatarTheme; - - /// Color for [ChannelHeaderTheme] - final Color? color; - - /// Copy with theme - ChannelHeaderTheme copyWith({ - TextStyle? title, - TextStyle? subtitle, - AvatarTheme? avatarTheme, - Color? color, - }) => - ChannelHeaderTheme( - title: title ?? this.title, - subtitle: subtitle ?? this.subtitle, - avatarTheme: avatarTheme ?? this.avatarTheme, - color: color ?? this.color, - ); - - /// Merge with other [ChannelHeaderTheme] - ChannelHeaderTheme merge(ChannelHeaderTheme? other) { - if (other == null) return this; - return copyWith( - title: title?.merge(other.title) ?? other.title, - subtitle: subtitle?.merge(other.subtitle) ?? other.subtitle, - avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, - color: other.color, - ); - } -} - -/// Theme dedicated to the [ChannelListHeader] -class ChannelListHeaderTheme { - /// Returns a new [ChannelListHeaderTheme] - const ChannelListHeaderTheme({ - this.title, - this.avatarTheme, - this.color, - }); - - /// Style of the title text - final TextStyle? title; - - /// Theme dedicated to the userAvatar - final AvatarTheme? avatarTheme; - - /// Background color of the appbar - final Color? color; - - /// Returns a new [ChannelListHeaderTheme] replacing some of its properties - ChannelListHeaderTheme copyWith({ - TextStyle? title, - AvatarTheme? avatarTheme, - Color? color, - }) => - ChannelListHeaderTheme( - title: title ?? this.title, - avatarTheme: avatarTheme ?? this.avatarTheme, - color: color ?? this.color, - ); - - /// Merges [this] [ChannelListHeaderTheme] with the [other] - ChannelListHeaderTheme merge(ChannelListHeaderTheme? other) { - if (other == null) return this; - return copyWith( - title: title?.merge(other.title) ?? other.title, - avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, - color: other.color, - ); - } -} - -/// Defines the theme dedicated to the [MessageInput] widget -class MessageInputTheme { - /// Returns a new [MessageInputTheme] - const MessageInputTheme({ - this.sendAnimationDuration, - this.actionButtonColor, - this.sendButtonColor, - this.actionButtonIdleColor, - this.sendButtonIdleColor, - this.inputBackground, - this.inputTextStyle, - this.inputDecoration, - this.activeBorderGradient, - this.idleBorderGradient, - this.borderRadius, - this.expandButtonColor, - }); - - /// Duration of the [MessageInput] send button animation - final Duration? sendAnimationDuration; - - /// Background color of [MessageInput] send button - final Color? sendButtonColor; - - /// Background color of [MessageInput] action buttons - final Color? actionButtonColor; - - /// Background color of [MessageInput] send button - final Color? sendButtonIdleColor; - - /// Background color of [MessageInput] action buttons - final Color? actionButtonIdleColor; - - /// Background color of [MessageInput] expand button - final Color? expandButtonColor; - - /// Background color of [MessageInput] - final Color? inputBackground; - - /// TextStyle of [MessageInput] - final TextStyle? inputTextStyle; - - /// InputDecoration of [MessageInput] - final InputDecoration? inputDecoration; - - /// Border gradient when the [MessageInput] is not focused - final Gradient? idleBorderGradient; - - /// Border gradient when the [MessageInput] is focused - final Gradient? activeBorderGradient; - - /// Border radius of [MessageInput] - final BorderRadius? borderRadius; - - /// Returns a new [MessageInputTheme] replacing some of its properties - MessageInputTheme copyWith({ - Duration? sendAnimationDuration, - Color? inputBackground, - Color? actionButtonColor, - Color? sendButtonColor, - Color? actionButtonIdleColor, - Color? sendButtonIdleColor, - Color? expandButtonColor, - TextStyle? inputTextStyle, - InputDecoration? inputDecoration, - Gradient? activeBorderGradient, - Gradient? idleBorderGradient, - BorderRadius? borderRadius, - }) => - MessageInputTheme( - sendAnimationDuration: - sendAnimationDuration ?? this.sendAnimationDuration, - inputBackground: inputBackground ?? this.inputBackground, - actionButtonColor: actionButtonColor ?? this.actionButtonColor, - sendButtonColor: sendButtonColor ?? this.sendButtonColor, - actionButtonIdleColor: - actionButtonIdleColor ?? this.actionButtonIdleColor, - expandButtonColor: expandButtonColor ?? this.expandButtonColor, - inputTextStyle: inputTextStyle ?? this.inputTextStyle, - sendButtonIdleColor: sendButtonIdleColor ?? this.sendButtonIdleColor, - inputDecoration: inputDecoration ?? this.inputDecoration, - activeBorderGradient: activeBorderGradient ?? this.activeBorderGradient, - idleBorderGradient: idleBorderGradient ?? this.idleBorderGradient, - borderRadius: borderRadius ?? this.borderRadius, - ); - - /// Merges [this] [MessageInputTheme] with the [other] - MessageInputTheme merge(MessageInputTheme? other) { - if (other == null) return this; - return copyWith( - sendAnimationDuration: other.sendAnimationDuration, - inputBackground: other.inputBackground, - actionButtonColor: other.actionButtonColor, - actionButtonIdleColor: other.actionButtonIdleColor, - sendButtonColor: other.sendButtonColor, - sendButtonIdleColor: other.sendButtonIdleColor, - inputTextStyle: - inputTextStyle?.merge(other.inputTextStyle) ?? other.inputTextStyle, - inputDecoration: inputDecoration?.merge(other.inputDecoration) ?? - other.inputDecoration, - activeBorderGradient: other.activeBorderGradient, - idleBorderGradient: other.idleBorderGradient, - borderRadius: other.borderRadius, - expandButtonColor: other.expandButtonColor, - ); - } -} - -/// Effect store -class Effect { - /// Constructor for creating [Effect] - const Effect({ - this.sigmaX, - this.sigmaY, - this.color, - this.alpha, - this.blur, - }); - - /// - final double? sigmaX; - - /// - final double? sigmaY; - - /// - final Color? color; - - /// - final double? alpha; - - /// - final double? blur; - - /// Copy with new effect - Effect copyWith({ - double? sigmaX, - double? sigmaY, - Color? color, - double? alpha, - double? blur, - }) => - Effect( - sigmaX: sigmaX ?? this.sigmaX, - sigmaY: sigmaY ?? this.sigmaY, - color: color ?? this.color, - alpha: color as double? ?? this.alpha, - blur: blur ?? this.blur, - ); -} - -/// Overrides the default style of [GalleryHeader] descendants. -/// -/// See also: -/// -/// * [GalleryHeaderThemeData], which is used to configure this theme. -class GalleryHeaderTheme extends InheritedTheme { - /// Creates an [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(); - 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.subtitle]. - 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)); - } -} - -/// 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(); - 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)); - } -} - -/// 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(); - 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)); - } -} - -/// 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(); - 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)); - } -} - -/// 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(); - 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)); - } -} - -/// 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(); - 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)); - } -} diff --git a/packages/stream_chat_flutter/lib/src/theme/avatar_theme.dart b/packages/stream_chat_flutter/lib/src/theme/avatar_theme.dart new file mode 100644 index 00000000..f3e68597 --- /dev/null +++ b/packages/stream_chat_flutter/lib/src/theme/avatar_theme.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; + +/// Theme for avatar +class AvatarTheme { + /// Constructor for creating [AvatarTheme] + AvatarTheme({ + BoxConstraints? constraints, + BorderRadius? borderRadius, + }) : _constraints = constraints, + _borderRadius = borderRadius; + + final BoxConstraints? _constraints; + final BorderRadius? _borderRadius; + + /// Get constraints for avatar + BoxConstraints get constraints => + _constraints ?? + const BoxConstraints.tightFor( + height: 32, + width: 32, + ); + + /// Get border radius + BorderRadius get borderRadius => _borderRadius ?? BorderRadius.circular(20); + + /// Copy with another theme + AvatarTheme copyWith({ + BoxConstraints? constraints, + BorderRadius? borderRadius, + }) => + AvatarTheme( + constraints: constraints ?? _constraints, + borderRadius: borderRadius ?? _borderRadius, + ); + + /// Merge with another AvatarTheme + AvatarTheme merge(AvatarTheme? other) { + if (other == null) return this; + return copyWith( + constraints: other._constraints, + borderRadius: other._borderRadius, + ); + } +} \ No newline at end of file diff --git a/packages/stream_chat_flutter/lib/src/theme/channel_header_theme.dart b/packages/stream_chat_flutter/lib/src/theme/channel_header_theme.dart new file mode 100644 index 00000000..2072b3c5 --- /dev/null +++ b/packages/stream_chat_flutter/lib/src/theme/channel_header_theme.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/src/theme/avatar_theme.dart'; + +/// Theme for [ChannelHeader] +class ChannelHeaderTheme { + /// Constructor for creating a [ChannelHeaderTheme] + const ChannelHeaderTheme({ + this.title, + this.subtitle, + this.avatarTheme, + this.color, + }); + + /// Theme for title + final TextStyle? title; + + /// Theme for subtitle + final TextStyle? subtitle; + + /// Theme for avatar + final AvatarTheme? avatarTheme; + + /// Color for [ChannelHeaderTheme] + final Color? color; + + /// Copy with theme + ChannelHeaderTheme copyWith({ + TextStyle? title, + TextStyle? subtitle, + AvatarTheme? avatarTheme, + Color? color, + }) => + ChannelHeaderTheme( + title: title ?? this.title, + subtitle: subtitle ?? this.subtitle, + avatarTheme: avatarTheme ?? this.avatarTheme, + color: color ?? this.color, + ); + + /// Merge with other [ChannelHeaderTheme] + ChannelHeaderTheme merge(ChannelHeaderTheme? other) { + if (other == null) return this; + return copyWith( + title: title?.merge(other.title) ?? other.title, + subtitle: subtitle?.merge(other.subtitle) ?? other.subtitle, + avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, + color: other.color, + ); + } +} \ No newline at end of file diff --git a/packages/stream_chat_flutter/lib/src/theme/channel_list_header_theme.dart b/packages/stream_chat_flutter/lib/src/theme/channel_list_header_theme.dart new file mode 100644 index 00000000..ca36b9bd --- /dev/null +++ b/packages/stream_chat_flutter/lib/src/theme/channel_list_header_theme.dart @@ -0,0 +1,43 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/src/theme/avatar_theme.dart'; + +/// Theme dedicated to the [ChannelListHeader] +class ChannelListHeaderTheme { + /// Returns a new [ChannelListHeaderTheme] + const ChannelListHeaderTheme({ + this.title, + this.avatarTheme, + this.color, + }); + + /// Style of the title text + final TextStyle? title; + + /// Theme dedicated to the userAvatar + final AvatarTheme? avatarTheme; + + /// Background color of the appbar + final Color? color; + + /// Returns a new [ChannelListHeaderTheme] replacing some of its properties + ChannelListHeaderTheme copyWith({ + TextStyle? title, + AvatarTheme? avatarTheme, + Color? color, + }) => + ChannelListHeaderTheme( + title: title ?? this.title, + avatarTheme: avatarTheme ?? this.avatarTheme, + color: color ?? this.color, + ); + + /// Merges [this] [ChannelListHeaderTheme] with the [other] + ChannelListHeaderTheme merge(ChannelListHeaderTheme? other) { + if (other == null) return this; + return copyWith( + title: title?.merge(other.title) ?? other.title, + avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, + color: other.color, + ); + } +} \ No newline at end of file diff --git a/packages/stream_chat_flutter/lib/src/theme/channel_list_view_theme.dart b/packages/stream_chat_flutter/lib/src/theme/channel_list_view_theme.dart new file mode 100644 index 00000000..d310e2bc --- /dev/null +++ b/packages/stream_chat_flutter/lib/src/theme/channel_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 [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(); + 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)); + } +} diff --git a/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart b/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart new file mode 100644 index 00000000..4643bb8d --- /dev/null +++ b/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart @@ -0,0 +1,64 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/src/theme/avatar_theme.dart'; + +/// Theme for channel preview +class ChannelPreviewTheme { + /// Constructor for creating [ChannelPreviewTheme] + const ChannelPreviewTheme({ + this.title, + this.subtitle, + this.lastMessageAt, + this.avatarTheme, + this.unreadCounterColor, + this.indicatorIconSize, + }); + + /// Theme for title + final TextStyle? title; + + /// Theme for subtitle + final TextStyle? subtitle; + + /// Theme of last message at + final TextStyle? lastMessageAt; + + /// Avatar theme + final AvatarTheme? avatarTheme; + + /// Unread counter color + final Color? unreadCounterColor; + + /// Indicator icon size + final double? indicatorIconSize; + + /// Copy with theme + ChannelPreviewTheme copyWith({ + TextStyle? title, + TextStyle? subtitle, + TextStyle? lastMessageAt, + AvatarTheme? avatarTheme, + Color? unreadCounterColor, + double? indicatorIconSize, + }) => + ChannelPreviewTheme( + title: title ?? this.title, + subtitle: subtitle ?? this.subtitle, + lastMessageAt: lastMessageAt ?? this.lastMessageAt, + avatarTheme: avatarTheme ?? this.avatarTheme, + unreadCounterColor: unreadCounterColor ?? this.unreadCounterColor, + indicatorIconSize: indicatorIconSize ?? this.indicatorIconSize, + ); + + /// Merge with theme + ChannelPreviewTheme merge(ChannelPreviewTheme? other) { + if (other == null) return this; + return copyWith( + title: title?.merge(other.title) ?? other.title, + subtitle: subtitle?.merge(other.subtitle) ?? other.subtitle, + lastMessageAt: + lastMessageAt?.merge(other.lastMessageAt) ?? other.lastMessageAt, + avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, + unreadCounterColor: other.unreadCounterColor, + ); + } +} \ No newline at end of file diff --git a/packages/stream_chat_flutter/lib/src/theme/channel_theme.dart b/packages/stream_chat_flutter/lib/src/theme/channel_theme.dart new file mode 100644 index 00000000..bf752f94 --- /dev/null +++ b/packages/stream_chat_flutter/lib/src/theme/channel_theme.dart @@ -0,0 +1,28 @@ +import 'package:stream_chat_flutter/src/theme/channel_header_theme.dart'; + +/// Channel theme data +class ChannelTheme { + /// Constructor for creating [ChannelTheme] + ChannelTheme({ + required this.channelHeaderTheme, + }); + + /// Theme of the [ChannelHeader] widget + final ChannelHeaderTheme channelHeaderTheme; + + /// Creates a copy of [ChannelTheme] with specified attributes overridden. + ChannelTheme copyWith({ + ChannelHeaderTheme? channelHeaderTheme, + }) => + ChannelTheme( + channelHeaderTheme: channelHeaderTheme ?? this.channelHeaderTheme, + ); + + /// Merge with theme + ChannelTheme merge(ChannelTheme? other) { + if (other == null) return this; + return copyWith( + channelHeaderTheme: channelHeaderTheme.merge(other.channelHeaderTheme), + ); + } +} diff --git a/packages/stream_chat_flutter/lib/src/theme/color_theme.dart b/packages/stream_chat_flutter/lib/src/theme/color_theme.dart new file mode 100644 index 00000000..d021c6cf --- /dev/null +++ b/packages/stream_chat_flutter/lib/src/theme/color_theme.dart @@ -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, + ); +} diff --git a/packages/stream_chat_flutter/lib/src/theme/gallery_footer_theme.dart b/packages/stream_chat_flutter/lib/src/theme/gallery_footer_theme.dart new file mode 100644 index 00000000..bdf273e7 --- /dev/null +++ b/packages/stream_chat_flutter/lib/src/theme/gallery_footer_theme.dart @@ -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(); + 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)); + } +} diff --git a/packages/stream_chat_flutter/lib/src/theme/gallery_header_theme.dart b/packages/stream_chat_flutter/lib/src/theme/gallery_header_theme.dart new file mode 100644 index 00000000..9b5faa83 --- /dev/null +++ b/packages/stream_chat_flutter/lib/src/theme/gallery_header_theme.dart @@ -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 an [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(); + 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.subtitle]. + 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)); + } +} diff --git a/packages/stream_chat_flutter/lib/src/theme/message_input_theme.dart b/packages/stream_chat_flutter/lib/src/theme/message_input_theme.dart new file mode 100644 index 00000000..b8889e6b --- /dev/null +++ b/packages/stream_chat_flutter/lib/src/theme/message_input_theme.dart @@ -0,0 +1,110 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/src/extension.dart'; + +/// Defines the theme dedicated to the [MessageInput] widget +class MessageInputTheme { + /// Returns a new [MessageInputTheme] + const MessageInputTheme({ + this.sendAnimationDuration, + this.actionButtonColor, + this.sendButtonColor, + this.actionButtonIdleColor, + this.sendButtonIdleColor, + this.inputBackground, + this.inputTextStyle, + this.inputDecoration, + this.activeBorderGradient, + this.idleBorderGradient, + this.borderRadius, + this.expandButtonColor, + }); + + /// Duration of the [MessageInput] send button animation + final Duration? sendAnimationDuration; + + /// Background color of [MessageInput] send button + final Color? sendButtonColor; + + /// Background color of [MessageInput] action buttons + final Color? actionButtonColor; + + /// Background color of [MessageInput] send button + final Color? sendButtonIdleColor; + + /// Background color of [MessageInput] action buttons + final Color? actionButtonIdleColor; + + /// Background color of [MessageInput] expand button + final Color? expandButtonColor; + + /// Background color of [MessageInput] + final Color? inputBackground; + + /// TextStyle of [MessageInput] + final TextStyle? inputTextStyle; + + /// InputDecoration of [MessageInput] + final InputDecoration? inputDecoration; + + /// Border gradient when the [MessageInput] is not focused + final Gradient? idleBorderGradient; + + /// Border gradient when the [MessageInput] is focused + final Gradient? activeBorderGradient; + + /// Border radius of [MessageInput] + final BorderRadius? borderRadius; + + /// Returns a new [MessageInputTheme] replacing some of its properties + MessageInputTheme copyWith({ + Duration? sendAnimationDuration, + Color? inputBackground, + Color? actionButtonColor, + Color? sendButtonColor, + Color? actionButtonIdleColor, + Color? sendButtonIdleColor, + Color? expandButtonColor, + TextStyle? inputTextStyle, + InputDecoration? inputDecoration, + Gradient? activeBorderGradient, + Gradient? idleBorderGradient, + BorderRadius? borderRadius, + }) => + MessageInputTheme( + sendAnimationDuration: + sendAnimationDuration ?? this.sendAnimationDuration, + inputBackground: inputBackground ?? this.inputBackground, + actionButtonColor: actionButtonColor ?? this.actionButtonColor, + sendButtonColor: sendButtonColor ?? this.sendButtonColor, + actionButtonIdleColor: + actionButtonIdleColor ?? this.actionButtonIdleColor, + expandButtonColor: expandButtonColor ?? this.expandButtonColor, + inputTextStyle: inputTextStyle ?? this.inputTextStyle, + sendButtonIdleColor: sendButtonIdleColor ?? this.sendButtonIdleColor, + inputDecoration: inputDecoration ?? this.inputDecoration, + activeBorderGradient: activeBorderGradient ?? this.activeBorderGradient, + idleBorderGradient: idleBorderGradient ?? this.idleBorderGradient, + borderRadius: borderRadius ?? this.borderRadius, + ); + + /// Merges [this] [MessageInputTheme] with the [other] + MessageInputTheme merge(MessageInputTheme? other) { + if (other == null) return this; + return copyWith( + sendAnimationDuration: other.sendAnimationDuration, + inputBackground: other.inputBackground, + actionButtonColor: other.actionButtonColor, + actionButtonIdleColor: other.actionButtonIdleColor, + sendButtonColor: other.sendButtonColor, + sendButtonIdleColor: other.sendButtonIdleColor, + inputTextStyle: + inputTextStyle?.merge(other.inputTextStyle) ?? other.inputTextStyle, + inputDecoration: inputDecoration?.merge(other.inputDecoration) ?? + other.inputDecoration, + activeBorderGradient: other.activeBorderGradient, + idleBorderGradient: other.idleBorderGradient, + borderRadius: other.borderRadius, + expandButtonColor: other.expandButtonColor, + ); + } +} \ No newline at end of file diff --git a/packages/stream_chat_flutter/lib/src/theme/message_list_view_theme.dart b/packages/stream_chat_flutter/lib/src/theme/message_list_view_theme.dart new file mode 100644 index 00000000..49bd05f9 --- /dev/null +++ b/packages/stream_chat_flutter/lib/src/theme/message_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 [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(); + 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)); + } +} diff --git a/packages/stream_chat_flutter/lib/src/theme/message_search_list_view_theme.dart b/packages/stream_chat_flutter/lib/src/theme/message_search_list_view_theme.dart new file mode 100644 index 00000000..670e05e7 --- /dev/null +++ b/packages/stream_chat_flutter/lib/src/theme/message_search_list_view_theme.dart @@ -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(); + 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)); + } +} diff --git a/packages/stream_chat_flutter/lib/src/theme/message_theme.dart b/packages/stream_chat_flutter/lib/src/theme/message_theme.dart new file mode 100644 index 00000000..87543cb1 --- /dev/null +++ b/packages/stream_chat_flutter/lib/src/theme/message_theme.dart @@ -0,0 +1,103 @@ +import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/src/theme/avatar_theme.dart'; + +/// Class for getting message theme +class MessageTheme { + /// Constructor into [MessageTheme] + const MessageTheme({ + this.replies, + this.messageText, + this.messageAuthor, + this.messageLinks, + this.messageBackgroundColor, + this.messageBorderColor, + this.reactionsBackgroundColor, + this.reactionsBorderColor, + this.reactionsMaskColor, + this.avatarTheme, + this.createdAt, + }); + + /// Text style for message text + final TextStyle? messageText; + + /// Text style for message author + final TextStyle? messageAuthor; + + /// Text style for message links + final TextStyle? messageLinks; + + /// Text style for created at text + final TextStyle? createdAt; + + /// Text style for replies + final TextStyle? replies; + + /// Color for messageBackgroundColor + final Color? messageBackgroundColor; + + /// Color for message border color + final Color? messageBorderColor; + + /// Color for reactions + final Color? reactionsBackgroundColor; + + /// Colors reaction border + final Color? reactionsBorderColor; + + /// Color for reaction mask + final Color? reactionsMaskColor; + + /// Theme of the avatar + final AvatarTheme? avatarTheme; + + /// Copy with a theme + MessageTheme copyWith({ + TextStyle? messageText, + TextStyle? messageAuthor, + TextStyle? messageLinks, + TextStyle? createdAt, + TextStyle? replies, + Color? messageBackgroundColor, + Color? messageBorderColor, + AvatarTheme? avatarTheme, + Color? reactionsBackgroundColor, + Color? reactionsBorderColor, + Color? reactionsMaskColor, + }) => + MessageTheme( + messageText: messageText ?? this.messageText, + messageAuthor: messageAuthor ?? this.messageAuthor, + messageLinks: messageLinks ?? this.messageLinks, + createdAt: createdAt ?? this.createdAt, + messageBackgroundColor: + messageBackgroundColor ?? this.messageBackgroundColor, + messageBorderColor: messageBorderColor ?? this.messageBorderColor, + avatarTheme: avatarTheme ?? this.avatarTheme, + replies: replies ?? this.replies, + reactionsBackgroundColor: + reactionsBackgroundColor ?? this.reactionsBackgroundColor, + reactionsBorderColor: reactionsBorderColor ?? this.reactionsBorderColor, + reactionsMaskColor: reactionsMaskColor ?? this.reactionsMaskColor, + ); + + /// Merge with a theme + MessageTheme merge(MessageTheme? other) { + if (other == null) return this; + return copyWith( + messageText: messageText?.merge(other.messageText) ?? other.messageText, + messageAuthor: + messageAuthor?.merge(other.messageAuthor) ?? other.messageAuthor, + messageLinks: + messageLinks?.merge(other.messageLinks) ?? other.messageLinks, + createdAt: createdAt?.merge(other.createdAt) ?? other.createdAt, + replies: replies?.merge(other.replies) ?? other.replies, + messageBackgroundColor: other.messageBackgroundColor, + messageBorderColor: other.messageBorderColor, + avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, + reactionsBackgroundColor: other.reactionsBackgroundColor, + reactionsBorderColor: other.reactionsBorderColor, + reactionsMaskColor: other.reactionsMaskColor, + ); + } +} diff --git a/packages/stream_chat_flutter/lib/src/theme/text_theme.dart b/packages/stream_chat_flutter/lib/src/theme/text_theme.dart new file mode 100644 index 00000000..ec70cf83 --- /dev/null +++ b/packages/stream_chat_flutter/lib/src/theme/text_theme.dart @@ -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), + ); + } +} diff --git a/packages/stream_chat_flutter/lib/src/theme/themes.dart b/packages/stream_chat_flutter/lib/src/theme/themes.dart new file mode 100644 index 00000000..4236f874 --- /dev/null +++ b/packages/stream_chat_flutter/lib/src/theme/themes.dart @@ -0,0 +1,15 @@ +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 'channel_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'; \ No newline at end of file diff --git a/packages/stream_chat_flutter/lib/src/theme/user_list_view_theme.dart b/packages/stream_chat_flutter/lib/src/theme/user_list_view_theme.dart new file mode 100644 index 00000000..0d99ccbd --- /dev/null +++ b/packages/stream_chat_flutter/lib/src/theme/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(); + 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)); + } +} diff --git a/packages/stream_chat_flutter/lib/src/user_list_view.dart b/packages/stream_chat_flutter/lib/src/user_list_view.dart index 39d4453d..0374ffc8 100644 --- a/packages/stream_chat_flutter/lib/src/user_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/user_list_view.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:stream_chat_flutter/src/theme/themes.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart'; diff --git a/packages/stream_chat_flutter/lib/stream_chat_flutter.dart b/packages/stream_chat_flutter/lib/stream_chat_flutter.dart index 12049fc6..0a65d672 100644 --- a/packages/stream_chat_flutter/lib/stream_chat_flutter.dart +++ b/packages/stream_chat_flutter/lib/stream_chat_flutter.dart @@ -33,6 +33,7 @@ export 'src/stream_chat_theme.dart'; export 'src/stream_neumorphic_button.dart'; export 'src/stream_svg_icon.dart'; export 'src/system_message.dart'; +export 'src/theme/themes.dart'; export 'src/thread_header.dart'; export 'src/typing_indicator.dart'; export 'src/unread_indicator.dart'; From f90fd713c20844341cc086eb78056f7606286c7a Mon Sep 17 00:00:00 2001 From: groovinchip Date: Tue, 27 Jul 2021 10:32:49 -0400 Subject: [PATCH 02/42] chore: upgrade AvatarTheme * `AvatarTheme` is now an `InheritedTheme` and has a corresponding `AvatarThemeData` class --- .../example/lib/tutorial_part_6.dart | 4 +- .../lib/src/stream_chat_theme.dart | 23 +++- .../lib/src/theme/avatar_theme.dart | 113 +++++++++++++++--- .../lib/src/theme/channel_header_theme.dart | 4 +- .../src/theme/channel_list_header_theme.dart | 4 +- .../lib/src/theme/channel_preview_theme.dart | 4 +- .../lib/src/theme/gallery_header_theme.dart | 2 +- .../lib/src/theme/message_theme.dart | 4 +- 8 files changed, 127 insertions(+), 31 deletions(-) diff --git a/packages/stream_chat_flutter/example/lib/tutorial_part_6.dart b/packages/stream_chat_flutter/example/lib/tutorial_part_6.dart index cf94b568..1cf34d27 100644 --- a/packages/stream_chat_flutter/example/lib/tutorial_part_6.dart +++ b/packages/stream_chat_flutter/example/lib/tutorial_part_6.dart @@ -59,7 +59,7 @@ class MyApp extends StatelessWidget { final colorTheme = defaultTheme.colorTheme; final customTheme = defaultTheme.merge(StreamChatThemeData( channelPreviewTheme: ChannelPreviewTheme( - avatarTheme: AvatarTheme( + avatarTheme: AvatarThemeData( borderRadius: BorderRadius.circular(8), ), ), @@ -68,7 +68,7 @@ class MyApp extends StatelessWidget { messageText: TextStyle( color: colorTheme.barsBg, ), - avatarTheme: AvatarTheme( + avatarTheme: AvatarThemeData( borderRadius: BorderRadius.circular(8), ), ), diff --git a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart index 4336325b..d2eb0df0 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart @@ -62,6 +62,7 @@ class StreamChatThemeData { ChannelListViewThemeData? channelListViewTheme, UserListViewThemeData? userListViewTheme, MessageSearchListViewThemeData? messageSearchListViewTheme, + AvatarThemeData? avatarTheme, }) { brightness ??= colorTheme?.brightness ?? Brightness.light; final isDark = brightness == Brightness.dark; @@ -89,6 +90,7 @@ class StreamChatThemeData { channelListViewTheme: channelListViewTheme, userListViewTheme: userListViewTheme, messageSearchListViewTheme: messageSearchListViewTheme, + avatarTheme: avatarTheme, ); return defaultData.merge(customizedData); @@ -121,6 +123,7 @@ class StreamChatThemeData { required this.channelListViewTheme, required this.userListViewTheme, required this.messageSearchListViewTheme, + required this.avatarTheme, }); /// Create a theme from a Material [Theme] @@ -188,6 +191,9 @@ class StreamChatThemeData { /// Theme configuration for the [] widget. final MessageSearchListViewThemeData messageSearchListViewTheme; + /// Theme configuration for the [] widget. + final AvatarThemeData avatarTheme; + /// Creates a copy of [StreamChatThemeData] with specified attributes /// overridden. StreamChatThemeData copyWith({ @@ -208,6 +214,7 @@ class StreamChatThemeData { ChannelListViewThemeData? channelListViewTheme, UserListViewThemeData? userListViewTheme, MessageSearchListViewThemeData? messageSearchListViewTheme, + AvatarThemeData? avatarTheme, }) => StreamChatThemeData.raw( channelListHeaderTheme: @@ -230,6 +237,7 @@ class StreamChatThemeData { userListViewTheme: userListViewTheme ?? this.userListViewTheme, messageSearchListViewTheme: messageSearchListViewTheme ?? this.messageSearchListViewTheme, + avatarTheme: avatarTheme ?? this.avatarTheme, ); /// Merge themes @@ -257,6 +265,7 @@ class StreamChatThemeData { userListViewTheme: userListViewTheme.merge(other.userListViewTheme), messageSearchListViewTheme: messageSearchListViewTheme.merge(other.messageSearchListViewTheme), + avatarTheme: avatarTheme.merge(other.avatarTheme), ); } @@ -271,7 +280,7 @@ class StreamChatThemeData { IconThemeData(color: colorTheme.textHighEmphasis.withOpacity(.5)); final channelTheme = ChannelTheme( channelHeaderTheme: ChannelHeaderTheme( - avatarTheme: AvatarTheme( + avatarTheme: AvatarThemeData( borderRadius: BorderRadius.circular(20), constraints: const BoxConstraints.tightFor( height: 40, @@ -287,7 +296,7 @@ class StreamChatThemeData { ); final channelPreviewTheme = ChannelPreviewTheme( unreadCounterColor: colorTheme.accentError, - avatarTheme: AvatarTheme( + avatarTheme: AvatarThemeData( borderRadius: BorderRadius.circular(20), constraints: const BoxConstraints.tightFor( height: 40, @@ -315,7 +324,7 @@ class StreamChatThemeData { ), channelPreviewTheme: channelPreviewTheme, channelListHeaderTheme: ChannelListHeaderTheme( - avatarTheme: AvatarTheme( + avatarTheme: AvatarThemeData( borderRadius: BorderRadius.circular(20), constraints: const BoxConstraints.tightFor( height: 40, @@ -338,7 +347,7 @@ class StreamChatThemeData { reactionsBorderColor: colorTheme.borders, reactionsMaskColor: colorTheme.appBg, messageBorderColor: colorTheme.disabled, - avatarTheme: AvatarTheme( + avatarTheme: AvatarThemeData( borderRadius: BorderRadius.circular(20), constraints: const BoxConstraints.tightFor( height: 32, @@ -364,7 +373,7 @@ class StreamChatThemeData { ), messageBackgroundColor: colorTheme.barsBg, messageBorderColor: colorTheme.borders, - avatarTheme: AvatarTheme( + avatarTheme: AvatarThemeData( borderRadius: BorderRadius.circular(20), constraints: const BoxConstraints.tightFor( height: 32, @@ -487,7 +496,9 @@ class StreamChatThemeData { messageSearchListViewTheme: MessageSearchListViewThemeData( backgroundColor: colorTheme.appBg, ), + avatarTheme: AvatarThemeData( + borderRadius: BorderRadius.circular(8), + ), ); } } - diff --git a/packages/stream_chat_flutter/lib/src/theme/avatar_theme.dart b/packages/stream_chat_flutter/lib/src/theme/avatar_theme.dart index f3e68597..873bd259 100644 --- a/packages/stream_chat_flutter/lib/src/theme/avatar_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/avatar_theme.dart @@ -1,9 +1,62 @@ +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/themes.dart'; -/// Theme for avatar -class AvatarTheme { - /// Constructor for creating [AvatarTheme] - AvatarTheme({ +/// Overrides the default style of [UserAvatar] descendants. +/// +/// See also: +/// +/// * [AvatarThemeData], which is used to configure this theme. +class AvatarTheme extends InheritedTheme { + /// Creates an [AvatarTheme]. + /// + /// The [data] parameter must not be null. + const AvatarTheme({ + Key? key, + required this.data, + required Widget child, + }) : super(key: key, child: child); + + /// The configuration of this theme. + final AvatarThemeData data; + + /// The closest instance of this class that encloses the given context. + /// + /// If there is no enclosing [GalleryHeaderTheme] widget, then + /// [StreamChatThemeData.avatarTheme] is used. + /// + /// Typical usage is as follows: + /// + /// ```dart + /// final theme = AvatarTheme.of(context); + /// ``` + static AvatarThemeData of(BuildContext context) { + final avatarTheme = + context.dependOnInheritedWidgetOfExactType(); + return avatarTheme?.data ?? StreamChatTheme.of(context).avatarTheme; + } + + @override + Widget wrap(BuildContext context, Widget child) => + AvatarTheme(data: data, child: child); + + @override + bool updateShouldNotify(AvatarTheme oldWidget) => data != oldWidget.data; +} + +/// A style that overrides the default appearance of [UserAvatar]s when used +/// with [AvatarTheme] or with the overall [StreamChatTheme]'s +/// [StreamChatThemeData.avatarTheme]. +/// +/// See also: +/// +/// * [AvatarTheme], the theme which is configured with this class. +/// * [StreamChatThemeData.avatarTheme], which can be used to override +/// the default style for [UserAvatar]s below the overall [StreamChatTheme]. +class AvatarThemeData with Diagnosticable { + /// Creates an [AvatarThemeData]. + AvatarThemeData({ BoxConstraints? constraints, BorderRadius? borderRadius, }) : _constraints = constraints, @@ -15,30 +68,62 @@ class AvatarTheme { /// Get constraints for avatar BoxConstraints get constraints => _constraints ?? - const BoxConstraints.tightFor( - height: 32, - width: 32, - ); + const BoxConstraints.tightFor( + height: 32, + width: 32, + ); /// Get border radius BorderRadius get borderRadius => _borderRadius ?? BorderRadius.circular(20); - /// Copy with another theme - AvatarTheme copyWith({ + /// Copy this [AvatarThemeData] to another. + AvatarThemeData copyWith({ BoxConstraints? constraints, BorderRadius? borderRadius, }) => - AvatarTheme( + AvatarThemeData( constraints: constraints ?? _constraints, borderRadius: borderRadius ?? _borderRadius, ); - /// Merge with another AvatarTheme - AvatarTheme merge(AvatarTheme? other) { + /// 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, ); } -} \ No newline at end of file + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('borderRadius', borderRadius)) + ..add(DiagnosticsProperty('constraints', constraints)); + } +} diff --git a/packages/stream_chat_flutter/lib/src/theme/channel_header_theme.dart b/packages/stream_chat_flutter/lib/src/theme/channel_header_theme.dart index 2072b3c5..be1d0347 100644 --- a/packages/stream_chat_flutter/lib/src/theme/channel_header_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/channel_header_theme.dart @@ -18,7 +18,7 @@ class ChannelHeaderTheme { final TextStyle? subtitle; /// Theme for avatar - final AvatarTheme? avatarTheme; + final AvatarThemeData? avatarTheme; /// Color for [ChannelHeaderTheme] final Color? color; @@ -27,7 +27,7 @@ class ChannelHeaderTheme { ChannelHeaderTheme copyWith({ TextStyle? title, TextStyle? subtitle, - AvatarTheme? avatarTheme, + AvatarThemeData? avatarTheme, Color? color, }) => ChannelHeaderTheme( diff --git a/packages/stream_chat_flutter/lib/src/theme/channel_list_header_theme.dart b/packages/stream_chat_flutter/lib/src/theme/channel_list_header_theme.dart index ca36b9bd..8b5984bd 100644 --- a/packages/stream_chat_flutter/lib/src/theme/channel_list_header_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/channel_list_header_theme.dart @@ -14,7 +14,7 @@ class ChannelListHeaderTheme { final TextStyle? title; /// Theme dedicated to the userAvatar - final AvatarTheme? avatarTheme; + final AvatarThemeData? avatarTheme; /// Background color of the appbar final Color? color; @@ -22,7 +22,7 @@ class ChannelListHeaderTheme { /// Returns a new [ChannelListHeaderTheme] replacing some of its properties ChannelListHeaderTheme copyWith({ TextStyle? title, - AvatarTheme? avatarTheme, + AvatarThemeData? avatarTheme, Color? color, }) => ChannelListHeaderTheme( diff --git a/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart b/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart index 4643bb8d..61975b3f 100644 --- a/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart @@ -23,7 +23,7 @@ class ChannelPreviewTheme { final TextStyle? lastMessageAt; /// Avatar theme - final AvatarTheme? avatarTheme; + final AvatarThemeData? avatarTheme; /// Unread counter color final Color? unreadCounterColor; @@ -36,7 +36,7 @@ class ChannelPreviewTheme { TextStyle? title, TextStyle? subtitle, TextStyle? lastMessageAt, - AvatarTheme? avatarTheme, + AvatarThemeData? avatarTheme, Color? unreadCounterColor, double? indicatorIconSize, }) => diff --git a/packages/stream_chat_flutter/lib/src/theme/gallery_header_theme.dart b/packages/stream_chat_flutter/lib/src/theme/gallery_header_theme.dart index 9b5faa83..611a77bc 100644 --- a/packages/stream_chat_flutter/lib/src/theme/gallery_header_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/gallery_header_theme.dart @@ -8,7 +8,7 @@ import 'package:stream_chat_flutter/src/stream_chat_theme.dart'; /// /// * [GalleryHeaderThemeData], which is used to configure this theme. class GalleryHeaderTheme extends InheritedTheme { - /// Creates an [GalleryHeaderTheme]. + /// Creates a [GalleryHeaderTheme]. /// /// The [data] parameter must not be null. const GalleryHeaderTheme({ diff --git a/packages/stream_chat_flutter/lib/src/theme/message_theme.dart b/packages/stream_chat_flutter/lib/src/theme/message_theme.dart index 87543cb1..e9deb1f4 100644 --- a/packages/stream_chat_flutter/lib/src/theme/message_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/message_theme.dart @@ -49,7 +49,7 @@ class MessageTheme { final Color? reactionsMaskColor; /// Theme of the avatar - final AvatarTheme? avatarTheme; + final AvatarThemeData? avatarTheme; /// Copy with a theme MessageTheme copyWith({ @@ -60,7 +60,7 @@ class MessageTheme { TextStyle? replies, Color? messageBackgroundColor, Color? messageBorderColor, - AvatarTheme? avatarTheme, + AvatarThemeData? avatarTheme, Color? reactionsBackgroundColor, Color? reactionsBorderColor, Color? reactionsMaskColor, From 66ea5557e88ace85dbaccbfe3add1320803e031f Mon Sep 17 00:00:00 2001 From: groovinchip Date: Tue, 27 Jul 2021 10:47:01 -0400 Subject: [PATCH 03/42] test: create tests for AvatarThemeData --- .../lib/src/theme/avatar_theme.dart | 2 +- .../test/src/avatar_theme_test.dart | 50 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 packages/stream_chat_flutter/test/src/avatar_theme_test.dart diff --git a/packages/stream_chat_flutter/lib/src/theme/avatar_theme.dart b/packages/stream_chat_flutter/lib/src/theme/avatar_theme.dart index 873bd259..7af1b976 100644 --- a/packages/stream_chat_flutter/lib/src/theme/avatar_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/avatar_theme.dart @@ -56,7 +56,7 @@ class AvatarTheme extends InheritedTheme { /// the default style for [UserAvatar]s below the overall [StreamChatTheme]. class AvatarThemeData with Diagnosticable { /// Creates an [AvatarThemeData]. - AvatarThemeData({ + const AvatarThemeData({ BoxConstraints? constraints, BorderRadius? borderRadius, }) : _constraints = constraints, diff --git a/packages/stream_chat_flutter/test/src/avatar_theme_test.dart b/packages/stream_chat_flutter/test/src/avatar_theme_test.dart new file mode 100644 index 00000000..63e6da86 --- /dev/null +++ b/packages/stream_chat_flutter/test/src/avatar_theme_test.dart @@ -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, + ), +); From 1fa8c5264ab18d00e42d213deab85a6078bdef84 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Tue, 27 Jul 2021 11:46:19 -0400 Subject: [PATCH 04/42] chore: upgrade ChannelHeaderTheme --- .../lib/src/stream_chat_theme.dart | 8 +-- .../lib/src/theme/channel_header_theme.dart | 72 ++++++++++++++++--- .../lib/src/theme/channel_theme.dart | 4 +- 3 files changed, 69 insertions(+), 15 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart index d2eb0df0..38511e38 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart @@ -188,10 +188,10 @@ class StreamChatThemeData { /// Theme configuration for the [UserListView] widget. final UserListViewThemeData userListViewTheme; - /// Theme configuration for the [] widget. + /// Theme configuration for the [MessageSearchListView] widget. final MessageSearchListViewThemeData messageSearchListViewTheme; - /// Theme configuration for the [] widget. + /// Theme configuration for the [UserAvatar] widget. final AvatarThemeData avatarTheme; /// Creates a copy of [StreamChatThemeData] with specified attributes @@ -279,7 +279,7 @@ class StreamChatThemeData { final iconTheme = IconThemeData(color: colorTheme.textHighEmphasis.withOpacity(.5)); final channelTheme = ChannelTheme( - channelHeaderTheme: ChannelHeaderTheme( + channelHeaderTheme: ChannelHeaderThemeData( avatarTheme: AvatarThemeData( borderRadius: BorderRadius.circular(20), constraints: const BoxConstraints.tightFor( @@ -497,7 +497,7 @@ class StreamChatThemeData { backgroundColor: colorTheme.appBg, ), avatarTheme: AvatarThemeData( - borderRadius: BorderRadius.circular(8), + borderRadius: BorderRadius.circular(20), ), ); } diff --git a/packages/stream_chat_flutter/lib/src/theme/channel_header_theme.dart b/packages/stream_chat_flutter/lib/src/theme/channel_header_theme.dart index be1d0347..8ea92615 100644 --- a/packages/stream_chat_flutter/lib/src/theme/channel_header_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/channel_header_theme.dart @@ -1,10 +1,64 @@ +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'; -/// Theme for [ChannelHeader] -class ChannelHeaderTheme { - /// Constructor for creating a [ChannelHeaderTheme] +/// 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(); + return channelHeaderTheme?.data ?? + StreamChatTheme.of(context).channelTheme.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.title, this.subtitle, this.avatarTheme, @@ -20,25 +74,25 @@ class ChannelHeaderTheme { /// Theme for avatar final AvatarThemeData? avatarTheme; - /// Color for [ChannelHeaderTheme] + /// Color for [ChannelHeaderThemeData] final Color? color; /// Copy with theme - ChannelHeaderTheme copyWith({ + ChannelHeaderThemeData copyWith({ TextStyle? title, TextStyle? subtitle, AvatarThemeData? avatarTheme, Color? color, }) => - ChannelHeaderTheme( + ChannelHeaderThemeData( title: title ?? this.title, subtitle: subtitle ?? this.subtitle, avatarTheme: avatarTheme ?? this.avatarTheme, color: color ?? this.color, ); - /// Merge with other [ChannelHeaderTheme] - ChannelHeaderTheme merge(ChannelHeaderTheme? other) { + /// Merge with other [ChannelHeaderThemeData] + ChannelHeaderThemeData merge(ChannelHeaderThemeData? other) { if (other == null) return this; return copyWith( title: title?.merge(other.title) ?? other.title, @@ -47,4 +101,4 @@ class ChannelHeaderTheme { color: other.color, ); } -} \ No newline at end of file +} diff --git a/packages/stream_chat_flutter/lib/src/theme/channel_theme.dart b/packages/stream_chat_flutter/lib/src/theme/channel_theme.dart index bf752f94..a8c6260d 100644 --- a/packages/stream_chat_flutter/lib/src/theme/channel_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/channel_theme.dart @@ -8,11 +8,11 @@ class ChannelTheme { }); /// Theme of the [ChannelHeader] widget - final ChannelHeaderTheme channelHeaderTheme; + final ChannelHeaderThemeData channelHeaderTheme; /// Creates a copy of [ChannelTheme] with specified attributes overridden. ChannelTheme copyWith({ - ChannelHeaderTheme? channelHeaderTheme, + ChannelHeaderThemeData? channelHeaderTheme, }) => ChannelTheme( channelHeaderTheme: channelHeaderTheme ?? this.channelHeaderTheme, From 8bf45f85019c87ed70947d4f1ae7378cc4da3bb6 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Tue, 27 Jul 2021 13:21:20 -0400 Subject: [PATCH 05/42] fix: remove duplicate exports in stream_chat_flutter.dart --- packages/stream_chat_flutter/lib/stream_chat_flutter.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/stream_chat_flutter/lib/stream_chat_flutter.dart b/packages/stream_chat_flutter/lib/stream_chat_flutter.dart index 0a65d672..c5684bbb 100644 --- a/packages/stream_chat_flutter/lib/stream_chat_flutter.dart +++ b/packages/stream_chat_flutter/lib/stream_chat_flutter.dart @@ -39,7 +39,5 @@ export 'src/typing_indicator.dart'; export 'src/unread_indicator.dart'; export 'src/user_avatar.dart'; export 'src/user_item.dart'; -export 'src/user_item.dart'; -export 'src/user_list_view.dart'; export 'src/user_list_view.dart'; export 'src/utils.dart'; From 3a072fc836919b096539a9bdca71296a0658ede9 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Tue, 27 Jul 2021 13:33:58 -0400 Subject: [PATCH 06/42] chore: more upgrades for channel_header_theme.dart * Renamed: * title -> titleStyle * subtitle -> subtitleStyle * Added * == * hashcode * debugFillProperties * lerp --- .../lib/src/channel_header.dart | 4 +- .../lib/src/channel_info.dart | 2 +- .../lib/src/message_list_view.dart | 2 +- .../lib/src/stream_chat_theme.dart | 4 +- .../lib/src/theme/channel_header_theme.dart | 65 ++++++++++++++++--- .../lib/src/theme/gallery_header_theme.dart | 2 +- .../lib/src/thread_header.dart | 8 +-- 7 files changed, 66 insertions(+), 21 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/channel_header.dart b/packages/stream_chat_flutter/lib/src/channel_header.dart index 8f586516..4df44765 100644 --- a/packages/stream_chat_flutter/lib/src/channel_header.dart +++ b/packages/stream_chat_flutter/lib/src/channel_header.dart @@ -169,7 +169,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { title ?? ChannelName( textStyle: chatThemeData - .channelTheme.channelHeaderTheme.title, + .channelTheme.channelHeaderTheme.titleStyle, ), const SizedBox(height: 2), subtitle ?? @@ -177,7 +177,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { showTypingIndicator: showTypingIndicator, channel: channel, textStyle: chatThemeData - .channelTheme.channelHeaderTheme.subtitle, + .channelTheme.channelHeaderTheme.subtitleStyle, ), ], ), diff --git a/packages/stream_chat_flutter/lib/src/channel_info.dart b/packages/stream_chat_flutter/lib/src/channel_info.dart index 89894324..67e18801 100644 --- a/packages/stream_chat_flutter/lib/src/channel_info.dart +++ b/packages/stream_chat_flutter/lib/src/channel_info.dart @@ -64,7 +64,7 @@ class ChannelInfo extends StatelessWidget { style: StreamChatTheme.of(context) .channelTheme .channelHeaderTheme - .subtitle, + .subtitleStyle, ); } else { final userId = StreamChat.of(context).currentUser?.id; diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index e7279579..303c76db 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -628,7 +628,7 @@ class _MessageListViewState extends State { child: Text( '$replyCount ${replyCount == 1 ? 'Reply' : 'Replies'}', textAlign: TextAlign.center, - style: _streamTheme.channelTheme.channelHeaderTheme.subtitle, + style: _streamTheme.channelTheme.channelHeaderTheme.subtitleStyle, ), ), ); diff --git a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart index 38511e38..dad5dadb 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart @@ -288,8 +288,8 @@ class StreamChatThemeData { ), ), color: colorTheme.barsBg, - title: textTheme.headlineBold, - subtitle: textTheme.footnote.copyWith( + titleStyle: textTheme.headlineBold, + subtitleStyle: textTheme.footnote.copyWith( color: const Color(0xff7A7A7A), ), ), diff --git a/packages/stream_chat_flutter/lib/src/theme/channel_header_theme.dart b/packages/stream_chat_flutter/lib/src/theme/channel_header_theme.dart index 8ea92615..2d3253dc 100644 --- a/packages/stream_chat_flutter/lib/src/theme/channel_header_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/channel_header_theme.dart @@ -2,6 +2,7 @@ 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. /// @@ -59,17 +60,17 @@ class ChannelHeaderTheme extends InheritedTheme { class ChannelHeaderThemeData with Diagnosticable { /// Creates a [ChannelHeaderThemeData] const ChannelHeaderThemeData({ - this.title, - this.subtitle, + this.titleStyle, + this.subtitleStyle, this.avatarTheme, this.color, }); /// Theme for title - final TextStyle? title; + final TextStyle? titleStyle; /// Theme for subtitle - final TextStyle? subtitle; + final TextStyle? subtitleStyle; /// Theme for avatar final AvatarThemeData? avatarTheme; @@ -79,26 +80,70 @@ class ChannelHeaderThemeData with Diagnosticable { /// Copy with theme ChannelHeaderThemeData copyWith({ - TextStyle? title, - TextStyle? subtitle, + TextStyle? titleStyle, + TextStyle? subtitleStyle, AvatarThemeData? avatarTheme, Color? color, }) => ChannelHeaderThemeData( - title: title ?? this.title, - subtitle: subtitle ?? this.subtitle, + 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( - title: title?.merge(other.title) ?? other.title, - subtitle: subtitle?.merge(other.subtitle) ?? other.subtitle, + 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)); + } } diff --git a/packages/stream_chat_flutter/lib/src/theme/gallery_header_theme.dart b/packages/stream_chat_flutter/lib/src/theme/gallery_header_theme.dart index 611a77bc..862a9a9e 100644 --- a/packages/stream_chat_flutter/lib/src/theme/gallery_header_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/gallery_header_theme.dart @@ -86,7 +86,7 @@ class GalleryHeaderThemeData with Diagnosticable { /// The [TextStyle] to use for the [GalleryHeader] subtitle text. /// - /// Defaults to [ChannelPreviewTheme.subtitle]. + /// Defaults to [ChannelPreviewTheme.subtitleStyle]. final TextStyle? subtitleTextStyle; /// diff --git a/packages/stream_chat_flutter/lib/src/thread_header.dart b/packages/stream_chat_flutter/lib/src/thread_header.dart index bfde9a4c..0473ca48 100644 --- a/packages/stream_chat_flutter/lib/src/thread_header.dart +++ b/packages/stream_chat_flutter/lib/src/thread_header.dart @@ -112,12 +112,12 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { children: [ Text( 'with ', - style: chatThemeData.channelTheme.channelHeaderTheme.subtitle, + style: chatThemeData.channelTheme.channelHeaderTheme.subtitleStyle, ), Flexible( child: ChannelName( textStyle: - chatThemeData.channelTheme.channelHeaderTheme.subtitle, + chatThemeData.channelTheme.channelHeaderTheme.subtitleStyle, ), ), ], @@ -150,14 +150,14 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { title ?? Text( 'Thread Reply', - style: chatThemeData.channelTheme.channelHeaderTheme.title, + style: chatThemeData.channelTheme.channelHeaderTheme.titleStyle, ), const SizedBox(height: 2), if (showTypingIndicator) TypingIndicator( alignment: Alignment.center, channel: StreamChannel.of(context).channel, - style: chatThemeData.channelTheme.channelHeaderTheme.subtitle, + style: chatThemeData.channelTheme.channelHeaderTheme.subtitleStyle, parentId: parent.id, alternativeWidget: defaultSubtitle, ) From 362d55b89e783713d82256b3b9b2c93bb96359c4 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Tue, 27 Jul 2021 13:48:32 -0400 Subject: [PATCH 07/42] test: add tests for ChannelHeaderThemeData --- .../test/src/channel_header_theme_test.dart | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 packages/stream_chat_flutter/test/src/channel_header_theme_test.dart diff --git a/packages/stream_chat_flutter/test/src/channel_header_theme_test.dart b/packages/stream_chat_flutter/test/src/channel_header_theme_test.dart new file mode 100644 index 00000000..de9803b7 --- /dev/null +++ b/packages/stream_chat_flutter/test/src/channel_header_theme_test.dart @@ -0,0 +1,93 @@ +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), + _channelThemeControlDark); + }); + + 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: ColorTheme.light().barsBg, + titleStyle: TextTheme.light().headlineBold, + 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), + ), +); From 82fa91609069c28ed2ac8d7b6cb507756c5d037e Mon Sep 17 00:00:00 2001 From: groovinchip Date: Tue, 27 Jul 2021 15:30:34 -0400 Subject: [PATCH 08/42] test: move theme test files into their own folder within test/src --- .../test/src/{ => theme}/avatar_theme_test.dart | 0 .../test/src/{ => theme}/channel_header_theme_test.dart | 0 .../test/src/{ => theme}/channel_list_view_theme_test.dart | 2 +- .../test/src/{ => theme}/gallery_footer_theme_test.dart | 0 .../test/src/{ => theme}/gallery_header_theme_test.dart | 0 .../test/src/{ => theme}/message_list_view_theme_test.dart | 2 +- .../src/{ => theme}/message_search_list_view_theme_test.dart | 2 +- .../test/src/{ => theme}/user_list_view_theme_test.dart | 2 +- 8 files changed, 4 insertions(+), 4 deletions(-) rename packages/stream_chat_flutter/test/src/{ => theme}/avatar_theme_test.dart (100%) rename packages/stream_chat_flutter/test/src/{ => theme}/channel_header_theme_test.dart (100%) rename packages/stream_chat_flutter/test/src/{ => theme}/channel_list_view_theme_test.dart (99%) rename packages/stream_chat_flutter/test/src/{ => theme}/gallery_footer_theme_test.dart (100%) rename packages/stream_chat_flutter/test/src/{ => theme}/gallery_header_theme_test.dart (100%) rename packages/stream_chat_flutter/test/src/{ => theme}/message_list_view_theme_test.dart (99%) rename packages/stream_chat_flutter/test/src/{ => theme}/message_search_list_view_theme_test.dart (99%) rename packages/stream_chat_flutter/test/src/{ => theme}/user_list_view_theme_test.dart (99%) diff --git a/packages/stream_chat_flutter/test/src/avatar_theme_test.dart b/packages/stream_chat_flutter/test/src/theme/avatar_theme_test.dart similarity index 100% rename from packages/stream_chat_flutter/test/src/avatar_theme_test.dart rename to packages/stream_chat_flutter/test/src/theme/avatar_theme_test.dart diff --git a/packages/stream_chat_flutter/test/src/channel_header_theme_test.dart b/packages/stream_chat_flutter/test/src/theme/channel_header_theme_test.dart similarity index 100% rename from packages/stream_chat_flutter/test/src/channel_header_theme_test.dart rename to packages/stream_chat_flutter/test/src/theme/channel_header_theme_test.dart diff --git a/packages/stream_chat_flutter/test/src/channel_list_view_theme_test.dart b/packages/stream_chat_flutter/test/src/theme/channel_list_view_theme_test.dart similarity index 99% rename from packages/stream_chat_flutter/test/src/channel_list_view_theme_test.dart rename to packages/stream_chat_flutter/test/src/theme/channel_list_view_theme_test.dart index 80a21d25..38b1c524 100644 --- a/packages/stream_chat_flutter/test/src/channel_list_view_theme_test.dart +++ b/packages/stream_chat_flutter/test/src/theme/channel_list_view_theme_test.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'mocks.dart'; +import '../mocks.dart'; void main() { test('ChannelListViewThemeData copyWith, ==, hashCode basics', () { diff --git a/packages/stream_chat_flutter/test/src/gallery_footer_theme_test.dart b/packages/stream_chat_flutter/test/src/theme/gallery_footer_theme_test.dart similarity index 100% rename from packages/stream_chat_flutter/test/src/gallery_footer_theme_test.dart rename to packages/stream_chat_flutter/test/src/theme/gallery_footer_theme_test.dart diff --git a/packages/stream_chat_flutter/test/src/gallery_header_theme_test.dart b/packages/stream_chat_flutter/test/src/theme/gallery_header_theme_test.dart similarity index 100% rename from packages/stream_chat_flutter/test/src/gallery_header_theme_test.dart rename to packages/stream_chat_flutter/test/src/theme/gallery_header_theme_test.dart diff --git a/packages/stream_chat_flutter/test/src/message_list_view_theme_test.dart b/packages/stream_chat_flutter/test/src/theme/message_list_view_theme_test.dart similarity index 99% rename from packages/stream_chat_flutter/test/src/message_list_view_theme_test.dart rename to packages/stream_chat_flutter/test/src/theme/message_list_view_theme_test.dart index ffe54dd0..476f5063 100644 --- a/packages/stream_chat_flutter/test/src/message_list_view_theme_test.dart +++ b/packages/stream_chat_flutter/test/src/theme/message_list_view_theme_test.dart @@ -3,7 +3,7 @@ import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'mocks.dart'; +import '../mocks.dart'; class MockStreamChatClient extends Mock implements StreamChatClient {} diff --git a/packages/stream_chat_flutter/test/src/message_search_list_view_theme_test.dart b/packages/stream_chat_flutter/test/src/theme/message_search_list_view_theme_test.dart similarity index 99% rename from packages/stream_chat_flutter/test/src/message_search_list_view_theme_test.dart rename to packages/stream_chat_flutter/test/src/theme/message_search_list_view_theme_test.dart index e485e0d6..4da1c7dc 100644 --- a/packages/stream_chat_flutter/test/src/message_search_list_view_theme_test.dart +++ b/packages/stream_chat_flutter/test/src/theme/message_search_list_view_theme_test.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'mocks.dart'; +import '../mocks.dart'; void main() { test('MessageSearchListViewThemeData copyWith, ==, hashCode basics', () { diff --git a/packages/stream_chat_flutter/test/src/user_list_view_theme_test.dart b/packages/stream_chat_flutter/test/src/theme/user_list_view_theme_test.dart similarity index 99% rename from packages/stream_chat_flutter/test/src/user_list_view_theme_test.dart rename to packages/stream_chat_flutter/test/src/theme/user_list_view_theme_test.dart index e9b7985a..a22eebd0 100644 --- a/packages/stream_chat_flutter/test/src/user_list_view_theme_test.dart +++ b/packages/stream_chat_flutter/test/src/theme/user_list_view_theme_test.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:stream_chat_flutter/stream_chat_flutter.dart'; -import 'mocks.dart'; +import '../mocks.dart'; void main() { test('UserListViewThemeData copyWith, ==, hashCode basics', () { From de4e1e29e251d62c9802127760765436e10145d5 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Wed, 28 Jul 2021 12:49:14 -0400 Subject: [PATCH 09/42] chore: remove AvatarTheme --- .../lib/src/stream_chat_theme.dart | 12 ----- .../lib/src/theme/avatar_theme.dart | 54 +------------------ 2 files changed, 1 insertion(+), 65 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart index dad5dadb..f83050a3 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart @@ -62,7 +62,6 @@ class StreamChatThemeData { ChannelListViewThemeData? channelListViewTheme, UserListViewThemeData? userListViewTheme, MessageSearchListViewThemeData? messageSearchListViewTheme, - AvatarThemeData? avatarTheme, }) { brightness ??= colorTheme?.brightness ?? Brightness.light; final isDark = brightness == Brightness.dark; @@ -90,7 +89,6 @@ class StreamChatThemeData { channelListViewTheme: channelListViewTheme, userListViewTheme: userListViewTheme, messageSearchListViewTheme: messageSearchListViewTheme, - avatarTheme: avatarTheme, ); return defaultData.merge(customizedData); @@ -123,7 +121,6 @@ class StreamChatThemeData { required this.channelListViewTheme, required this.userListViewTheme, required this.messageSearchListViewTheme, - required this.avatarTheme, }); /// Create a theme from a Material [Theme] @@ -191,9 +188,6 @@ class StreamChatThemeData { /// Theme configuration for the [MessageSearchListView] widget. final MessageSearchListViewThemeData messageSearchListViewTheme; - /// Theme configuration for the [UserAvatar] widget. - final AvatarThemeData avatarTheme; - /// Creates a copy of [StreamChatThemeData] with specified attributes /// overridden. StreamChatThemeData copyWith({ @@ -214,7 +208,6 @@ class StreamChatThemeData { ChannelListViewThemeData? channelListViewTheme, UserListViewThemeData? userListViewTheme, MessageSearchListViewThemeData? messageSearchListViewTheme, - AvatarThemeData? avatarTheme, }) => StreamChatThemeData.raw( channelListHeaderTheme: @@ -237,7 +230,6 @@ class StreamChatThemeData { userListViewTheme: userListViewTheme ?? this.userListViewTheme, messageSearchListViewTheme: messageSearchListViewTheme ?? this.messageSearchListViewTheme, - avatarTheme: avatarTheme ?? this.avatarTheme, ); /// Merge themes @@ -265,7 +257,6 @@ class StreamChatThemeData { userListViewTheme: userListViewTheme.merge(other.userListViewTheme), messageSearchListViewTheme: messageSearchListViewTheme.merge(other.messageSearchListViewTheme), - avatarTheme: avatarTheme.merge(other.avatarTheme), ); } @@ -496,9 +487,6 @@ class StreamChatThemeData { messageSearchListViewTheme: MessageSearchListViewThemeData( backgroundColor: colorTheme.appBg, ), - avatarTheme: AvatarThemeData( - borderRadius: BorderRadius.circular(20), - ), ); } } diff --git a/packages/stream_chat_flutter/lib/src/theme/avatar_theme.dart b/packages/stream_chat_flutter/lib/src/theme/avatar_theme.dart index 7af1b976..6c287638 100644 --- a/packages/stream_chat_flutter/lib/src/theme/avatar_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/avatar_theme.dart @@ -1,59 +1,7 @@ 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/themes.dart'; -/// Overrides the default style of [UserAvatar] descendants. -/// -/// See also: -/// -/// * [AvatarThemeData], which is used to configure this theme. -class AvatarTheme extends InheritedTheme { - /// Creates an [AvatarTheme]. - /// - /// The [data] parameter must not be null. - const AvatarTheme({ - Key? key, - required this.data, - required Widget child, - }) : super(key: key, child: child); - - /// The configuration of this theme. - final AvatarThemeData data; - - /// The closest instance of this class that encloses the given context. - /// - /// If there is no enclosing [GalleryHeaderTheme] widget, then - /// [StreamChatThemeData.avatarTheme] is used. - /// - /// Typical usage is as follows: - /// - /// ```dart - /// final theme = AvatarTheme.of(context); - /// ``` - static AvatarThemeData of(BuildContext context) { - final avatarTheme = - context.dependOnInheritedWidgetOfExactType(); - return avatarTheme?.data ?? StreamChatTheme.of(context).avatarTheme; - } - - @override - Widget wrap(BuildContext context, Widget child) => - AvatarTheme(data: data, child: child); - - @override - bool updateShouldNotify(AvatarTheme oldWidget) => data != oldWidget.data; -} - -/// A style that overrides the default appearance of [UserAvatar]s when used -/// with [AvatarTheme] or with the overall [StreamChatTheme]'s -/// [StreamChatThemeData.avatarTheme]. -/// -/// See also: -/// -/// * [AvatarTheme], the theme which is configured with this class. -/// * [StreamChatThemeData.avatarTheme], which can be used to override -/// the default style for [UserAvatar]s below the overall [StreamChatTheme]. +/// A style that overrides the default appearance of various avatar widgets. class AvatarThemeData with Diagnosticable { /// Creates an [AvatarThemeData]. const AvatarThemeData({ From cede1b572a5eda90ea084899c0c7d91ee9be37e3 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Wed, 28 Jul 2021 14:49:12 -0400 Subject: [PATCH 10/42] chore: run dartfmt on /theme --- .../src/theme/channel_list_header_theme.dart | 2 +- .../lib/src/theme/channel_preview_theme.dart | 4 +-- .../lib/src/theme/gallery_header_theme.dart | 34 +++++++++---------- .../lib/src/theme/message_input_theme.dart | 8 ++--- .../src/theme/message_list_view_theme.dart | 16 ++++----- .../lib/src/theme/themes.dart | 2 +- 6 files changed, 33 insertions(+), 33 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/theme/channel_list_header_theme.dart b/packages/stream_chat_flutter/lib/src/theme/channel_list_header_theme.dart index 8b5984bd..339361b9 100644 --- a/packages/stream_chat_flutter/lib/src/theme/channel_list_header_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/channel_list_header_theme.dart @@ -40,4 +40,4 @@ class ChannelListHeaderTheme { color: other.color, ); } -} \ No newline at end of file +} diff --git a/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart b/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart index 61975b3f..2fcecaf7 100644 --- a/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart @@ -56,9 +56,9 @@ class ChannelPreviewTheme { title: title?.merge(other.title) ?? other.title, subtitle: subtitle?.merge(other.subtitle) ?? other.subtitle, lastMessageAt: - lastMessageAt?.merge(other.lastMessageAt) ?? other.lastMessageAt, + lastMessageAt?.merge(other.lastMessageAt) ?? other.lastMessageAt, avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, unreadCounterColor: other.unreadCounterColor, ); } -} \ No newline at end of file +} diff --git a/packages/stream_chat_flutter/lib/src/theme/gallery_header_theme.dart b/packages/stream_chat_flutter/lib/src/theme/gallery_header_theme.dart index 862a9a9e..23402c57 100644 --- a/packages/stream_chat_flutter/lib/src/theme/gallery_header_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/gallery_header_theme.dart @@ -32,7 +32,7 @@ class GalleryHeaderTheme extends InheritedTheme { /// ``` static GalleryHeaderThemeData of(BuildContext context) { final galleryHeaderTheme = - context.dependOnInheritedWidgetOfExactType(); + context.dependOnInheritedWidgetOfExactType(); return galleryHeaderTheme?.data ?? StreamChatTheme.of(context).galleryHeaderTheme; } @@ -108,27 +108,27 @@ class GalleryHeaderThemeData with Diagnosticable { titleTextStyle: titleTextStyle ?? this.titleTextStyle, subtitleTextStyle: subtitleTextStyle ?? this.subtitleTextStyle, bottomSheetBarrierColor: - bottomSheetBarrierColor ?? this.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 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), + Color.lerp(a.iconMenuPointColor, b.iconMenuPointColor, t), titleTextStyle: TextStyle.lerp(a.titleTextStyle, b.titleTextStyle, t), subtitleTextStyle: - TextStyle.lerp(a.subtitleTextStyle, b.subtitleTextStyle, t), + TextStyle.lerp(a.subtitleTextStyle, b.subtitleTextStyle, t), bottomSheetBarrierColor: - Color.lerp(a.bottomSheetBarrierColor, b.bottomSheetBarrierColor, t), + Color.lerp(a.bottomSheetBarrierColor, b.bottomSheetBarrierColor, t), ); /// Merges one [GalleryHeaderThemeData] with the another @@ -147,14 +147,14 @@ class GalleryHeaderThemeData with Diagnosticable { @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; + 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 => diff --git a/packages/stream_chat_flutter/lib/src/theme/message_input_theme.dart b/packages/stream_chat_flutter/lib/src/theme/message_input_theme.dart index b8889e6b..09c99478 100644 --- a/packages/stream_chat_flutter/lib/src/theme/message_input_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/message_input_theme.dart @@ -72,12 +72,12 @@ class MessageInputTheme { }) => MessageInputTheme( sendAnimationDuration: - sendAnimationDuration ?? this.sendAnimationDuration, + sendAnimationDuration ?? this.sendAnimationDuration, inputBackground: inputBackground ?? this.inputBackground, actionButtonColor: actionButtonColor ?? this.actionButtonColor, sendButtonColor: sendButtonColor ?? this.sendButtonColor, actionButtonIdleColor: - actionButtonIdleColor ?? this.actionButtonIdleColor, + actionButtonIdleColor ?? this.actionButtonIdleColor, expandButtonColor: expandButtonColor ?? this.expandButtonColor, inputTextStyle: inputTextStyle ?? this.inputTextStyle, sendButtonIdleColor: sendButtonIdleColor ?? this.sendButtonIdleColor, @@ -98,7 +98,7 @@ class MessageInputTheme { sendButtonColor: other.sendButtonColor, sendButtonIdleColor: other.sendButtonIdleColor, inputTextStyle: - inputTextStyle?.merge(other.inputTextStyle) ?? other.inputTextStyle, + inputTextStyle?.merge(other.inputTextStyle) ?? other.inputTextStyle, inputDecoration: inputDecoration?.merge(other.inputDecoration) ?? other.inputDecoration, activeBorderGradient: other.activeBorderGradient, @@ -107,4 +107,4 @@ class MessageInputTheme { expandButtonColor: other.expandButtonColor, ); } -} \ No newline at end of file +} diff --git a/packages/stream_chat_flutter/lib/src/theme/message_list_view_theme.dart b/packages/stream_chat_flutter/lib/src/theme/message_list_view_theme.dart index 49bd05f9..8ad8ea9d 100644 --- a/packages/stream_chat_flutter/lib/src/theme/message_list_view_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/message_list_view_theme.dart @@ -32,7 +32,7 @@ class MessageListViewTheme extends InheritedTheme { /// ``` static MessageListViewThemeData of(BuildContext context) { final messageListViewTheme = - context.dependOnInheritedWidgetOfExactType(); + context.dependOnInheritedWidgetOfExactType(); return messageListViewTheme?.data ?? StreamChatTheme.of(context).messageListViewTheme; } @@ -77,10 +77,10 @@ class MessageListViewThemeData with Diagnosticable { /// /// All the properties must be non-null. MessageListViewThemeData lerp( - MessageListViewThemeData a, - MessageListViewThemeData b, - double t, - ) => + MessageListViewThemeData a, + MessageListViewThemeData b, + double t, + ) => MessageListViewThemeData( backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t), ); @@ -96,9 +96,9 @@ class MessageListViewThemeData with Diagnosticable { @override bool operator ==(Object other) => identical(this, other) || - other is MessageListViewThemeData && - runtimeType == other.runtimeType && - backgroundColor == other.backgroundColor; + other is MessageListViewThemeData && + runtimeType == other.runtimeType && + backgroundColor == other.backgroundColor; @override int get hashCode => backgroundColor.hashCode; diff --git a/packages/stream_chat_flutter/lib/src/theme/themes.dart b/packages/stream_chat_flutter/lib/src/theme/themes.dart index 4236f874..a3e974e8 100644 --- a/packages/stream_chat_flutter/lib/src/theme/themes.dart +++ b/packages/stream_chat_flutter/lib/src/theme/themes.dart @@ -12,4 +12,4 @@ 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'; \ No newline at end of file +export 'user_list_view_theme.dart'; From 15defc4caa308c719966d16e4f2f1a7429a2b107 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Thu, 29 Jul 2021 09:23:50 -0400 Subject: [PATCH 11/42] chore: remove unnecessary ChannelTheme class --- .../lib/src/channel_header.dart | 15 +++---- .../lib/src/channel_info.dart | 5 +-- .../lib/src/full_screen_media.dart | 1 - .../lib/src/message_list_view.dart | 2 +- .../lib/src/stream_chat_theme.dart | 44 +++++++++---------- .../lib/src/theme/channel_header_theme.dart | 2 +- .../lib/src/theme/channel_theme.dart | 28 ------------ .../lib/src/theme/themes.dart | 1 - .../lib/src/thread_header.dart | 11 +++-- 9 files changed, 36 insertions(+), 73 deletions(-) delete mode 100644 packages/stream_chat_flutter/lib/src/theme/channel_theme.dart diff --git a/packages/stream_chat_flutter/lib/src/channel_header.dart b/packages/stream_chat_flutter/lib/src/channel_header.dart index 4df44765..c3adf9ee 100644 --- a/packages/stream_chat_flutter/lib/src/channel_header.dart +++ b/packages/stream_chat_flutter/lib/src/channel_header.dart @@ -140,17 +140,16 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { brightness: Theme.of(context).brightness, elevation: 1, leading: leadingWidget, - backgroundColor: - chatThemeData.channelTheme.channelHeaderTheme.color, + backgroundColor: chatThemeData.channelHeaderTheme.color, actions: actions ?? [ Padding( padding: const EdgeInsets.only(right: 10), child: Center( child: ChannelAvatar( - borderRadius: chatThemeData.channelTheme + borderRadius: chatThemeData .channelHeaderTheme.avatarTheme?.borderRadius, - constraints: chatThemeData.channelTheme + constraints: chatThemeData .channelHeaderTheme.avatarTheme?.constraints, onTap: onImageTap, ), @@ -168,16 +167,16 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { children: [ title ?? ChannelName( - textStyle: chatThemeData - .channelTheme.channelHeaderTheme.titleStyle, + textStyle: + chatThemeData.channelHeaderTheme.titleStyle, ), const SizedBox(height: 2), subtitle ?? ChannelInfo( showTypingIndicator: showTypingIndicator, channel: channel, - textStyle: chatThemeData - .channelTheme.channelHeaderTheme.subtitleStyle, + textStyle: + chatThemeData.channelHeaderTheme.subtitleStyle, ), ], ), diff --git a/packages/stream_chat_flutter/lib/src/channel_info.dart b/packages/stream_chat_flutter/lib/src/channel_info.dart index 67e18801..e7fa84c0 100644 --- a/packages/stream_chat_flutter/lib/src/channel_info.dart +++ b/packages/stream_chat_flutter/lib/src/channel_info.dart @@ -61,10 +61,7 @@ class ChannelInfo extends StatelessWidget { if (watcherCount > 0) text += ' $watcherCount Online'; alternativeWidget = Text( text, - style: StreamChatTheme.of(context) - .channelTheme - .channelHeaderTheme - .subtitleStyle, + style: StreamChatTheme.of(context).channelHeaderTheme.subtitleStyle, ); } else { final userId = StreamChat.of(context).currentUser?.id; diff --git a/packages/stream_chat_flutter/lib/src/full_screen_media.dart b/packages/stream_chat_flutter/lib/src/full_screen_media.dart index 0f6101b9..5d32d512 100644 --- a/packages/stream_chat_flutter/lib/src/full_screen_media.dart +++ b/packages/stream_chat_flutter/lib/src/full_screen_media.dart @@ -125,7 +125,6 @@ class _FullScreenMediaState extends State backgroundDecoration: BoxDecoration( color: ColorTween( begin: StreamChatTheme.of(context) - .channelTheme .channelHeaderTheme .color, end: Colors.black, diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index 303c76db..bdc460af 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -628,7 +628,7 @@ class _MessageListViewState extends State { child: Text( '$replyCount ${replyCount == 1 ? 'Reply' : 'Replies'}', textAlign: TextAlign.center, - style: _streamTheme.channelTheme.channelHeaderTheme.subtitleStyle, + style: _streamTheme.channelHeaderTheme.subtitleStyle, ), ), ); diff --git a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart index f83050a3..98a6e156 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart @@ -49,7 +49,7 @@ class StreamChatThemeData { ColorTheme? colorTheme, ChannelListHeaderTheme? channelListHeaderTheme, ChannelPreviewTheme? channelPreviewTheme, - ChannelTheme? channelTheme, + ChannelHeaderThemeData? channelHeaderTheme, MessageTheme? otherMessageTheme, MessageTheme? ownMessageTheme, MessageInputTheme? messageInputTheme, @@ -76,7 +76,7 @@ class StreamChatThemeData { final customizedData = defaultData.copyWith( channelListHeaderTheme: channelListHeaderTheme, channelPreviewTheme: channelPreviewTheme, - channelTheme: channelTheme, + channelHeaderTheme: channelHeaderTheme, otherMessageTheme: otherMessageTheme, ownMessageTheme: ownMessageTheme, messageInputTheme: messageInputTheme, @@ -108,7 +108,7 @@ class StreamChatThemeData { required this.colorTheme, required this.channelListHeaderTheme, required this.channelPreviewTheme, - required this.channelTheme, + required this.channelHeaderTheme, required this.otherMessageTheme, required this.ownMessageTheme, required this.messageInputTheme, @@ -147,8 +147,8 @@ class StreamChatThemeData { /// Theme of the [ChannelListHeader] final ChannelListHeaderTheme channelListHeaderTheme; - /// Theme of the chat widgets dedicated to a channel - final ChannelTheme channelTheme; + /// Theme of the chat widgets dedicated to a channel header + final ChannelHeaderThemeData channelHeaderTheme; /// The default style for [GalleryHeader]s below the overall /// [StreamChatTheme]. @@ -194,7 +194,7 @@ class StreamChatThemeData { TextTheme? textTheme, ColorTheme? colorTheme, ChannelPreviewTheme? channelPreviewTheme, - ChannelTheme? channelTheme, + ChannelHeaderThemeData? channelHeaderTheme, MessageTheme? ownMessageTheme, MessageTheme? otherMessageTheme, MessageInputTheme? messageInputTheme, @@ -218,7 +218,7 @@ class StreamChatThemeData { defaultUserImage: defaultUserImage ?? this.defaultUserImage, channelPreviewTheme: this.channelPreviewTheme.merge(channelPreviewTheme), - channelTheme: this.channelTheme.merge(channelTheme), + channelHeaderTheme: this.channelHeaderTheme.merge(channelHeaderTheme), ownMessageTheme: this.ownMessageTheme.merge(ownMessageTheme), otherMessageTheme: this.otherMessageTheme.merge(otherMessageTheme), messageInputTheme: this.messageInputTheme.merge(messageInputTheme), @@ -243,7 +243,7 @@ class StreamChatThemeData { primaryIconTheme: other.primaryIconTheme, defaultUserImage: other.defaultUserImage, channelPreviewTheme: channelPreviewTheme.merge(other.channelPreviewTheme), - channelTheme: channelTheme.merge(other.channelTheme), + channelHeaderTheme: channelHeaderTheme.merge(other.channelHeaderTheme), ownMessageTheme: ownMessageTheme.merge(other.ownMessageTheme), otherMessageTheme: otherMessageTheme.merge(other.otherMessageTheme), messageInputTheme: messageInputTheme.merge(other.messageInputTheme), @@ -269,21 +269,19 @@ class StreamChatThemeData { final accentColor = colorTheme.accentPrimary; final iconTheme = IconThemeData(color: colorTheme.textHighEmphasis.withOpacity(.5)); - final channelTheme = ChannelTheme( - channelHeaderTheme: ChannelHeaderThemeData( - avatarTheme: AvatarThemeData( - borderRadius: BorderRadius.circular(20), - constraints: const BoxConstraints.tightFor( - height: 40, - width: 40, - ), - ), - color: colorTheme.barsBg, - titleStyle: textTheme.headlineBold, - subtitleStyle: textTheme.footnote.copyWith( - color: const Color(0xff7A7A7A), + final channelHeaderTheme = ChannelHeaderThemeData( + avatarTheme: AvatarThemeData( + borderRadius: BorderRadius.circular(20), + constraints: const BoxConstraints.tightFor( + height: 40, + width: 40, ), ), + color: colorTheme.barsBg, + titleStyle: textTheme.headlineBold, + subtitleStyle: textTheme.footnote.copyWith( + color: const Color(0xff7A7A7A), + ), ); final channelPreviewTheme = ChannelPreviewTheme( unreadCounterColor: colorTheme.accentError, @@ -325,7 +323,7 @@ class StreamChatThemeData { color: colorTheme.barsBg, title: textTheme.headlineBold, ), - channelTheme: channelTheme, + channelHeaderTheme: channelHeaderTheme, ownMessageTheme: MessageTheme( messageAuthor: textTheme.footnote.copyWith(color: colorTheme.textLowEmphasis), @@ -459,7 +457,7 @@ class StreamChatThemeData { ], galleryHeaderTheme: GalleryHeaderThemeData( closeButtonColor: colorTheme.textHighEmphasis, - backgroundColor: channelTheme.channelHeaderTheme.color, + backgroundColor: channelHeaderTheme.color, iconMenuPointColor: colorTheme.textHighEmphasis, titleTextStyle: textTheme.headlineBold, subtitleTextStyle: channelPreviewTheme.subtitle, diff --git a/packages/stream_chat_flutter/lib/src/theme/channel_header_theme.dart b/packages/stream_chat_flutter/lib/src/theme/channel_header_theme.dart index 2d3253dc..63e208e5 100644 --- a/packages/stream_chat_flutter/lib/src/theme/channel_header_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/channel_header_theme.dart @@ -36,7 +36,7 @@ class ChannelHeaderTheme extends InheritedTheme { final channelHeaderTheme = context.dependOnInheritedWidgetOfExactType(); return channelHeaderTheme?.data ?? - StreamChatTheme.of(context).channelTheme.channelHeaderTheme; + StreamChatTheme.of(context).channelHeaderTheme; } @override diff --git a/packages/stream_chat_flutter/lib/src/theme/channel_theme.dart b/packages/stream_chat_flutter/lib/src/theme/channel_theme.dart deleted file mode 100644 index a8c6260d..00000000 --- a/packages/stream_chat_flutter/lib/src/theme/channel_theme.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'package:stream_chat_flutter/src/theme/channel_header_theme.dart'; - -/// Channel theme data -class ChannelTheme { - /// Constructor for creating [ChannelTheme] - ChannelTheme({ - required this.channelHeaderTheme, - }); - - /// Theme of the [ChannelHeader] widget - final ChannelHeaderThemeData channelHeaderTheme; - - /// Creates a copy of [ChannelTheme] with specified attributes overridden. - ChannelTheme copyWith({ - ChannelHeaderThemeData? channelHeaderTheme, - }) => - ChannelTheme( - channelHeaderTheme: channelHeaderTheme ?? this.channelHeaderTheme, - ); - - /// Merge with theme - ChannelTheme merge(ChannelTheme? other) { - if (other == null) return this; - return copyWith( - channelHeaderTheme: channelHeaderTheme.merge(other.channelHeaderTheme), - ); - } -} diff --git a/packages/stream_chat_flutter/lib/src/theme/themes.dart b/packages/stream_chat_flutter/lib/src/theme/themes.dart index a3e974e8..7e2fb0aa 100644 --- a/packages/stream_chat_flutter/lib/src/theme/themes.dart +++ b/packages/stream_chat_flutter/lib/src/theme/themes.dart @@ -3,7 +3,6 @@ export 'channel_header_theme.dart'; export 'channel_list_header_theme.dart'; export 'channel_list_view_theme.dart'; export 'channel_preview_theme.dart'; -export 'channel_theme.dart'; export 'color_theme.dart'; export 'gallery_footer_theme.dart'; export 'gallery_header_theme.dart'; diff --git a/packages/stream_chat_flutter/lib/src/thread_header.dart b/packages/stream_chat_flutter/lib/src/thread_header.dart index 0473ca48..adf2f0e6 100644 --- a/packages/stream_chat_flutter/lib/src/thread_header.dart +++ b/packages/stream_chat_flutter/lib/src/thread_header.dart @@ -112,12 +112,11 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { children: [ Text( 'with ', - style: chatThemeData.channelTheme.channelHeaderTheme.subtitleStyle, + style: chatThemeData.channelHeaderTheme.subtitleStyle, ), Flexible( child: ChannelName( - textStyle: - chatThemeData.channelTheme.channelHeaderTheme.subtitleStyle, + textStyle: chatThemeData.channelHeaderTheme.subtitleStyle, ), ), ], @@ -136,7 +135,7 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { showUnreads: true, ) : const SizedBox()), - backgroundColor: chatThemeData.channelTheme.channelHeaderTheme.color, + backgroundColor: chatThemeData.channelHeaderTheme.color, centerTitle: true, actions: actions, title: InkWell( @@ -150,14 +149,14 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { title ?? Text( 'Thread Reply', - style: chatThemeData.channelTheme.channelHeaderTheme.titleStyle, + style: chatThemeData.channelHeaderTheme.titleStyle, ), const SizedBox(height: 2), if (showTypingIndicator) TypingIndicator( alignment: Alignment.center, channel: StreamChannel.of(context).channel, - style: chatThemeData.channelTheme.channelHeaderTheme.subtitleStyle, + style: chatThemeData.channelHeaderTheme.subtitleStyle, parentId: parent.id, alternativeWidget: defaultSubtitle, ) From 5afc274a6d8ff7091c700ffb048c47224f8af561 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Thu, 29 Jul 2021 10:48:52 -0400 Subject: [PATCH 12/42] chore: add lerp, hashcode, ==, and diagnosticable to message_input_theme.dart --- .../lib/src/message_actions_modal.dart | 3 +- .../lib/src/message_input.dart | 4 +- .../lib/src/stream_chat_theme.dart | 2 +- .../lib/src/theme/message_input_theme.dart | 92 +++++++++++++++++-- 4 files changed, 91 insertions(+), 10 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_actions_modal.dart b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart index efaf0ded..11d96e77 100644 --- a/packages/stream_chat_flutter/lib/src/message_actions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart @@ -562,7 +562,8 @@ class _MessageActionsModalState extends State { elevation: 2, clipBehavior: Clip.hardEdge, isScrollControlled: true, - backgroundColor: streamChatThemeData.messageInputTheme.inputBackground, + backgroundColor: + streamChatThemeData.messageInputTheme.inputBackgroundColor, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(16), diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index 5a4f6822..2030f47a 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -328,7 +328,7 @@ class MessageInputState extends State { Widget build(BuildContext context) { Widget child = DecoratedBox( decoration: BoxDecoration( - color: _streamChatTheme.messageInputTheme.inputBackground, + color: _streamChatTheme.messageInputTheme.inputBackgroundColor, ), child: SafeArea( child: GestureDetector( @@ -565,7 +565,7 @@ class MessageInputState extends State { child: DecoratedBox( decoration: BoxDecoration( borderRadius: _streamChatTheme.messageInputTheme.borderRadius, - color: _streamChatTheme.messageInputTheme.inputBackground, + color: _streamChatTheme.messageInputTheme.inputBackgroundColor, ), child: Column( mainAxisSize: MainAxisSize.min, diff --git a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart index 98a6e156..3f9c39fe 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart @@ -378,7 +378,7 @@ class StreamChatThemeData { expandButtonColor: colorTheme.accentPrimary, sendButtonColor: colorTheme.accentPrimary, sendButtonIdleColor: colorTheme.disabled, - inputBackground: colorTheme.barsBg, + inputBackgroundColor: colorTheme.barsBg, inputTextStyle: textTheme.body, idleBorderGradient: LinearGradient( colors: [ diff --git a/packages/stream_chat_flutter/lib/src/theme/message_input_theme.dart b/packages/stream_chat_flutter/lib/src/theme/message_input_theme.dart index 09c99478..1d14c1b9 100644 --- a/packages/stream_chat_flutter/lib/src/theme/message_input_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/message_input_theme.dart @@ -1,8 +1,9 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/extension.dart'; /// Defines the theme dedicated to the [MessageInput] widget -class MessageInputTheme { +class MessageInputTheme with Diagnosticable { /// Returns a new [MessageInputTheme] const MessageInputTheme({ this.sendAnimationDuration, @@ -10,7 +11,7 @@ class MessageInputTheme { this.sendButtonColor, this.actionButtonIdleColor, this.sendButtonIdleColor, - this.inputBackground, + this.inputBackgroundColor, this.inputTextStyle, this.inputDecoration, this.activeBorderGradient, @@ -38,7 +39,7 @@ class MessageInputTheme { final Color? expandButtonColor; /// Background color of [MessageInput] - final Color? inputBackground; + final Color? inputBackgroundColor; /// TextStyle of [MessageInput] final TextStyle? inputTextStyle; @@ -58,7 +59,7 @@ class MessageInputTheme { /// Returns a new [MessageInputTheme] replacing some of its properties MessageInputTheme copyWith({ Duration? sendAnimationDuration, - Color? inputBackground, + Color? inputBackgroundColor, Color? actionButtonColor, Color? sendButtonColor, Color? actionButtonIdleColor, @@ -73,7 +74,7 @@ class MessageInputTheme { MessageInputTheme( sendAnimationDuration: sendAnimationDuration ?? this.sendAnimationDuration, - inputBackground: inputBackground ?? this.inputBackground, + inputBackgroundColor: inputBackgroundColor ?? this.inputBackgroundColor, actionButtonColor: actionButtonColor ?? this.actionButtonColor, sendButtonColor: sendButtonColor ?? this.sendButtonColor, actionButtonIdleColor: @@ -87,12 +88,40 @@ class MessageInputTheme { borderRadius: borderRadius ?? this.borderRadius, ); + /// Linearly interpolate from one [MessageInputTheme] to another. + MessageInputTheme lerp( + MessageInputTheme a, + MessageInputTheme b, + double t, + ) => + MessageInputTheme( + 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] [MessageInputTheme] with the [other] MessageInputTheme merge(MessageInputTheme? other) { if (other == null) return this; return copyWith( sendAnimationDuration: other.sendAnimationDuration, - inputBackground: other.inputBackground, + inputBackgroundColor: other.inputBackgroundColor, actionButtonColor: other.actionButtonColor, actionButtonIdleColor: other.actionButtonIdleColor, sendButtonColor: other.sendButtonColor, @@ -107,4 +136,55 @@ class MessageInputTheme { expandButtonColor: other.expandButtonColor, ); } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is MessageInputTheme && + 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)); + } } From 8fb45ec4d1530361cd2f2008c0ec83c9a339f36a Mon Sep 17 00:00:00 2001 From: groovinchip Date: Thu, 29 Jul 2021 10:50:03 -0400 Subject: [PATCH 13/42] chore: rename MessageInputTheme to MessageInputThemeData --- .../lib/src/stream_chat_theme.dart | 8 +++--- .../lib/src/theme/message_input_theme.dart | 28 +++++++++---------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart index 3f9c39fe..c2eb8c85 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart @@ -52,7 +52,7 @@ class StreamChatThemeData { ChannelHeaderThemeData? channelHeaderTheme, MessageTheme? otherMessageTheme, MessageTheme? ownMessageTheme, - MessageInputTheme? messageInputTheme, + MessageInputThemeData? messageInputTheme, Widget Function(BuildContext, User)? defaultUserImage, IconThemeData? primaryIconTheme, List? reactionIcons, @@ -165,7 +165,7 @@ class StreamChatThemeData { final MessageTheme otherMessageTheme; /// Theme dedicated to the [MessageInput] widget - final MessageInputTheme messageInputTheme; + final MessageInputThemeData messageInputTheme; /// The widget that will be built when the user image is unavailable final Widget Function(BuildContext, User) defaultUserImage; @@ -197,7 +197,7 @@ class StreamChatThemeData { ChannelHeaderThemeData? channelHeaderTheme, MessageTheme? ownMessageTheme, MessageTheme? otherMessageTheme, - MessageInputTheme? messageInputTheme, + MessageInputThemeData? messageInputTheme, Widget Function(BuildContext, User)? defaultUserImage, IconThemeData? primaryIconTheme, ChannelListHeaderTheme? channelListHeaderTheme, @@ -370,7 +370,7 @@ class StreamChatThemeData { ), ), ), - messageInputTheme: MessageInputTheme( + messageInputTheme: MessageInputThemeData( borderRadius: BorderRadius.circular(20), sendAnimationDuration: const Duration(milliseconds: 300), actionButtonColor: colorTheme.accentPrimary, diff --git a/packages/stream_chat_flutter/lib/src/theme/message_input_theme.dart b/packages/stream_chat_flutter/lib/src/theme/message_input_theme.dart index 1d14c1b9..45f4a6b7 100644 --- a/packages/stream_chat_flutter/lib/src/theme/message_input_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/message_input_theme.dart @@ -3,9 +3,9 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/extension.dart'; /// Defines the theme dedicated to the [MessageInput] widget -class MessageInputTheme with Diagnosticable { - /// Returns a new [MessageInputTheme] - const MessageInputTheme({ +class MessageInputThemeData with Diagnosticable { + /// Returns a new [MessageInputThemeData] + const MessageInputThemeData({ this.sendAnimationDuration, this.actionButtonColor, this.sendButtonColor, @@ -56,8 +56,8 @@ class MessageInputTheme with Diagnosticable { /// Border radius of [MessageInput] final BorderRadius? borderRadius; - /// Returns a new [MessageInputTheme] replacing some of its properties - MessageInputTheme copyWith({ + /// Returns a new [MessageInputThemeData] replacing some of its properties + MessageInputThemeData copyWith({ Duration? sendAnimationDuration, Color? inputBackgroundColor, Color? actionButtonColor, @@ -71,7 +71,7 @@ class MessageInputTheme with Diagnosticable { Gradient? idleBorderGradient, BorderRadius? borderRadius, }) => - MessageInputTheme( + MessageInputThemeData( sendAnimationDuration: sendAnimationDuration ?? this.sendAnimationDuration, inputBackgroundColor: inputBackgroundColor ?? this.inputBackgroundColor, @@ -88,13 +88,13 @@ class MessageInputTheme with Diagnosticable { borderRadius: borderRadius ?? this.borderRadius, ); - /// Linearly interpolate from one [MessageInputTheme] to another. - MessageInputTheme lerp( - MessageInputTheme a, - MessageInputTheme b, + /// Linearly interpolate from one [MessageInputThemeData] to another. + MessageInputThemeData lerp( + MessageInputThemeData a, + MessageInputThemeData b, double t, ) => - MessageInputTheme( + MessageInputThemeData( actionButtonColor: Color.lerp(a.actionButtonColor, b.actionButtonColor, t), actionButtonIdleColor: @@ -116,8 +116,8 @@ class MessageInputTheme with Diagnosticable { inputDecoration: a.inputDecoration, ); - /// Merges [this] [MessageInputTheme] with the [other] - MessageInputTheme merge(MessageInputTheme? other) { + /// Merges [this] [MessageInputThemeData] with the [other] + MessageInputThemeData merge(MessageInputThemeData? other) { if (other == null) return this; return copyWith( sendAnimationDuration: other.sendAnimationDuration, @@ -140,7 +140,7 @@ class MessageInputTheme with Diagnosticable { @override bool operator ==(Object other) => identical(this, other) || - other is MessageInputTheme && + other is MessageInputThemeData && runtimeType == other.runtimeType && sendAnimationDuration == other.sendAnimationDuration && sendButtonColor == other.sendButtonColor && From 700ce9a7753573ff750a6c06cb313db42a15e779 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Thu, 29 Jul 2021 11:02:29 -0400 Subject: [PATCH 14/42] chore: add a MessageInputTheme inherited theme --- .../lib/src/theme/message_input_theme.dart | 51 ++++++++++++++++++- 1 file changed, 49 insertions(+), 2 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/theme/message_input_theme.dart b/packages/stream_chat_flutter/lib/src/theme/message_input_theme.dart index 45f4a6b7..26a995a9 100644 --- a/packages/stream_chat_flutter/lib/src/theme/message_input_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/message_input_theme.dart @@ -1,10 +1,57 @@ 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'; -/// Defines the theme dedicated to the [MessageInput] widget +/// 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(); + 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 { - /// Returns a new [MessageInputThemeData] + /// Creates a [MessageInputThemeData]. const MessageInputThemeData({ this.sendAnimationDuration, this.actionButtonColor, From 1aa62987994e02b9a6fca2c4323f0b52dfb7a9d7 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Thu, 29 Jul 2021 11:07:17 -0400 Subject: [PATCH 15/42] chore: use MessageInputTheme in message_input.dart --- .../lib/src/message_input.dart | 36 ++++++++++--------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_input.dart b/packages/stream_chat_flutter/lib/src/message_input.dart index 2030f47a..30bfd747 100644 --- a/packages/stream_chat_flutter/lib/src/message_input.dart +++ b/packages/stream_chat_flutter/lib/src/message_input.dart @@ -288,6 +288,7 @@ class MessageInputState extends State { late final TextEditingController textEditingController; late StreamChatThemeData _streamChatTheme; + late MessageInputThemeData _messageInputTheme; bool get _hasQuotedMessage => widget.quotedMessage != null; @@ -328,7 +329,7 @@ class MessageInputState extends State { Widget build(BuildContext context) { Widget child = DecoratedBox( decoration: BoxDecoration( - color: _streamChatTheme.messageInputTheme.inputBackgroundColor, + color: _messageInputTheme.inputBackgroundColor, ), child: SafeArea( child: GestureDetector( @@ -484,7 +485,7 @@ class MessageInputState extends State { : CrossFadeState.showSecond, firstChild: sendButton, secondChild: widget.idleSendButton ?? _buildIdleSendButton(context), - duration: _streamChatTheme.messageInputTheme.sendAnimationDuration!, + duration: _messageInputTheme.sendAnimationDuration!, alignment: Alignment.center, ); } @@ -509,7 +510,7 @@ class MessageInputState extends State { ? pi : 0, child: StreamSvgIcon.emptyCircleLeft( - color: _streamChatTheme.messageInputTheme.expandButtonColor, + color: _messageInputTheme.expandButtonColor, ), ), padding: const EdgeInsets.all(0), @@ -555,17 +556,17 @@ class MessageInputState extends State { clipBehavior: Clip.hardEdge, margin: margin, decoration: BoxDecoration( - borderRadius: _streamChatTheme.messageInputTheme.borderRadius, + borderRadius: _messageInputTheme.borderRadius, gradient: _focusNode.hasFocus - ? _streamChatTheme.messageInputTheme.activeBorderGradient - : _streamChatTheme.messageInputTheme.idleBorderGradient, + ? _messageInputTheme.activeBorderGradient + : _messageInputTheme.idleBorderGradient, ), child: Padding( padding: const EdgeInsets.all(1.5), child: DecoratedBox( decoration: BoxDecoration( - borderRadius: _streamChatTheme.messageInputTheme.borderRadius, - color: _streamChatTheme.messageInputTheme.inputBackgroundColor, + borderRadius: _messageInputTheme.borderRadius, + color: _messageInputTheme.inputBackgroundColor, ), child: Column( mainAxisSize: MainAxisSize.min, @@ -583,7 +584,7 @@ class MessageInputState extends State { keyboardType: widget.keyboardType, controller: textEditingController, focusNode: _focusNode, - style: _streamChatTheme.messageInputTheme.inputTextStyle, + style: _messageInputTheme.inputTextStyle, autofocus: widget.autofocus, textAlignVertical: TextAlignVertical.center, decoration: _getInputDecoration(), @@ -599,11 +600,11 @@ class MessageInputState extends State { } InputDecoration _getInputDecoration() { - final passedDecoration = _streamChatTheme.messageInputTheme.inputDecoration; + final passedDecoration = _messageInputTheme.inputDecoration; return InputDecoration( isDense: true, hintText: _getHint(), - hintStyle: _streamChatTheme.messageInputTheme.inputTextStyle!.copyWith( + hintStyle: _messageInputTheme.inputTextStyle!.copyWith( color: _streamChatTheme.colorTheme.textLowEmphasis, ), border: const OutlineInputBorder( @@ -1685,8 +1686,8 @@ class MessageInputState extends State { color: s.isNotEmpty ? _streamChatTheme.colorTheme.disabled : (_commandsOverlay != null - ? _streamChatTheme.messageInputTheme.actionButtonColor - : _streamChatTheme.messageInputTheme.actionButtonIdleColor), + ? _messageInputTheme.actionButtonColor + : _messageInputTheme.actionButtonIdleColor), ), padding: const EdgeInsets.all(0), constraints: const BoxConstraints.tightFor( @@ -1723,8 +1724,8 @@ class MessageInputState extends State { Widget _buildAttachmentButton() => IconButton( icon: StreamSvgIcon.attach( color: _openFilePickerSection - ? _streamChatTheme.messageInputTheme.actionButtonColor - : _streamChatTheme.messageInputTheme.actionButtonIdleColor, + ? _messageInputTheme.actionButtonColor + : _messageInputTheme.actionButtonIdleColor, ), padding: const EdgeInsets.all(0), constraints: const BoxConstraints.tightFor( @@ -1959,7 +1960,7 @@ class MessageInputState extends State { padding: const EdgeInsets.all(8), child: StreamSvgIcon( assetName: _getIdleSendIcon(), - color: _streamChatTheme.messageInputTheme.sendButtonIdleColor, + color: _messageInputTheme.sendButtonIdleColor, ), ); @@ -1975,7 +1976,7 @@ class MessageInputState extends State { ), icon: StreamSvgIcon( assetName: _getSendIcon(), - color: _streamChatTheme.messageInputTheme.sendButtonColor, + color: _messageInputTheme.sendButtonColor, ), ), ); @@ -2182,6 +2183,7 @@ class MessageInputState extends State { @override void didChangeDependencies() { _streamChatTheme = StreamChatTheme.of(context); + _messageInputTheme = MessageInputTheme.of(context); if (widget.editMessage != null && !_initialized) { FocusScope.of(context).requestFocus(_focusNode); _initialized = true; From 822b0ad725abff8d85708640859689cd4d4062eb Mon Sep 17 00:00:00 2001 From: groovinchip Date: Thu, 29 Jul 2021 13:59:02 -0400 Subject: [PATCH 16/42] test: start testing MessageInputTheme --- .../src/theme/message_input_theme_test.dart | 93 +++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 packages/stream_chat_flutter/test/src/theme/message_input_theme_test.dart diff --git a/packages/stream_chat_flutter/test/src/theme/message_input_theme_test.dart b/packages/stream_chat_flutter/test/src/theme/message_input_theme_test.dart new file mode 100644 index 00000000..b1427509 --- /dev/null +++ b/packages/stream_chat_flutter/test/src/theme/message_input_theme_test.dart @@ -0,0 +1,93 @@ +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); + }); + }); +} + +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( + colors: [ + ColorTheme.light().disabled, + ColorTheme.light().disabled, + ], + ), + activeBorderGradient: LinearGradient( + colors: [ + ColorTheme.light().disabled, + ColorTheme.light().disabled, + ], + ), +); + +final _messageInputThemeControlMidLerp = 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( + colors: [ + ColorTheme.light().disabled, + ColorTheme.light().disabled, + ], + ), + activeBorderGradient: LinearGradient( + colors: [ + ColorTheme.light().disabled, + ColorTheme.light().disabled, + ], + ), +); + +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( + colors: [ + ColorTheme.dark().disabled, + ColorTheme.dark().disabled, + ], + ), + activeBorderGradient: LinearGradient( + colors: [ + ColorTheme.dark().disabled, + ColorTheme.dark().disabled, + ], + ), +); From cc89edc2444b4136cf72dc1a531ce3bab72d8889 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Fri, 30 Jul 2021 10:30:33 -0400 Subject: [PATCH 17/42] test: fix light to dark test, add dark to light test --- .../test/src/theme/message_input_theme_test.dart | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/stream_chat_flutter/test/src/theme/message_input_theme_test.dart b/packages/stream_chat_flutter/test/src/theme/message_input_theme_test.dart index b1427509..b19d5dee 100644 --- a/packages/stream_chat_flutter/test/src/theme/message_input_theme_test.dart +++ b/packages/stream_chat_flutter/test/src/theme/message_input_theme_test.dart @@ -17,6 +17,13 @@ void main() { _messageInputThemeControl, _messageInputThemeControlDark, 1), _messageInputThemeControlDark); }); + + test('Lerp completely from dark to light', () { + expect( + const MessageInputThemeData().lerp( + _messageInputThemeControlDark, _messageInputThemeControl, 1), + _messageInputThemeControl); + }); }); } @@ -79,12 +86,14 @@ final _messageInputThemeControlDark = MessageInputThemeData( 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, From f0f2418e92bb28bed4d17ad8020053f324ff7e10 Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Fri, 30 Jul 2021 20:39:10 +0530 Subject: [PATCH 18/42] test(ui): fix lerp dark to light test Signed-off-by: Sahil Kumar --- .../test/src/theme/message_input_theme_test.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/stream_chat_flutter/test/src/theme/message_input_theme_test.dart b/packages/stream_chat_flutter/test/src/theme/message_input_theme_test.dart index b19d5dee..227cdc9c 100644 --- a/packages/stream_chat_flutter/test/src/theme/message_input_theme_test.dart +++ b/packages/stream_chat_flutter/test/src/theme/message_input_theme_test.dart @@ -38,12 +38,14 @@ final _messageInputThemeControl = MessageInputThemeData( 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, From 5b99507db350121e5ab52a2b075a65f0b5e8fcc5 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Fri, 30 Jul 2021 11:34:46 -0400 Subject: [PATCH 19/42] test: lerp halfway from light to dark --- .../src/theme/message_input_theme_test.dart | 39 ++++++++++++------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/packages/stream_chat_flutter/test/src/theme/message_input_theme_test.dart b/packages/stream_chat_flutter/test/src/theme/message_input_theme_test.dart index 227cdc9c..69e9669a 100644 --- a/packages/stream_chat_flutter/test/src/theme/message_input_theme_test.dart +++ b/packages/stream_chat_flutter/test/src/theme/message_input_theme_test.dart @@ -18,6 +18,13 @@ void main() { _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( @@ -56,23 +63,29 @@ final _messageInputThemeControl = MessageInputThemeData( final _messageInputThemeControlMidLerp = 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( + 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: [ - ColorTheme.light().disabled, - ColorTheme.light().disabled, + Color(0xff848585), + Color(0xff848585), ], ), - activeBorderGradient: LinearGradient( + activeBorderGradient: const LinearGradient( + stops: [0.0, 1.0], colors: [ - ColorTheme.light().disabled, - ColorTheme.light().disabled, + Color(0xff848585), + Color(0xff848585), ], ), ); From c7d399704e4c6614c9ed012289b6184254a69e12 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Fri, 30 Jul 2021 11:35:32 -0400 Subject: [PATCH 20/42] test: Merging two MessageInputThemeData results in the latter --- .../test/src/theme/message_input_theme_test.dart | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/stream_chat_flutter/test/src/theme/message_input_theme_test.dart b/packages/stream_chat_flutter/test/src/theme/message_input_theme_test.dart index 69e9669a..c618d65c 100644 --- a/packages/stream_chat_flutter/test/src/theme/message_input_theme_test.dart +++ b/packages/stream_chat_flutter/test/src/theme/message_input_theme_test.dart @@ -32,6 +32,11 @@ void main() { _messageInputThemeControl); }); }); + + test('Merging two MessageInputThemeData results in the latter', () { + expect(_messageInputThemeControl.merge(_messageInputThemeControlDark), + _messageInputThemeControlDark); + }); } final _messageInputThemeControl = MessageInputThemeData( From 67658541329c9a4fd8fe64a07e9bbe9b6a3aff1c Mon Sep 17 00:00:00 2001 From: groovinchip Date: Fri, 30 Jul 2021 13:43:22 -0400 Subject: [PATCH 21/42] chore: rename ChannelPreviewTheme.title and .subtitle to .titleStyle and .subtitleStyle --- .../example/lib/tutorial_part_3.dart | 2 +- .../lib/src/channel_bottom_sheet.dart | 2 +- .../lib/src/channel_preview.dart | 14 +++++++------- .../lib/src/message_search_item.dart | 10 +++++----- .../lib/src/stream_chat_theme.dart | 6 +++--- .../lib/src/theme/channel_preview_theme.dart | 16 ++++++++-------- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/packages/stream_chat_flutter/example/lib/tutorial_part_3.dart b/packages/stream_chat_flutter/example/lib/tutorial_part_3.dart index 9658eec4..b6214ff9 100644 --- a/packages/stream_chat_flutter/example/lib/tutorial_part_3.dart +++ b/packages/stream_chat_flutter/example/lib/tutorial_part_3.dart @@ -119,7 +119,7 @@ class ChannelListPage extends StatelessWidget { ), title: ChannelName( textStyle: - StreamChatTheme.of(context).channelPreviewTheme.title!.copyWith( + StreamChatTheme.of(context).channelPreviewTheme.titleStyle!.copyWith( color: StreamChatTheme.of(context) .colorTheme .textHighEmphasis diff --git a/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart b/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart index 0d40c67a..a9b8a2f7 100644 --- a/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart +++ b/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart @@ -64,7 +64,7 @@ class _ChannelBottomSheetState extends State { showTypingIndicator: false, channel: _streamChannelState.channel, textStyle: - _streamChatThemeData.channelPreviewTheme.subtitle, + _streamChatThemeData.channelPreviewTheme.subtitleStyle, ), ), const SizedBox( diff --git a/packages/stream_chat_flutter/lib/src/channel_preview.dart b/packages/stream_chat_flutter/lib/src/channel_preview.dart index 81d09e3c..74c46ca5 100644 --- a/packages/stream_chat_flutter/lib/src/channel_preview.dart +++ b/packages/stream_chat_flutter/lib/src/channel_preview.dart @@ -90,7 +90,7 @@ class ChannelPreview extends StatelessWidget { Flexible( child: title ?? ChannelName( - textStyle: channelPreviewTheme.title, + textStyle: channelPreviewTheme.titleStyle, ), ), BetterStreamBuilder?>( @@ -199,7 +199,7 @@ class ChannelPreview extends StatelessWidget { ), Text( ' Channel is muted', - style: chatThemeData.channelPreviewTheme.subtitle, + style: chatThemeData.channelPreviewTheme.subtitleStyle, ), ], ); @@ -207,7 +207,7 @@ class ChannelPreview extends StatelessWidget { return TypingIndicator( channel: channel, alternativeWidget: _buildLastMessage(context), - style: chatThemeData.channelPreviewTheme.subtitle, + style: chatThemeData.channelPreviewTheme.subtitleStyle, ); } @@ -248,13 +248,13 @@ class ChannelPreview extends StatelessWidget { text, lastMessage.mentionedUsers, lastMessage.attachments, - chatThemeData.channelPreviewTheme.subtitle?.copyWith( - color: chatThemeData.channelPreviewTheme.subtitle?.color, + chatThemeData.channelPreviewTheme.subtitleStyle?.copyWith( + color: chatThemeData.channelPreviewTheme.subtitleStyle?.color, fontStyle: (lastMessage.isSystem || lastMessage.isDeleted) ? FontStyle.italic : FontStyle.normal), - chatThemeData.channelPreviewTheme.subtitle?.copyWith( - color: chatThemeData.channelPreviewTheme.subtitle?.color, + chatThemeData.channelPreviewTheme.subtitleStyle?.copyWith( + color: chatThemeData.channelPreviewTheme.subtitleStyle?.color, fontStyle: (lastMessage.isSystem || lastMessage.isDeleted) ? FontStyle.italic : FontStyle.normal, diff --git a/packages/stream_chat_flutter/lib/src/message_search_item.dart b/packages/stream_chat_flutter/lib/src/message_search_item.dart index d44ddd0d..9bb0ffd1 100644 --- a/packages/stream_chat_flutter/lib/src/message_search_item.dart +++ b/packages/stream_chat_flutter/lib/src/message_search_item.dart @@ -52,18 +52,18 @@ class MessageSearchItem extends StatelessWidget { user.id == StreamChat.of(context).currentUser?.id ? 'You' : user.name, - style: chatThemeData.channelPreviewTheme.title, + style: chatThemeData.channelPreviewTheme.titleStyle, ), if (channelName != null) ...[ Text( ' in ', - style: chatThemeData.channelPreviewTheme.title?.copyWith( + style: chatThemeData.channelPreviewTheme.titleStyle?.copyWith( fontWeight: FontWeight.normal, ), ), Text( channelName as String, - style: chatThemeData.channelPreviewTheme.title, + style: chatThemeData.channelPreviewTheme.titleStyle, ), ], ], @@ -127,12 +127,12 @@ class MessageSearchItem extends StatelessWidget { text!, message.mentionedUsers, message.attachments, - chatThemeData.channelPreviewTheme.subtitle?.copyWith( + chatThemeData.channelPreviewTheme.subtitleStyle?.copyWith( fontStyle: (message.isSystem || message.isDeleted) ? FontStyle.italic : FontStyle.normal, ), - chatThemeData.channelPreviewTheme.subtitle?.copyWith( + chatThemeData.channelPreviewTheme.subtitleStyle?.copyWith( fontStyle: (message.isSystem || message.isDeleted) ? FontStyle.italic : FontStyle.normal, diff --git a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart index c2eb8c85..000f5aab 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart @@ -292,8 +292,8 @@ class StreamChatThemeData { width: 40, ), ), - title: textTheme.bodyBold, - subtitle: textTheme.footnote.copyWith( + titleStyle: textTheme.bodyBold, + subtitleStyle: textTheme.footnote.copyWith( color: const Color(0xff7A7A7A), ), lastMessageAt: textTheme.footnote.copyWith( @@ -460,7 +460,7 @@ class StreamChatThemeData { backgroundColor: channelHeaderTheme.color, iconMenuPointColor: colorTheme.textHighEmphasis, titleTextStyle: textTheme.headlineBold, - subtitleTextStyle: channelPreviewTheme.subtitle, + subtitleTextStyle: channelPreviewTheme.subtitleStyle, bottomSheetBarrierColor: colorTheme.overlay, ), galleryFooterTheme: GalleryFooterThemeData( diff --git a/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart b/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart index 2fcecaf7..ceeb3c16 100644 --- a/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart @@ -5,8 +5,8 @@ import 'package:stream_chat_flutter/src/theme/avatar_theme.dart'; class ChannelPreviewTheme { /// Constructor for creating [ChannelPreviewTheme] const ChannelPreviewTheme({ - this.title, - this.subtitle, + this.titleStyle, + this.subtitleStyle, this.lastMessageAt, this.avatarTheme, this.unreadCounterColor, @@ -14,10 +14,10 @@ class ChannelPreviewTheme { }); /// Theme for title - final TextStyle? title; + final TextStyle? titleStyle; /// Theme for subtitle - final TextStyle? subtitle; + final TextStyle? subtitleStyle; /// Theme of last message at final TextStyle? lastMessageAt; @@ -41,8 +41,8 @@ class ChannelPreviewTheme { double? indicatorIconSize, }) => ChannelPreviewTheme( - title: title ?? this.title, - subtitle: subtitle ?? this.subtitle, + titleStyle: title ?? this.titleStyle, + subtitleStyle: subtitle ?? this.subtitleStyle, lastMessageAt: lastMessageAt ?? this.lastMessageAt, avatarTheme: avatarTheme ?? this.avatarTheme, unreadCounterColor: unreadCounterColor ?? this.unreadCounterColor, @@ -53,8 +53,8 @@ class ChannelPreviewTheme { ChannelPreviewTheme merge(ChannelPreviewTheme? other) { if (other == null) return this; return copyWith( - title: title?.merge(other.title) ?? other.title, - subtitle: subtitle?.merge(other.subtitle) ?? other.subtitle, + title: titleStyle?.merge(other.titleStyle) ?? other.titleStyle, + subtitle: subtitleStyle?.merge(other.subtitleStyle) ?? other.subtitleStyle, lastMessageAt: lastMessageAt?.merge(other.lastMessageAt) ?? other.lastMessageAt, avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, From 019bd5d5da18f48cfc6595fdfb21b75c697bb5fb Mon Sep 17 00:00:00 2001 From: groovinchip Date: Fri, 30 Jul 2021 13:44:53 -0400 Subject: [PATCH 22/42] chore: run dartfmt on changed files --- .../example/lib/tutorial_part_3.dart | 16 +++++++++------- .../lib/src/channel_preview.dart | 3 ++- .../lib/src/theme/channel_preview_theme.dart | 3 ++- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/stream_chat_flutter/example/lib/tutorial_part_3.dart b/packages/stream_chat_flutter/example/lib/tutorial_part_3.dart index b6214ff9..a6e80b57 100644 --- a/packages/stream_chat_flutter/example/lib/tutorial_part_3.dart +++ b/packages/stream_chat_flutter/example/lib/tutorial_part_3.dart @@ -118,13 +118,15 @@ class ChannelListPage extends StatelessWidget { channel: channel, ), title: ChannelName( - textStyle: - StreamChatTheme.of(context).channelPreviewTheme.titleStyle!.copyWith( - color: StreamChatTheme.of(context) - .colorTheme - .textHighEmphasis - .withOpacity(opacity), - ), + textStyle: StreamChatTheme.of(context) + .channelPreviewTheme + .titleStyle! + .copyWith( + color: StreamChatTheme.of(context) + .colorTheme + .textHighEmphasis + .withOpacity(opacity), + ), ), subtitle: Text(subtitle), trailing: channel.state!.unreadCount > 0 diff --git a/packages/stream_chat_flutter/lib/src/channel_preview.dart b/packages/stream_chat_flutter/lib/src/channel_preview.dart index 74c46ca5..2a9b82da 100644 --- a/packages/stream_chat_flutter/lib/src/channel_preview.dart +++ b/packages/stream_chat_flutter/lib/src/channel_preview.dart @@ -249,7 +249,8 @@ class ChannelPreview extends StatelessWidget { lastMessage.mentionedUsers, lastMessage.attachments, chatThemeData.channelPreviewTheme.subtitleStyle?.copyWith( - color: chatThemeData.channelPreviewTheme.subtitleStyle?.color, + color: + chatThemeData.channelPreviewTheme.subtitleStyle?.color, fontStyle: (lastMessage.isSystem || lastMessage.isDeleted) ? FontStyle.italic : FontStyle.normal), diff --git a/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart b/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart index ceeb3c16..673061e9 100644 --- a/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart @@ -54,7 +54,8 @@ class ChannelPreviewTheme { if (other == null) return this; return copyWith( title: titleStyle?.merge(other.titleStyle) ?? other.titleStyle, - subtitle: subtitleStyle?.merge(other.subtitleStyle) ?? other.subtitleStyle, + subtitle: + subtitleStyle?.merge(other.subtitleStyle) ?? other.subtitleStyle, lastMessageAt: lastMessageAt?.merge(other.lastMessageAt) ?? other.lastMessageAt, avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, From f55110c458a1014dccda093c3fde9df30691c140 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Fri, 30 Jul 2021 13:45:58 -0400 Subject: [PATCH 23/42] fix: instances where new naming wasn't applied --- .../lib/src/theme/channel_preview_theme.dart | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart b/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart index 673061e9..bb7a638f 100644 --- a/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart @@ -33,16 +33,16 @@ class ChannelPreviewTheme { /// Copy with theme ChannelPreviewTheme copyWith({ - TextStyle? title, - TextStyle? subtitle, + TextStyle? titleStyle, + TextStyle? subtitleStyle, TextStyle? lastMessageAt, AvatarThemeData? avatarTheme, Color? unreadCounterColor, double? indicatorIconSize, }) => ChannelPreviewTheme( - titleStyle: title ?? this.titleStyle, - subtitleStyle: subtitle ?? this.subtitleStyle, + titleStyle: titleStyle ?? this.titleStyle, + subtitleStyle: subtitleStyle ?? this.subtitleStyle, lastMessageAt: lastMessageAt ?? this.lastMessageAt, avatarTheme: avatarTheme ?? this.avatarTheme, unreadCounterColor: unreadCounterColor ?? this.unreadCounterColor, @@ -53,8 +53,8 @@ class ChannelPreviewTheme { ChannelPreviewTheme merge(ChannelPreviewTheme? other) { if (other == null) return this; return copyWith( - title: titleStyle?.merge(other.titleStyle) ?? other.titleStyle, - subtitle: + titleStyle: titleStyle?.merge(other.titleStyle) ?? other.titleStyle, + subtitleStyle: subtitleStyle?.merge(other.subtitleStyle) ?? other.subtitleStyle, lastMessageAt: lastMessageAt?.merge(other.lastMessageAt) ?? other.lastMessageAt, From 008dc0b1df909e7a13af64a8fdff4aeb78dcbd2b Mon Sep 17 00:00:00 2001 From: groovinchip Date: Fri, 30 Jul 2021 13:48:49 -0400 Subject: [PATCH 24/42] chore: add diagnosticable properties to channel_preview_theme.dart --- .../lib/src/theme/channel_preview_theme.dart | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart b/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart index bb7a638f..af3b35b5 100644 --- a/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart @@ -1,8 +1,9 @@ +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/theme/avatar_theme.dart'; /// Theme for channel preview -class ChannelPreviewTheme { +class ChannelPreviewTheme with Diagnosticable { /// Constructor for creating [ChannelPreviewTheme] const ChannelPreviewTheme({ this.titleStyle, @@ -62,4 +63,15 @@ class ChannelPreviewTheme { unreadCounterColor: other.unreadCounterColor, ); } + + @override + void debugFillProperties(DiagnosticPropertiesBuilder properties) { + super.debugFillProperties(properties); + properties + ..add(DiagnosticsProperty('titleStyle', titleStyle)) + ..add(DiagnosticsProperty('subtitleStyle', subtitleStyle)) + ..add(DiagnosticsProperty('lastMessageAtStyle', lastMessageAt)) + ..add(DiagnosticsProperty('avatarTheme', avatarTheme)) + ..add(ColorProperty('unreadCounterColor', unreadCounterColor)); + } } From c5d53de53c5948af885cd2da6d8fdec28f8e5ee2 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Fri, 30 Jul 2021 13:50:42 -0400 Subject: [PATCH 25/42] chore: rename ChannelPreviewTheme.lastMessageAt to .lastMessageAtStyle --- .../lib/src/channel_preview.dart | 5 +++-- .../lib/src/message_search_item.dart | 2 +- .../lib/src/stream_chat_theme.dart | 2 +- .../lib/src/theme/channel_preview_theme.dart | 14 +++++++------- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/channel_preview.dart b/packages/stream_chat_flutter/lib/src/channel_preview.dart index 2a9b82da..8a9eb9f1 100644 --- a/packages/stream_chat_flutter/lib/src/channel_preview.dart +++ b/packages/stream_chat_flutter/lib/src/channel_preview.dart @@ -182,8 +182,9 @@ class ChannelPreview extends StatelessWidget { return Text( stringDate, - style: - StreamChatTheme.of(context).channelPreviewTheme.lastMessageAt, + style: StreamChatTheme.of(context) + .channelPreviewTheme + .lastMessageAtStyle, ); }, ); diff --git a/packages/stream_chat_flutter/lib/src/message_search_item.dart b/packages/stream_chat_flutter/lib/src/message_search_item.dart index 9bb0ffd1..c465fb44 100644 --- a/packages/stream_chat_flutter/lib/src/message_search_item.dart +++ b/packages/stream_chat_flutter/lib/src/message_search_item.dart @@ -93,7 +93,7 @@ class MessageSearchItem extends StatelessWidget { return Text( stringDate, - style: StreamChatTheme.of(context).channelPreviewTheme.lastMessageAt, + style: StreamChatTheme.of(context).channelPreviewTheme.lastMessageAtStyle, ); } diff --git a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart index 000f5aab..b323833a 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart @@ -296,7 +296,7 @@ class StreamChatThemeData { subtitleStyle: textTheme.footnote.copyWith( color: const Color(0xff7A7A7A), ), - lastMessageAt: textTheme.footnote.copyWith( + lastMessageAtStyle: textTheme.footnote.copyWith( color: colorTheme.textHighEmphasis.withOpacity(.5), ), indicatorIconSize: 16, diff --git a/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart b/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart index af3b35b5..9f264750 100644 --- a/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart @@ -8,7 +8,7 @@ class ChannelPreviewTheme with Diagnosticable { const ChannelPreviewTheme({ this.titleStyle, this.subtitleStyle, - this.lastMessageAt, + this.lastMessageAtStyle, this.avatarTheme, this.unreadCounterColor, this.indicatorIconSize, @@ -21,7 +21,7 @@ class ChannelPreviewTheme with Diagnosticable { final TextStyle? subtitleStyle; /// Theme of last message at - final TextStyle? lastMessageAt; + final TextStyle? lastMessageAtStyle; /// Avatar theme final AvatarThemeData? avatarTheme; @@ -36,7 +36,7 @@ class ChannelPreviewTheme with Diagnosticable { ChannelPreviewTheme copyWith({ TextStyle? titleStyle, TextStyle? subtitleStyle, - TextStyle? lastMessageAt, + TextStyle? lastMessageAtStyle, AvatarThemeData? avatarTheme, Color? unreadCounterColor, double? indicatorIconSize, @@ -44,7 +44,7 @@ class ChannelPreviewTheme with Diagnosticable { ChannelPreviewTheme( titleStyle: titleStyle ?? this.titleStyle, subtitleStyle: subtitleStyle ?? this.subtitleStyle, - lastMessageAt: lastMessageAt ?? this.lastMessageAt, + lastMessageAtStyle: lastMessageAtStyle ?? this.lastMessageAtStyle, avatarTheme: avatarTheme ?? this.avatarTheme, unreadCounterColor: unreadCounterColor ?? this.unreadCounterColor, indicatorIconSize: indicatorIconSize ?? this.indicatorIconSize, @@ -57,8 +57,8 @@ class ChannelPreviewTheme with Diagnosticable { titleStyle: titleStyle?.merge(other.titleStyle) ?? other.titleStyle, subtitleStyle: subtitleStyle?.merge(other.subtitleStyle) ?? other.subtitleStyle, - lastMessageAt: - lastMessageAt?.merge(other.lastMessageAt) ?? other.lastMessageAt, + lastMessageAtStyle: lastMessageAtStyle?.merge(other.lastMessageAtStyle) ?? + other.lastMessageAtStyle, avatarTheme: avatarTheme?.merge(other.avatarTheme) ?? other.avatarTheme, unreadCounterColor: other.unreadCounterColor, ); @@ -70,7 +70,7 @@ class ChannelPreviewTheme with Diagnosticable { properties ..add(DiagnosticsProperty('titleStyle', titleStyle)) ..add(DiagnosticsProperty('subtitleStyle', subtitleStyle)) - ..add(DiagnosticsProperty('lastMessageAtStyle', lastMessageAt)) + ..add(DiagnosticsProperty('lastMessageAtStyle', lastMessageAtStyle)) ..add(DiagnosticsProperty('avatarTheme', avatarTheme)) ..add(ColorProperty('unreadCounterColor', unreadCounterColor)); } From 37f4ee720e1ad2d045f4645172302709bf5babc8 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Fri, 30 Jul 2021 13:52:07 -0400 Subject: [PATCH 26/42] chore: rename ChannelPreviewTheme to ChannelPreviewThemeData --- .../example/lib/tutorial_part_6.dart | 2 +- .../lib/src/stream_chat_theme.dart | 8 ++++---- .../lib/src/theme/channel_preview_theme.dart | 12 ++++++------ 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/stream_chat_flutter/example/lib/tutorial_part_6.dart b/packages/stream_chat_flutter/example/lib/tutorial_part_6.dart index 1cf34d27..2cad67f2 100644 --- a/packages/stream_chat_flutter/example/lib/tutorial_part_6.dart +++ b/packages/stream_chat_flutter/example/lib/tutorial_part_6.dart @@ -58,7 +58,7 @@ class MyApp extends StatelessWidget { final defaultTheme = StreamChatThemeData.fromTheme(themeData); final colorTheme = defaultTheme.colorTheme; final customTheme = defaultTheme.merge(StreamChatThemeData( - channelPreviewTheme: ChannelPreviewTheme( + channelPreviewTheme: ChannelPreviewThemeData( avatarTheme: AvatarThemeData( borderRadius: BorderRadius.circular(8), ), diff --git a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart index b323833a..7a520f40 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart @@ -48,7 +48,7 @@ class StreamChatThemeData { TextTheme? textTheme, ColorTheme? colorTheme, ChannelListHeaderTheme? channelListHeaderTheme, - ChannelPreviewTheme? channelPreviewTheme, + ChannelPreviewThemeData? channelPreviewTheme, ChannelHeaderThemeData? channelHeaderTheme, MessageTheme? otherMessageTheme, MessageTheme? ownMessageTheme, @@ -142,7 +142,7 @@ class StreamChatThemeData { final ColorTheme colorTheme; /// Theme of the [ChannelPreview] - final ChannelPreviewTheme channelPreviewTheme; + final ChannelPreviewThemeData channelPreviewTheme; /// Theme of the [ChannelListHeader] final ChannelListHeaderTheme channelListHeaderTheme; @@ -193,7 +193,7 @@ class StreamChatThemeData { StreamChatThemeData copyWith({ TextTheme? textTheme, ColorTheme? colorTheme, - ChannelPreviewTheme? channelPreviewTheme, + ChannelPreviewThemeData? channelPreviewTheme, ChannelHeaderThemeData? channelHeaderTheme, MessageTheme? ownMessageTheme, MessageTheme? otherMessageTheme, @@ -283,7 +283,7 @@ class StreamChatThemeData { color: const Color(0xff7A7A7A), ), ); - final channelPreviewTheme = ChannelPreviewTheme( + final channelPreviewTheme = ChannelPreviewThemeData( unreadCounterColor: colorTheme.accentError, avatarTheme: AvatarThemeData( borderRadius: BorderRadius.circular(20), diff --git a/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart b/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart index 9f264750..023c1f0a 100644 --- a/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart @@ -3,9 +3,9 @@ import 'package:flutter/material.dart'; import 'package:stream_chat_flutter/src/theme/avatar_theme.dart'; /// Theme for channel preview -class ChannelPreviewTheme with Diagnosticable { - /// Constructor for creating [ChannelPreviewTheme] - const ChannelPreviewTheme({ +class ChannelPreviewThemeData with Diagnosticable { + /// Constructor for creating [ChannelPreviewThemeData] + const ChannelPreviewThemeData({ this.titleStyle, this.subtitleStyle, this.lastMessageAtStyle, @@ -33,7 +33,7 @@ class ChannelPreviewTheme with Diagnosticable { final double? indicatorIconSize; /// Copy with theme - ChannelPreviewTheme copyWith({ + ChannelPreviewThemeData copyWith({ TextStyle? titleStyle, TextStyle? subtitleStyle, TextStyle? lastMessageAtStyle, @@ -41,7 +41,7 @@ class ChannelPreviewTheme with Diagnosticable { Color? unreadCounterColor, double? indicatorIconSize, }) => - ChannelPreviewTheme( + ChannelPreviewThemeData( titleStyle: titleStyle ?? this.titleStyle, subtitleStyle: subtitleStyle ?? this.subtitleStyle, lastMessageAtStyle: lastMessageAtStyle ?? this.lastMessageAtStyle, @@ -51,7 +51,7 @@ class ChannelPreviewTheme with Diagnosticable { ); /// Merge with theme - ChannelPreviewTheme merge(ChannelPreviewTheme? other) { + ChannelPreviewThemeData merge(ChannelPreviewThemeData? other) { if (other == null) return this; return copyWith( titleStyle: titleStyle?.merge(other.titleStyle) ?? other.titleStyle, From d8ca465b91a496fa5bf23a53f05291aa02da611f Mon Sep 17 00:00:00 2001 From: groovinchip Date: Mon, 2 Aug 2021 09:24:17 -0400 Subject: [PATCH 27/42] chore: add lerp, == and hashCode to ChannelPreviewTheme --- .../lib/src/theme/channel_preview_theme.dart | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart b/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart index 023c1f0a..18783d02 100644 --- a/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart @@ -50,6 +50,24 @@ class ChannelPreviewThemeData with Diagnosticable { 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; @@ -64,6 +82,27 @@ class ChannelPreviewThemeData with Diagnosticable { ); } + @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); From a06e6075d7f8f626eacd47784b2c062c95815d76 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Mon, 2 Aug 2021 09:38:15 -0400 Subject: [PATCH 28/42] chore: add ChannelPreviewTheme inherited theme and documentation --- .../lib/src/theme/channel_preview_theme.dart | 57 ++++++++++++++++++- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart b/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart index 18783d02..ff9ef70c 100644 --- a/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/channel_preview_theme.dart @@ -1,10 +1,63 @@ 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'; -/// Theme for channel preview +/// 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(); + 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 { - /// Constructor for creating [ChannelPreviewThemeData] + /// Creates a [ChannelPreviewThemeData]. const ChannelPreviewThemeData({ this.titleStyle, this.subtitleStyle, From 5e1eb7a32072f33e4371047b501a678c6e702c38 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Mon, 2 Aug 2021 09:53:39 -0400 Subject: [PATCH 29/42] test: add tests for ChannelPreviewTheme --- .../src/theme/channel_preview_theme_test.dart | 108 ++++++++++++++++++ 1 file changed, 108 insertions(+) create mode 100644 packages/stream_chat_flutter/test/src/theme/channel_preview_theme_test.dart diff --git a/packages/stream_chat_flutter/test/src/theme/channel_preview_theme_test.dart b/packages/stream_chat_flutter/test/src/theme/channel_preview_theme_test.dart new file mode 100644 index 00000000..24ad716b --- /dev/null +++ b/packages/stream_chat_flutter/test/src/theme/channel_preview_theme_test.dart @@ -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(0xffff3842), + avatarTheme: AvatarThemeData( + borderRadius: BorderRadius.circular(20), + constraints: const BoxConstraints.tightFor( + height: 40, + width: 40, + ), + ), + titleStyle: const TextStyle( + color: Color(0xff000000), + fontSize: 14, + fontWeight: FontWeight.bold, + ), + subtitleStyle: const TextStyle( + color: Color(0xff7a7a7a), + fontSize: 12, + ), + lastMessageAtStyle: TextTheme.light().footnote.copyWith( + color: Color(0x80000000).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, +); From 628ef401d4154bc96b63ecad3f8b196898f39da6 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Mon, 2 Aug 2021 10:47:38 -0400 Subject: [PATCH 30/42] chore: update message_theme.dart Includes Diagnosticable, more descriptive field names, lerp, ==, and hashCode --- .../example/lib/tutorial_part_6.dart | 4 +- .../lib/src/attachment/attachment_title.dart | 6 +- .../lib/src/attachment/image_attachment.dart | 4 +- .../lib/src/attachment/video_attachment.dart | 4 +- .../lib/src/deleted_message.dart | 6 +- .../lib/src/image_group.dart | 4 +- .../lib/src/message_actions_modal.dart | 6 +- .../lib/src/message_reactions_modal.dart | 9 +- .../lib/src/message_text.dart | 18 +-- .../lib/src/message_widget.dart | 20 +-- .../lib/src/quoted_message_widget.dart | 6 +- .../lib/src/stream_chat_theme.dart | 36 ++--- .../lib/src/theme/message_theme.dart | 143 ++++++++++++++---- .../test/src/deleted_message_test.dart | 6 +- 14 files changed, 175 insertions(+), 97 deletions(-) diff --git a/packages/stream_chat_flutter/example/lib/tutorial_part_6.dart b/packages/stream_chat_flutter/example/lib/tutorial_part_6.dart index 2cad67f2..b64281cb 100644 --- a/packages/stream_chat_flutter/example/lib/tutorial_part_6.dart +++ b/packages/stream_chat_flutter/example/lib/tutorial_part_6.dart @@ -63,9 +63,9 @@ class MyApp extends StatelessWidget { borderRadius: BorderRadius.circular(8), ), ), - otherMessageTheme: MessageTheme( + otherMessageTheme: MessageThemeData( messageBackgroundColor: colorTheme.textHighEmphasis, - messageText: TextStyle( + messageTextStyle: TextStyle( color: colorTheme.barsBg, ), avatarTheme: AvatarThemeData( diff --git a/packages/stream_chat_flutter/lib/src/attachment/attachment_title.dart b/packages/stream_chat_flutter/lib/src/attachment/attachment_title.dart index d0f45aad..a7d4d2e3 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/attachment_title.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/attachment_title.dart @@ -13,7 +13,7 @@ class AttachmentTitle extends StatelessWidget { }) : super(key: key); /// Theme to apply to text - final MessageTheme messageTheme; + final MessageThemeData messageTheme; /// Attachment data to display final Attachment attachment; @@ -35,7 +35,7 @@ class AttachmentTitle extends StatelessWidget { Text( attachment.title!, overflow: TextOverflow.ellipsis, - style: messageTheme.messageText?.copyWith( + style: messageTheme.messageTextStyle?.copyWith( color: StreamChatTheme.of(context).colorTheme.accentPrimary, fontWeight: FontWeight.bold, ), @@ -51,7 +51,7 @@ class AttachmentTitle extends StatelessWidget { .toList() .reversed .join('.'), - style: messageTheme.messageText, + style: messageTheme.messageTextStyle, ), ], ), diff --git a/packages/stream_chat_flutter/lib/src/attachment/image_attachment.dart b/packages/stream_chat_flutter/lib/src/attachment/image_attachment.dart index f912f282..95229418 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/image_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/image_attachment.dart @@ -28,8 +28,8 @@ class ImageAttachment extends AttachmentWidget { size: size, ); - /// [MessageTheme] for showing image title - final MessageTheme messageTheme; + /// [MessageThemeData] for showing image title + final MessageThemeData messageTheme; /// Flag for showing title final bool showTitle; diff --git a/packages/stream_chat_flutter/lib/src/attachment/video_attachment.dart b/packages/stream_chat_flutter/lib/src/attachment/video_attachment.dart index b976532a..ce4ac804 100644 --- a/packages/stream_chat_flutter/lib/src/attachment/video_attachment.dart +++ b/packages/stream_chat_flutter/lib/src/attachment/video_attachment.dart @@ -25,8 +25,8 @@ class VideoAttachment extends AttachmentWidget { size: size, ); - /// [MessageTheme] for showing title - final MessageTheme messageTheme; + /// [MessageThemeData] for showing title + final MessageThemeData messageTheme; /// Callback when show message is tapped final ShowMessageCallback? onShowMessage; diff --git a/packages/stream_chat_flutter/lib/src/deleted_message.dart b/packages/stream_chat_flutter/lib/src/deleted_message.dart index a973deb7..74673dff 100644 --- a/packages/stream_chat_flutter/lib/src/deleted_message.dart +++ b/packages/stream_chat_flutter/lib/src/deleted_message.dart @@ -15,7 +15,7 @@ class DeletedMessage extends StatelessWidget { }) : super(key: key); /// The theme of the message - final MessageTheme messageTheme; + final MessageThemeData messageTheme; /// The border radius of the message text final BorderRadiusGeometry? borderRadiusGeometry; @@ -51,9 +51,9 @@ class DeletedMessage extends StatelessWidget { ), child: Text( 'Message deleted', - style: messageTheme.messageText?.copyWith( + style: messageTheme.messageTextStyle?.copyWith( fontStyle: FontStyle.italic, - color: messageTheme.createdAt?.color, + color: messageTheme.createdAtStyle?.color, ), ), ), diff --git a/packages/stream_chat_flutter/lib/src/image_group.dart b/packages/stream_chat_flutter/lib/src/image_group.dart index ec50f294..627406d0 100644 --- a/packages/stream_chat_flutter/lib/src/image_group.dart +++ b/packages/stream_chat_flutter/lib/src/image_group.dart @@ -26,8 +26,8 @@ class ImageGroup extends StatelessWidget { /// Message which images are attached to final Message message; - /// [MessageTheme] to apply to message - final MessageTheme messageTheme; + /// [MessageThemeData] to apply to message + final MessageThemeData messageTheme; /// Size of iamges final Size size; diff --git a/packages/stream_chat_flutter/lib/src/message_actions_modal.dart b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart index 11d96e77..2c7e163d 100644 --- a/packages/stream_chat_flutter/lib/src/message_actions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart @@ -50,8 +50,8 @@ class MessageActionsModal extends StatefulWidget { /// Message in focus for actions final Message message; - /// [MessageTheme] for message - final MessageTheme messageTheme; + /// [MessageThemeData] for message + final MessageThemeData messageTheme; /// Flag for showing reactions final bool showReactions; @@ -117,7 +117,7 @@ class _MessageActionsModalState extends State { } } final roughSentenceSize = messageTextLength * - (widget.messageTheme.messageText?.fontSize ?? 1) * + (widget.messageTheme.messageTextStyle?.fontSize ?? 1) * 1.2; final divFactor = widget.message.attachments.isNotEmpty == true ? 1 diff --git a/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart b/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart index 669af376..5be0189a 100644 --- a/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/message_reactions_modal.dart @@ -28,8 +28,8 @@ class MessageReactionsModal extends StatelessWidget { /// Message to display reactions of final Message message; - /// [MessageTheme] to apply to [message] - final MessageTheme messageTheme; + /// [MessageThemeData] to apply to [message] + final MessageThemeData messageTheme; /// Flag to reverse message final bool reverse; @@ -56,8 +56,9 @@ class MessageReactionsModal extends StatelessWidget { messageTextLength = quotedMessageLength; } } - final roughSentenceSize = - messageTextLength * (messageTheme.messageText?.fontSize ?? 1) * 1.2; + final roughSentenceSize = messageTextLength * + (messageTheme.messageTextStyle?.fontSize ?? 1) * + 1.2; final divFactor = message.attachments.isNotEmpty == true ? 1 : (roughSentenceSize == 0 ? 1 : (roughSentenceSize / roughMaxSize)); diff --git a/packages/stream_chat_flutter/lib/src/message_text.dart b/packages/stream_chat_flutter/lib/src/message_text.dart index c11dc2fc..964a32a7 100644 --- a/packages/stream_chat_flutter/lib/src/message_text.dart +++ b/packages/stream_chat_flutter/lib/src/message_text.dart @@ -25,8 +25,8 @@ class MessageText extends StatelessWidget { /// Callback for when link is tapped final void Function(String)? onLinkTap; - /// [MessageTheme] whose text theme is to be applied - final MessageTheme messageTheme; + /// [MessageThemeData] whose text theme is to be applied + final MessageThemeData messageTheme; @override Widget build(BuildContext context) { @@ -64,16 +64,16 @@ class MessageText extends StatelessWidget { styleSheet: MarkdownStyleSheet.fromTheme( themeData.copyWith( textTheme: themeData.textTheme.apply( - bodyColor: messageTheme.messageText?.color, - decoration: messageTheme.messageText?.decoration, - decorationColor: messageTheme.messageText?.decorationColor, - decorationStyle: messageTheme.messageText?.decorationStyle, - fontFamily: messageTheme.messageText?.fontFamily, + bodyColor: messageTheme.messageTextStyle?.color, + decoration: messageTheme.messageTextStyle?.decoration, + decorationColor: messageTheme.messageTextStyle?.decorationColor, + decorationStyle: messageTheme.messageTextStyle?.decorationStyle, + fontFamily: messageTheme.messageTextStyle?.fontFamily, ), ), ).copyWith( - a: messageTheme.messageLinks, - p: messageTheme.messageText, + a: messageTheme.messageLinksStyle, + p: messageTheme.messageTextStyle, ), ); } diff --git a/packages/stream_chat_flutter/lib/src/message_widget.dart b/packages/stream_chat_flutter/lib/src/message_widget.dart index 133b5dc7..d218855d 100644 --- a/packages/stream_chat_flutter/lib/src/message_widget.dart +++ b/packages/stream_chat_flutter/lib/src/message_widget.dart @@ -283,7 +283,7 @@ class MessageWidget extends StatefulWidget { final Message message; /// The message theme - final MessageTheme messageTheme; + final MessageThemeData messageTheme; /// If true the widget will be mirrored final bool reverse; @@ -413,7 +413,7 @@ class MessageWidget extends StatefulWidget { Widget Function(BuildContext, Message)? usernameBuilder, void Function(BuildContext, Message)? onMessageActions, Message? message, - MessageTheme? messageTheme, + MessageThemeData? messageTheme, bool? reverse, ShapeBorder? shape, ShapeBorder? attachmentShape, @@ -888,14 +888,14 @@ class _MessageWidgetState extends State ), InkWell( onTap: widget.onThreadTap != null ? onThreadTap : null, - child: Text(msg, style: widget.messageTheme.replies), + child: Text(msg, style: widget.messageTheme.repliesStyle), ), ], if (showUsername) _buildUsername(usernameKey), if (showTimeStamp) Text( Jiffy(widget.message.createdAt.toLocal()).jm, - style: widget.messageTheme.createdAt, + style: widget.messageTheme.createdAtStyle, ), if (showSendingIndicator) _buildSendingIndicator(), ]); @@ -912,7 +912,7 @@ class _MessageWidgetState extends State Container( margin: EdgeInsets.only( bottom: context.textScaleFactor * - ((widget.messageTheme.replies?.fontSize ?? 1) / 2), + ((widget.messageTheme.repliesStyle?.fontSize ?? 1) / 2), ), child: CustomPaint( size: const Size(16, 32) * context.textScaleFactor, @@ -939,7 +939,7 @@ class _MessageWidgetState extends State Container( margin: EdgeInsets.only( bottom: context.textScaleFactor * - ((widget.messageTheme.replies?.fontSize ?? 1) / 2), + ((widget.messageTheme.repliesStyle?.fontSize ?? 1) / 2), ), child: CustomPaint( size: const Size(16, 32) * context.textScaleFactor, @@ -962,7 +962,7 @@ class _MessageWidgetState extends State widget.message.user!.name, maxLines: 1, key: usernameKey, - style: widget.messageTheme.messageAuthor, + style: widget.messageTheme.messageAuthorStyle, overflow: TextOverflow.ellipsis, ); } @@ -1186,7 +1186,7 @@ class _MessageWidgetState extends State } Widget _buildSendingIndicator() { - final style = widget.messageTheme.createdAt; + final style = widget.messageTheme.createdAtStyle; final message = widget.message; if (hasNonUrlAttachments && @@ -1263,8 +1263,8 @@ class _MessageWidgetState extends State onMentionTap: widget.onMentionTap, messageTheme: isOnlyEmoji ? widget.messageTheme.copyWith( - messageText: - widget.messageTheme.messageText!.copyWith( + messageTextStyle: + widget.messageTheme.messageTextStyle!.copyWith( fontSize: 42, )) : widget.messageTheme, diff --git a/packages/stream_chat_flutter/lib/src/quoted_message_widget.dart b/packages/stream_chat_flutter/lib/src/quoted_message_widget.dart index 5cf53a65..ad3d936a 100644 --- a/packages/stream_chat_flutter/lib/src/quoted_message_widget.dart +++ b/packages/stream_chat_flutter/lib/src/quoted_message_widget.dart @@ -74,7 +74,7 @@ class QuotedMessageWidget extends StatelessWidget { final Message message; /// The message theme - final MessageTheme messageTheme; + final MessageThemeData messageTheme; /// If true the widget will be mirrored final bool reverse; @@ -139,11 +139,11 @@ class QuotedMessageWidget extends StatelessWidget { message: msg, messageTheme: isOnlyEmoji && _containsText ? messageTheme.copyWith( - messageText: messageTheme.messageText?.copyWith( + messageTextStyle: messageTheme.messageTextStyle?.copyWith( fontSize: 32, )) : messageTheme.copyWith( - messageText: messageTheme.messageText?.copyWith( + messageTextStyle: messageTheme.messageTextStyle?.copyWith( fontSize: 12, )), ), diff --git a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart index 7a520f40..f82b916c 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart @@ -50,8 +50,8 @@ class StreamChatThemeData { ChannelListHeaderTheme? channelListHeaderTheme, ChannelPreviewThemeData? channelPreviewTheme, ChannelHeaderThemeData? channelHeaderTheme, - MessageTheme? otherMessageTheme, - MessageTheme? ownMessageTheme, + MessageThemeData? otherMessageTheme, + MessageThemeData? ownMessageTheme, MessageInputThemeData? messageInputTheme, Widget Function(BuildContext, User)? defaultUserImage, IconThemeData? primaryIconTheme, @@ -159,10 +159,10 @@ class StreamChatThemeData { final GalleryFooterThemeData galleryFooterTheme; /// Theme of the current user messages - final MessageTheme ownMessageTheme; + final MessageThemeData ownMessageTheme; /// Theme of other users messages - final MessageTheme otherMessageTheme; + final MessageThemeData otherMessageTheme; /// Theme dedicated to the [MessageInput] widget final MessageInputThemeData messageInputTheme; @@ -195,8 +195,8 @@ class StreamChatThemeData { ColorTheme? colorTheme, ChannelPreviewThemeData? channelPreviewTheme, ChannelHeaderThemeData? channelHeaderTheme, - MessageTheme? ownMessageTheme, - MessageTheme? otherMessageTheme, + MessageThemeData? ownMessageTheme, + MessageThemeData? otherMessageTheme, MessageInputThemeData? messageInputTheme, Widget Function(BuildContext, User)? defaultUserImage, IconThemeData? primaryIconTheme, @@ -324,13 +324,13 @@ class StreamChatThemeData { title: textTheme.headlineBold, ), channelHeaderTheme: channelHeaderTheme, - ownMessageTheme: MessageTheme( - messageAuthor: + ownMessageTheme: MessageThemeData( + messageAuthorStyle: textTheme.footnote.copyWith(color: colorTheme.textLowEmphasis), - messageText: textTheme.body, - createdAt: + messageTextStyle: textTheme.body, + createdAtStyle: textTheme.footnote.copyWith(color: colorTheme.textLowEmphasis), - replies: textTheme.footnoteBold.copyWith(color: accentColor), + repliesStyle: textTheme.footnoteBold.copyWith(color: accentColor), messageBackgroundColor: colorTheme.disabled, reactionsBackgroundColor: colorTheme.barsBg, reactionsBorderColor: colorTheme.borders, @@ -343,21 +343,21 @@ class StreamChatThemeData { width: 32, ), ), - messageLinks: TextStyle( + messageLinksStyle: TextStyle( color: accentColor, ), ), - otherMessageTheme: MessageTheme( + otherMessageTheme: MessageThemeData( reactionsBackgroundColor: colorTheme.disabled, reactionsBorderColor: colorTheme.barsBg, reactionsMaskColor: colorTheme.appBg, - messageText: textTheme.body, - createdAt: + messageTextStyle: textTheme.body, + createdAtStyle: textTheme.footnote.copyWith(color: colorTheme.textLowEmphasis), - messageAuthor: + messageAuthorStyle: textTheme.footnote.copyWith(color: colorTheme.textLowEmphasis), - replies: textTheme.footnoteBold.copyWith(color: accentColor), - messageLinks: TextStyle( + repliesStyle: textTheme.footnoteBold.copyWith(color: accentColor), + messageLinksStyle: TextStyle( color: accentColor, ), messageBackgroundColor: colorTheme.barsBg, diff --git a/packages/stream_chat_flutter/lib/src/theme/message_theme.dart b/packages/stream_chat_flutter/lib/src/theme/message_theme.dart index e9deb1f4..023a2917 100644 --- a/packages/stream_chat_flutter/lib/src/theme/message_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/message_theme.dart @@ -1,37 +1,38 @@ +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 MessageTheme { - /// Constructor into [MessageTheme] - const MessageTheme({ - this.replies, - this.messageText, - this.messageAuthor, - this.messageLinks, +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.createdAt, + this.createdAtStyle, }); /// Text style for message text - final TextStyle? messageText; + final TextStyle? messageTextStyle; /// Text style for message author - final TextStyle? messageAuthor; + final TextStyle? messageAuthorStyle; /// Text style for message links - final TextStyle? messageLinks; + final TextStyle? messageLinksStyle; /// Text style for created at text - final TextStyle? createdAt; + final TextStyle? createdAtStyle; /// Text style for replies - final TextStyle? replies; + final TextStyle? repliesStyle; /// Color for messageBackgroundColor final Color? messageBackgroundColor; @@ -52,12 +53,12 @@ class MessageTheme { final AvatarThemeData? avatarTheme; /// Copy with a theme - MessageTheme copyWith({ - TextStyle? messageText, - TextStyle? messageAuthor, - TextStyle? messageLinks, - TextStyle? createdAt, - TextStyle? replies, + MessageThemeData copyWith({ + TextStyle? messageTextStyle, + TextStyle? messageAuthorStyle, + TextStyle? messageLinksStyle, + TextStyle? createdAtStyle, + TextStyle? repliesStyle, Color? messageBackgroundColor, Color? messageBorderColor, AvatarThemeData? avatarTheme, @@ -65,33 +66,61 @@ class MessageTheme { Color? reactionsBorderColor, Color? reactionsMaskColor, }) => - MessageTheme( - messageText: messageText ?? this.messageText, - messageAuthor: messageAuthor ?? this.messageAuthor, - messageLinks: messageLinks ?? this.messageLinks, - createdAt: createdAt ?? this.createdAt, + 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, - replies: replies ?? this.replies, + 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 - MessageTheme merge(MessageTheme? other) { + MessageThemeData merge(MessageThemeData? other) { if (other == null) return this; return copyWith( - messageText: messageText?.merge(other.messageText) ?? other.messageText, - messageAuthor: - messageAuthor?.merge(other.messageAuthor) ?? other.messageAuthor, - messageLinks: - messageLinks?.merge(other.messageLinks) ?? other.messageLinks, - createdAt: createdAt?.merge(other.createdAt) ?? other.createdAt, - replies: replies?.merge(other.replies) ?? other.replies, + 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, @@ -100,4 +129,52 @@ class MessageTheme { 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)); + } } diff --git a/packages/stream_chat_flutter/test/src/deleted_message_test.dart b/packages/stream_chat_flutter/test/src/deleted_message_test.dart index ac953ee9..0d86e89c 100644 --- a/packages/stream_chat_flutter/test/src/deleted_message_test.dart +++ b/packages/stream_chat_flutter/test/src/deleted_message_test.dart @@ -21,11 +21,11 @@ void main() { client: client, child: const Scaffold( body: DeletedMessage( - messageTheme: MessageTheme( - createdAt: TextStyle( + messageTheme: MessageThemeData( + createdAtStyle: TextStyle( color: Colors.black, ), - messageText: TextStyle(), + messageTextStyle: TextStyle(), ), ), ), From c3d2896071b5392cd99f3976e9784b8a158d6476 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Mon, 2 Aug 2021 10:56:06 -0400 Subject: [PATCH 31/42] test: add tests for MessageTheme --- .../test/src/theme/message_theme_test.dart | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 packages/stream_chat_flutter/test/src/theme/message_theme_test.dart diff --git a/packages/stream_chat_flutter/test/src/theme/message_theme_test.dart b/packages/stream_chat_flutter/test/src/theme/message_theme_test.dart new file mode 100644 index 00000000..5908d864 --- /dev/null +++ b/packages/stream_chat_flutter/test/src/theme/message_theme_test.dart @@ -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, + ), +); From 51e0eb9a132bce35216dfcd187f6ad4e9703e4e0 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Mon, 2 Aug 2021 11:02:55 -0400 Subject: [PATCH 32/42] chore: use ChannelPreviewTheme.of(context) rather than StreamChatTheme.of(context).channelPreviewTheme --- packages/stream_chat_flutter/lib/src/channel_preview.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_chat_flutter/lib/src/channel_preview.dart b/packages/stream_chat_flutter/lib/src/channel_preview.dart index 8a9eb9f1..2929c6f4 100644 --- a/packages/stream_chat_flutter/lib/src/channel_preview.dart +++ b/packages/stream_chat_flutter/lib/src/channel_preview.dart @@ -68,7 +68,7 @@ class ChannelPreview extends StatelessWidget { @override Widget build(BuildContext context) { - final channelPreviewTheme = StreamChatTheme.of(context).channelPreviewTheme; + final channelPreviewTheme = ChannelPreviewTheme.of(context); final streamChatState = StreamChat.of(context); return BetterStreamBuilder( stream: channel.isMutedStream, From 34476db6f44d790f1211196be6f675d4a6aa9d31 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Mon, 2 Aug 2021 11:52:45 -0400 Subject: [PATCH 33/42] chore: update ChannelListHeaderTheme --- .../lib/src/channel_list_header.dart | 22 ++-- .../lib/src/stream_chat_theme.dart | 10 +- .../src/theme/channel_list_header_theme.dart | 108 +++++++++++++++--- 3 files changed, 110 insertions(+), 30 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/channel_list_header.dart b/packages/stream_chat_flutter/lib/src/channel_list_header.dart index ae017090..72145fe4 100644 --- a/packages/stream_chat_flutter/lib/src/channel_list_header.dart +++ b/packages/stream_chat_flutter/lib/src/channel_list_header.dart @@ -45,7 +45,7 @@ typedef TitleBuilder = Widget Function( /// if you don't have it in the widget tree. /// /// The widget components render the ui based on the first ancestor of type -/// [StreamChatTheme] and on its [ChannelListHeaderTheme] property. +/// [StreamChatTheme] and on its [ChannelListHeaderThemeData] property. /// Modify it to change the widget appearance. class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { /// Instantiates a ChannelListHeader @@ -115,6 +115,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { } final chatThemeData = StreamChatTheme.of(context); + final channelListHeaderThemeData = ChannelListHeaderTheme.of(context); return InfoTile( // ignore: avoid_bool_literals_in_conditional_expressions showMessage: showConnectionStateTile ? showStatus : false, @@ -123,7 +124,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { textTheme: Theme.of(context).textTheme, brightness: Theme.of(context).brightness, elevation: 1, - backgroundColor: chatThemeData.channelListHeaderTheme.color, + backgroundColor: channelListHeaderThemeData.color, centerTitle: true, leading: leading ?? Center( @@ -138,10 +139,10 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { } Scaffold.of(context).openDrawer(); }, - borderRadius: chatThemeData - .channelListHeaderTheme.avatarTheme?.borderRadius, - constraints: chatThemeData - .channelListHeaderTheme.avatarTheme?.constraints, + borderRadius: channelListHeaderThemeData + .avatarTheme?.borderRadius, + constraints: channelListHeaderThemeData + .avatarTheme?.constraints, ) : const Offstage(), ), @@ -227,10 +228,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { const SizedBox(width: 10), Text( 'Searching for Network', - style: StreamChatTheme.of(context) - .channelListHeaderTheme - .title - ?.copyWith( + style: ChannelListHeaderTheme.of(context).titleStyle?.copyWith( fontSize: 16, fontWeight: FontWeight.bold, ), @@ -248,7 +246,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { children: [ Text( 'Offline...', - style: chatThemeData.channelListHeaderTheme.title?.copyWith( + style: chatThemeData.channelListHeaderTheme.titleStyle?.copyWith( fontSize: 16, fontWeight: FontWeight.bold, ), @@ -259,7 +257,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { ..openConnection(), child: Text( 'Try Again', - style: chatThemeData.channelListHeaderTheme.title?.copyWith( + style: chatThemeData.channelListHeaderTheme.titleStyle?.copyWith( fontSize: 16, fontWeight: FontWeight.bold, color: chatThemeData.colorTheme.accentPrimary, diff --git a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart index f82b916c..5fe56dbc 100644 --- a/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart +++ b/packages/stream_chat_flutter/lib/src/stream_chat_theme.dart @@ -47,7 +47,7 @@ class StreamChatThemeData { Brightness? brightness, TextTheme? textTheme, ColorTheme? colorTheme, - ChannelListHeaderTheme? channelListHeaderTheme, + ChannelListHeaderThemeData? channelListHeaderTheme, ChannelPreviewThemeData? channelPreviewTheme, ChannelHeaderThemeData? channelHeaderTheme, MessageThemeData? otherMessageTheme, @@ -145,7 +145,7 @@ class StreamChatThemeData { final ChannelPreviewThemeData channelPreviewTheme; /// Theme of the [ChannelListHeader] - final ChannelListHeaderTheme channelListHeaderTheme; + final ChannelListHeaderThemeData channelListHeaderTheme; /// Theme of the chat widgets dedicated to a channel header final ChannelHeaderThemeData channelHeaderTheme; @@ -200,7 +200,7 @@ class StreamChatThemeData { MessageInputThemeData? messageInputTheme, Widget Function(BuildContext, User)? defaultUserImage, IconThemeData? primaryIconTheme, - ChannelListHeaderTheme? channelListHeaderTheme, + ChannelListHeaderThemeData? channelListHeaderTheme, List? reactionIcons, GalleryHeaderThemeData? galleryHeaderTheme, GalleryFooterThemeData? galleryFooterTheme, @@ -312,7 +312,7 @@ class StreamChatThemeData { ), ), channelPreviewTheme: channelPreviewTheme, - channelListHeaderTheme: ChannelListHeaderTheme( + channelListHeaderTheme: ChannelListHeaderThemeData( avatarTheme: AvatarThemeData( borderRadius: BorderRadius.circular(20), constraints: const BoxConstraints.tightFor( @@ -321,7 +321,7 @@ class StreamChatThemeData { ), ), color: colorTheme.barsBg, - title: textTheme.headlineBold, + titleStyle: textTheme.headlineBold, ), channelHeaderTheme: channelHeaderTheme, ownMessageTheme: MessageThemeData( diff --git a/packages/stream_chat_flutter/lib/src/theme/channel_list_header_theme.dart b/packages/stream_chat_flutter/lib/src/theme/channel_list_header_theme.dart index 339361b9..3846232e 100644 --- a/packages/stream_chat_flutter/lib/src/theme/channel_list_header_theme.dart +++ b/packages/stream_chat_flutter/lib/src/theme/channel_list_header_theme.dart @@ -1,17 +1,63 @@ +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'; -/// Theme dedicated to the [ChannelListHeader] -class ChannelListHeaderTheme { - /// Returns a new [ChannelListHeaderTheme] +/// 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({ - this.title, + 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(); + 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? title; + final TextStyle? titleStyle; /// Theme dedicated to the userAvatar final AvatarThemeData? avatarTheme; @@ -19,25 +65,61 @@ class ChannelListHeaderTheme { /// Background color of the appbar final Color? color; - /// Returns a new [ChannelListHeaderTheme] replacing some of its properties - ChannelListHeaderTheme copyWith({ - TextStyle? title, + /// Returns a new [ChannelListHeaderThemeData] replacing some of its + /// properties + ChannelListHeaderThemeData copyWith({ + TextStyle? titleStyle, AvatarThemeData? avatarTheme, Color? color, }) => - ChannelListHeaderTheme( - title: title ?? this.title, + ChannelListHeaderThemeData( + titleStyle: titleStyle ?? this.titleStyle, avatarTheme: avatarTheme ?? this.avatarTheme, color: color ?? this.color, ); - /// Merges [this] [ChannelListHeaderTheme] with the [other] - ChannelListHeaderTheme merge(ChannelListHeaderTheme? other) { + /// 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( - title: title?.merge(other.title) ?? other.title, + 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)); + } } From 26b2bf3f18db0ac819c346eba211c8c7baf810a8 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Mon, 2 Aug 2021 12:02:18 -0400 Subject: [PATCH 34/42] test: add test for ChannelListHeaderTheme --- .../theme/channel_list_header_theme_test.dart | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 packages/stream_chat_flutter/test/src/theme/channel_list_header_theme_test.dart diff --git a/packages/stream_chat_flutter/test/src/theme/channel_list_header_theme_test.dart b/packages/stream_chat_flutter/test/src/theme/channel_list_header_theme_test.dart new file mode 100644 index 00000000..aa378f3a --- /dev/null +++ b/packages/stream_chat_flutter/test/src/theme/channel_list_header_theme_test.dart @@ -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, +); From d5f38fa54561c99f43ee58f94c9c57b6c8f81c10 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Mon, 2 Aug 2021 12:58:31 -0400 Subject: [PATCH 35/42] test: fixed failing test in channel_preview_theme_test.dart --- .../test/src/theme/channel_preview_theme_test.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/stream_chat_flutter/test/src/theme/channel_preview_theme_test.dart b/packages/stream_chat_flutter/test/src/theme/channel_preview_theme_test.dart index 24ad716b..3be39952 100644 --- a/packages/stream_chat_flutter/test/src/theme/channel_preview_theme_test.dart +++ b/packages/stream_chat_flutter/test/src/theme/channel_preview_theme_test.dart @@ -65,7 +65,7 @@ final _channelPreviewThemeControl = ChannelPreviewThemeData( ); final _channelPreviewThemeControlMidLerp = ChannelPreviewThemeData( - unreadCounterColor: const Color(0xffff3842), + unreadCounterColor: const Color(0xffff3742), avatarTheme: AvatarThemeData( borderRadius: BorderRadius.circular(20), constraints: const BoxConstraints.tightFor( @@ -74,7 +74,7 @@ final _channelPreviewThemeControlMidLerp = ChannelPreviewThemeData( ), ), titleStyle: const TextStyle( - color: Color(0xff000000), + color: Color(0xff7f7f7f), fontSize: 14, fontWeight: FontWeight.bold, ), @@ -83,7 +83,7 @@ final _channelPreviewThemeControlMidLerp = ChannelPreviewThemeData( fontSize: 12, ), lastMessageAtStyle: TextTheme.light().footnote.copyWith( - color: Color(0x80000000).withOpacity(.5), + color: const Color(0x807f7f7f).withOpacity(.5), ), indicatorIconSize: 16, ); From 6e6ce8c7f3d57ed562de503e3865678185be6934 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Mon, 2 Aug 2021 14:44:36 -0400 Subject: [PATCH 36/42] test: fix mid-lerp test in channel_header_theme_test.dart --- .../test/src/theme/channel_header_theme_test.dart | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/stream_chat_flutter/test/src/theme/channel_header_theme_test.dart b/packages/stream_chat_flutter/test/src/theme/channel_header_theme_test.dart index de9803b7..475b1084 100644 --- a/packages/stream_chat_flutter/test/src/theme/channel_header_theme_test.dart +++ b/packages/stream_chat_flutter/test/src/theme/channel_header_theme_test.dart @@ -26,7 +26,7 @@ void main() { expect( const ChannelHeaderThemeData() .lerp(_channelThemeControl, _channelThemeControlDark, 0.5), - _channelThemeControlDark); + _channelThemeControlMidLerp); }); test( @@ -70,10 +70,14 @@ final _channelThemeControlMidLerp = ChannelHeaderThemeData( width: 40, ), ), - color: ColorTheme.light().barsBg, - titleStyle: TextTheme.light().headlineBold, + color: const Color(0xff101418), + titleStyle: const TextStyle( + color: Color(0xffffffff), + fontWeight: FontWeight.bold, + fontSize: 16, + ), subtitleStyle: TextTheme.light().footnote.copyWith( - color: const Color(0xff7A7A7A), + color: const Color(0xff7a7a7a), ), ); From 55cb5ead04703670d79344ea087528aace454308 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Wed, 4 Aug 2021 11:34:30 -0400 Subject: [PATCH 37/42] chore: use ChannelPreviewTheme.of(context) in message_search_item.dart --- .../stream_chat_flutter/lib/src/message_search_item.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/message_search_item.dart b/packages/stream_chat_flutter/lib/src/message_search_item.dart index 46413706..44b97c83 100644 --- a/packages/stream_chat_flutter/lib/src/message_search_item.dart +++ b/packages/stream_chat_flutter/lib/src/message_search_item.dart @@ -36,7 +36,7 @@ class MessageSearchItem extends StatelessWidget { final channel = getMessageResponse.channel; final channelName = channel?.extraData['name']; final user = message.user!; - final chatThemeData = StreamChatTheme.of(context); + final channelPreviewTheme = ChannelPreviewTheme.of(context); return ListTile( onTap: onTap, leading: UserAvatar( @@ -53,18 +53,18 @@ class MessageSearchItem extends StatelessWidget { user.id == StreamChat.of(context).currentUser?.id ? context.translations.youText : user.name, - style: chatThemeData.channelPreviewTheme.titleStyle, + style: channelPreviewTheme.titleStyle, ), if (channelName != null) ...[ Text( ' ${context.translations.inText} ', - style: chatThemeData.channelPreviewTheme.titleStyle?.copyWith( + style: channelPreviewTheme.titleStyle?.copyWith( fontWeight: FontWeight.normal, ), ), Text( channelName as String, - style: chatThemeData.channelPreviewTheme.titleStyle, + style: channelPreviewTheme.titleStyle, ), ], ], From 70c77e70e5184235b68da244e3ddb5b337d1b395 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Wed, 4 Aug 2021 11:36:58 -0400 Subject: [PATCH 38/42] chore: use ChannelHeaderTheme.of(context) in thread_header.dart --- .../stream_chat_flutter/lib/src/thread_header.dart | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/thread_header.dart b/packages/stream_chat_flutter/lib/src/thread_header.dart index d7c6f002..66b6b8be 100644 --- a/packages/stream_chat_flutter/lib/src/thread_header.dart +++ b/packages/stream_chat_flutter/lib/src/thread_header.dart @@ -104,7 +104,7 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { @override Widget build(BuildContext context) { - final chatThemeData = StreamChatTheme.of(context); + final channelHeaderTheme = ChannelHeaderTheme.of(context); final defaultSubtitle = subtitle ?? Row( @@ -113,11 +113,11 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { children: [ Text( '${context.translations.withText} ', - style: chatThemeData.channelHeaderTheme.subtitleStyle, + style: channelHeaderTheme.subtitleStyle, ), Flexible( child: ChannelName( - textStyle: chatThemeData.channelHeaderTheme.subtitleStyle, + textStyle: channelHeaderTheme.subtitleStyle, ), ), ], @@ -136,7 +136,7 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { showUnreads: true, ) : const SizedBox()), - backgroundColor: chatThemeData.channelHeaderTheme.color, + backgroundColor: channelHeaderTheme.color, centerTitle: true, actions: actions, title: InkWell( @@ -150,14 +150,14 @@ class ThreadHeader extends StatelessWidget implements PreferredSizeWidget { title ?? Text( context.translations.threadReplyLabel, - style: chatThemeData.channelHeaderTheme.titleStyle, + style: channelHeaderTheme.titleStyle, ), const SizedBox(height: 2), if (showTypingIndicator) TypingIndicator( alignment: Alignment.center, channel: StreamChannel.of(context).channel, - style: chatThemeData.channelHeaderTheme.subtitleStyle, + style: channelHeaderTheme.subtitleStyle, parentId: parent.id, alternativeWidget: defaultSubtitle, ) From f0cf4fd6dbae98f89650b93953efc04418e0aa2b Mon Sep 17 00:00:00 2001 From: groovinchip Date: Wed, 4 Aug 2021 11:40:10 -0400 Subject: [PATCH 39/42] chore: use ChannelPreviewTheme.of(context) in channel_bottom_sheet.dart --- .../stream_chat_flutter/lib/src/channel_bottom_sheet.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart b/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart index 1442aac8..5723234d 100644 --- a/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart +++ b/packages/stream_chat_flutter/lib/src/channel_bottom_sheet.dart @@ -19,6 +19,7 @@ class _ChannelBottomSheetState extends State { bool _showActions = true; late StreamChannelState _streamChannelState; + late ChannelPreviewThemeData _channelPreviewThemeData; late StreamChatThemeData _streamChatThemeData; late StreamChatState _streamChatState; @@ -64,8 +65,7 @@ class _ChannelBottomSheetState extends State { child: ChannelInfo( showTypingIndicator: false, channel: _streamChannelState.channel, - textStyle: - _streamChatThemeData.channelPreviewTheme.subtitleStyle, + textStyle: _channelPreviewThemeData.subtitleStyle, ), ), const SizedBox( @@ -213,6 +213,7 @@ class _ChannelBottomSheetState extends State { void didChangeDependencies() { _streamChannelState = StreamChannel.of(context); _streamChatThemeData = StreamChatTheme.of(context); + _channelPreviewThemeData = ChannelPreviewTheme.of(context); _streamChatState = StreamChat.of(context); super.didChangeDependencies(); } From 8a4632e6e23d24b0208dbe8998c27435d2d279c0 Mon Sep 17 00:00:00 2001 From: groovinchip Date: Wed, 4 Aug 2021 12:03:37 -0400 Subject: [PATCH 40/42] chore: address PR feedback --- .../example/lib/tutorial_part_3.dart | 5 +---- .../lib/src/channel_header.dart | 18 ++++++++---------- .../lib/src/channel_info.dart | 2 +- .../lib/src/channel_list_header.dart | 5 +++-- .../lib/src/channel_preview.dart | 10 ++++------ .../lib/src/full_screen_media.dart | 4 +--- .../lib/src/message_actions_modal.dart | 3 +-- .../lib/src/message_list_view.dart | 2 +- .../lib/src/message_search_item.dart | 6 +++--- 9 files changed, 23 insertions(+), 32 deletions(-) diff --git a/packages/stream_chat_flutter/example/lib/tutorial_part_3.dart b/packages/stream_chat_flutter/example/lib/tutorial_part_3.dart index a6e80b57..824c0efa 100644 --- a/packages/stream_chat_flutter/example/lib/tutorial_part_3.dart +++ b/packages/stream_chat_flutter/example/lib/tutorial_part_3.dart @@ -118,10 +118,7 @@ class ChannelListPage extends StatelessWidget { channel: channel, ), title: ChannelName( - textStyle: StreamChatTheme.of(context) - .channelPreviewTheme - .titleStyle! - .copyWith( + textStyle: ChannelPreviewTheme.of(context).titleStyle!.copyWith( color: StreamChatTheme.of(context) .colorTheme .textHighEmphasis diff --git a/packages/stream_chat_flutter/lib/src/channel_header.dart b/packages/stream_chat_flutter/lib/src/channel_header.dart index 26418a91..11dfc95a 100644 --- a/packages/stream_chat_flutter/lib/src/channel_header.dart +++ b/packages/stream_chat_flutter/lib/src/channel_header.dart @@ -105,7 +105,7 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { @override Widget build(BuildContext context) { final channel = StreamChannel.of(context).channel; - final chatThemeData = StreamChatTheme.of(context); + final channelHeaderTheme = ChannelHeaderTheme.of(context); final leadingWidget = leading ?? (showBackButton @@ -141,17 +141,17 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { brightness: Theme.of(context).brightness, elevation: 1, leading: leadingWidget, - backgroundColor: chatThemeData.channelHeaderTheme.color, + backgroundColor: channelHeaderTheme.color, actions: actions ?? [ Padding( padding: const EdgeInsets.only(right: 10), child: Center( child: ChannelAvatar( - borderRadius: chatThemeData - .channelHeaderTheme.avatarTheme?.borderRadius, - constraints: chatThemeData - .channelHeaderTheme.avatarTheme?.constraints, + borderRadius: + channelHeaderTheme.avatarTheme?.borderRadius, + constraints: + channelHeaderTheme.avatarTheme?.constraints, onTap: onImageTap, ), ), @@ -168,16 +168,14 @@ class ChannelHeader extends StatelessWidget implements PreferredSizeWidget { children: [ title ?? ChannelName( - textStyle: - chatThemeData.channelHeaderTheme.titleStyle, + textStyle: channelHeaderTheme.titleStyle, ), const SizedBox(height: 2), subtitle ?? ChannelInfo( showTypingIndicator: showTypingIndicator, channel: channel, - textStyle: - chatThemeData.channelHeaderTheme.subtitleStyle, + textStyle: channelHeaderTheme.subtitleStyle, ), ], ), diff --git a/packages/stream_chat_flutter/lib/src/channel_info.dart b/packages/stream_chat_flutter/lib/src/channel_info.dart index e5c2f635..de9d74b9 100644 --- a/packages/stream_chat_flutter/lib/src/channel_info.dart +++ b/packages/stream_chat_flutter/lib/src/channel_info.dart @@ -65,7 +65,7 @@ class ChannelInfo extends StatelessWidget { } alternativeWidget = Text( text, - style: StreamChatTheme.of(context).channelHeaderTheme.subtitleStyle, + style: ChannelHeaderTheme.of(context).subtitleStyle, ); } else { final userId = StreamChat.of(context).currentUser?.id; diff --git a/packages/stream_chat_flutter/lib/src/channel_list_header.dart b/packages/stream_chat_flutter/lib/src/channel_list_header.dart index 5832f3ba..692db477 100644 --- a/packages/stream_chat_flutter/lib/src/channel_list_header.dart +++ b/packages/stream_chat_flutter/lib/src/channel_list_header.dart @@ -241,12 +241,13 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { StreamChatClient client, ) { final chatThemeData = StreamChatTheme.of(context); + final channelListHeaderTheme = ChannelListHeaderTheme.of(context); return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( context.translations.offlineLabel, - style: chatThemeData.channelListHeaderTheme.titleStyle?.copyWith( + style: channelListHeaderTheme.titleStyle?.copyWith( fontSize: 16, fontWeight: FontWeight.bold, ), @@ -257,7 +258,7 @@ class ChannelListHeader extends StatelessWidget implements PreferredSizeWidget { ..openConnection(), child: Text( context.translations.tryAgainLabel, - style: chatThemeData.channelListHeaderTheme.titleStyle?.copyWith( + style: channelListHeaderTheme.titleStyle?.copyWith( fontSize: 16, fontWeight: FontWeight.bold, color: chatThemeData.colorTheme.accentPrimary, diff --git a/packages/stream_chat_flutter/lib/src/channel_preview.dart b/packages/stream_chat_flutter/lib/src/channel_preview.dart index 3127bcbb..6aa7684e 100644 --- a/packages/stream_chat_flutter/lib/src/channel_preview.dart +++ b/packages/stream_chat_flutter/lib/src/channel_preview.dart @@ -183,15 +183,13 @@ class ChannelPreview extends StatelessWidget { return Text( stringDate, - style: StreamChatTheme.of(context) - .channelPreviewTheme - .lastMessageAtStyle, + style: ChannelPreviewTheme.of(context).lastMessageAtStyle, ); }, ); Widget _buildSubtitle(BuildContext context) { - final chatThemeData = StreamChatTheme.of(context); + final channelPreviewTheme = ChannelPreviewTheme.of(context); if (channel.isMuted) { return Row( crossAxisAlignment: CrossAxisAlignment.end, @@ -201,7 +199,7 @@ class ChannelPreview extends StatelessWidget { ), Text( ' ${context.translations.channelIsMutedText}', - style: chatThemeData.channelPreviewTheme.subtitleStyle, + style: channelPreviewTheme.subtitleStyle, ), ], ); @@ -209,7 +207,7 @@ class ChannelPreview extends StatelessWidget { return TypingIndicator( channel: channel, alternativeWidget: _buildLastMessage(context), - style: chatThemeData.channelPreviewTheme.subtitleStyle, + style: channelPreviewTheme.subtitleStyle, ); } diff --git a/packages/stream_chat_flutter/lib/src/full_screen_media.dart b/packages/stream_chat_flutter/lib/src/full_screen_media.dart index 63b77d16..bef2a531 100644 --- a/packages/stream_chat_flutter/lib/src/full_screen_media.dart +++ b/packages/stream_chat_flutter/lib/src/full_screen_media.dart @@ -124,9 +124,7 @@ class _FullScreenMediaState extends State ), backgroundDecoration: BoxDecoration( color: ColorTween( - begin: StreamChatTheme.of(context) - .channelHeaderTheme - .color, + begin: ChannelHeaderTheme.of(context).color, end: Colors.black, ).lerp(_controller.value), ), diff --git a/packages/stream_chat_flutter/lib/src/message_actions_modal.dart b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart index f1fe967b..387e31a1 100644 --- a/packages/stream_chat_flutter/lib/src/message_actions_modal.dart +++ b/packages/stream_chat_flutter/lib/src/message_actions_modal.dart @@ -566,8 +566,7 @@ class _MessageActionsModalState extends State { elevation: 2, clipBehavior: Clip.hardEdge, isScrollControlled: true, - backgroundColor: - streamChatThemeData.messageInputTheme.inputBackgroundColor, + backgroundColor: MessageInputTheme.of(context).inputBackgroundColor, shape: const RoundedRectangleBorder( borderRadius: BorderRadius.only( topLeft: Radius.circular(16), diff --git a/packages/stream_chat_flutter/lib/src/message_list_view.dart b/packages/stream_chat_flutter/lib/src/message_list_view.dart index f6f9c309..a3830966 100644 --- a/packages/stream_chat_flutter/lib/src/message_list_view.dart +++ b/packages/stream_chat_flutter/lib/src/message_list_view.dart @@ -629,7 +629,7 @@ class _MessageListViewState extends State { child: Text( context.translations.threadSeparatorText(replyCount), textAlign: TextAlign.center, - style: _streamTheme.channelHeaderTheme.subtitleStyle, + style: ChannelHeaderTheme.of(context).subtitleStyle, ), ), ); diff --git a/packages/stream_chat_flutter/lib/src/message_search_item.dart b/packages/stream_chat_flutter/lib/src/message_search_item.dart index 44b97c83..ab41532c 100644 --- a/packages/stream_chat_flutter/lib/src/message_search_item.dart +++ b/packages/stream_chat_flutter/lib/src/message_search_item.dart @@ -122,18 +122,18 @@ class MessageSearchItem extends StatelessWidget { text = parts.join(' '); } - final chatThemeData = StreamChatTheme.of(context); + final channelPreviewTheme = ChannelPreviewTheme.of(context); return Text.rich( _getDisplayText( text!, message.mentionedUsers, message.attachments, - chatThemeData.channelPreviewTheme.subtitleStyle?.copyWith( + channelPreviewTheme.subtitleStyle?.copyWith( fontStyle: (message.isSystem || message.isDeleted) ? FontStyle.italic : FontStyle.normal, ), - chatThemeData.channelPreviewTheme.subtitleStyle?.copyWith( + channelPreviewTheme.subtitleStyle?.copyWith( fontStyle: (message.isSystem || message.isDeleted) ? FontStyle.italic : FontStyle.normal, From 8de0eab7cb6060067fcb7821401ece1c17b3748d Mon Sep 17 00:00:00 2001 From: groovinchip Date: Wed, 4 Aug 2021 12:24:56 -0400 Subject: [PATCH 41/42] chore: update CHANGELOG.md --- packages/stream_chat_flutter/CHANGELOG.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/stream_chat_flutter/CHANGELOG.md b/packages/stream_chat_flutter/CHANGELOG.md index 81e6235e..efac9508 100644 --- a/packages/stream_chat_flutter/CHANGELOG.md +++ b/packages/stream_chat_flutter/CHANGELOG.md @@ -1,3 +1,21 @@ +## Upcoming + +🔄 Changed + +Theming has been upgraded! Most theme classes now have `InheritedTheme` classes +associated with them, and have been upgraded with some goodies like `lerp` functions. +Here's the full naming breakdown: +* `AvatarTheme` is now `AvatarThemeData` +* `ChannelHeaderTheme` is now `ChannelHeaderThemeData` +* `ChannelListHeaderTheme` is now `ChannelListHeaderThemeData` +* `ChannelListViewTheme` is now `ChannelListViewThemeData` +* `ChannelPreviewTheme` is now `ChannelPreviewThemeData` +* `MessageInputTheme` is now `MessageInputThemeData` +* `MessageListViewTheme` is now `MessageListViewTheme` +* `MessageSearchListViewTheme` is now `MessageSearchListViewThemeData` +* `MessageTheme` is now `MessageThemeData` +* `UserListViewTheme` is now `UserListViewThemeData` + ## 2.1.2 🐞 Fixed @@ -531,6 +549,7 @@ Widget build(BuildContext context) { }, home: ChannelListPage(), ); +} ``` - Fix reaction bubble going below previous message on iOS From 1f48e571603af9e388c205b1739d70862b51d60e Mon Sep 17 00:00:00 2001 From: Sahil Kumar Date: Thu, 5 Aug 2021 13:06:11 +0530 Subject: [PATCH 42/42] chore(ui): address PR feedback Signed-off-by: xsahil03x --- .../stream_chat_flutter/lib/src/channel_preview.dart | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/stream_chat_flutter/lib/src/channel_preview.dart b/packages/stream_chat_flutter/lib/src/channel_preview.dart index 6aa7684e..333ee886 100644 --- a/packages/stream_chat_flutter/lib/src/channel_preview.dart +++ b/packages/stream_chat_flutter/lib/src/channel_preview.dart @@ -242,20 +242,19 @@ class ChannelPreview extends StatelessWidget { text = parts.join(' '); - final chatThemeData = StreamChatTheme.of(context); + final channelPreviewTheme = ChannelPreviewTheme.of(context); return Text.rich( _getDisplayText( text, lastMessage.mentionedUsers, lastMessage.attachments, - chatThemeData.channelPreviewTheme.subtitleStyle?.copyWith( - color: - chatThemeData.channelPreviewTheme.subtitleStyle?.color, + channelPreviewTheme.subtitleStyle?.copyWith( + color: channelPreviewTheme.subtitleStyle?.color, fontStyle: (lastMessage.isSystem || lastMessage.isDeleted) ? FontStyle.italic : FontStyle.normal), - chatThemeData.channelPreviewTheme.subtitleStyle?.copyWith( - color: chatThemeData.channelPreviewTheme.subtitleStyle?.color, + channelPreviewTheme.subtitleStyle?.copyWith( + color: channelPreviewTheme.subtitleStyle?.color, fontStyle: (lastMessage.isSystem || lastMessage.isDeleted) ? FontStyle.italic : FontStyle.normal,