From c783013a674825cea282912854a9bd22991d604c Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Fri, 13 Feb 2026 17:31:26 +0100 Subject: [PATCH 1/8] Improved media and file attachments --- ...essage_composer_attachment_media_file.dart | 2 +- .../lib/src/components.dart | 1 + ...dia_badge.dart => stream_media_badge.dart} | 26 +++---- .../lib/src/components/message_composer.dart | 1 + .../message_composer_attachment_file.dart | 74 +++++++++++++++++++ ...essage_composer_attachment_media_file.dart | 51 ++++++++++--- .../message_composer_input.dart | 9 ++- 7 files changed, 137 insertions(+), 27 deletions(-) rename packages/stream_core_flutter/lib/src/components/badge/{media_badge.dart => stream_media_badge.dart} (62%) create mode 100644 packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_file.dart diff --git a/apps/design_system_gallery/lib/components/message_composer/message_composer_attachment_media_file.dart b/apps/design_system_gallery/lib/components/message_composer/message_composer_attachment_media_file.dart index 5698d92..17de6a6 100644 --- a/apps/design_system_gallery/lib/components/message_composer/message_composer_attachment_media_file.dart +++ b/apps/design_system_gallery/lib/components/message_composer/message_composer_attachment_media_file.dart @@ -13,7 +13,7 @@ import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; ) Widget buildMessageComposerAttachmentMediaFilePlayground(BuildContext context) { return Center( - child: MessageComposerAttachmentMediaFile( + child: MessageComposerAttachmentMediaFile.image( image: const AssetImage('assets/attachment_image.png'), onRemovePressed: () {}, ), diff --git a/packages/stream_core_flutter/lib/src/components.dart b/packages/stream_core_flutter/lib/src/components.dart index 46cb141..fec8d66 100644 --- a/packages/stream_core_flutter/lib/src/components.dart +++ b/packages/stream_core_flutter/lib/src/components.dart @@ -4,6 +4,7 @@ export 'components/avatar/stream_avatar.dart' hide DefaultStreamAvatar; export 'components/avatar/stream_avatar_group.dart' hide DefaultStreamAvatarGroup; export 'components/avatar/stream_avatar_stack.dart' hide DefaultStreamAvatarStack; export 'components/badge/stream_badge_count.dart' hide DefaultStreamBadgeCount; +export 'components/badge/stream_media_badge.dart'; export 'components/badge/stream_online_indicator.dart' hide DefaultStreamOnlineIndicator; export 'components/buttons/stream_button.dart' hide DefaultStreamButton; export 'components/buttons/stream_emoji_button.dart' hide DefaultStreamEmojiButton; diff --git a/packages/stream_core_flutter/lib/src/components/badge/media_badge.dart b/packages/stream_core_flutter/lib/src/components/badge/stream_media_badge.dart similarity index 62% rename from packages/stream_core_flutter/lib/src/components/badge/media_badge.dart rename to packages/stream_core_flutter/lib/src/components/badge/stream_media_badge.dart index 62f47f7..b522606 100644 --- a/packages/stream_core_flutter/lib/src/components/badge/media_badge.dart +++ b/packages/stream_core_flutter/lib/src/components/badge/stream_media_badge.dart @@ -2,12 +2,8 @@ import 'package:flutter/widgets.dart'; import '../../../stream_core_flutter.dart'; -class MediaBadge extends StatelessWidget { - const MediaBadge({ - super.key, - required this.type, - required this.duration, - }); +class StreamMediaBadge extends StatelessWidget { + const StreamMediaBadge({super.key, required this.type, this.duration}); final MediaBadgeType type; final Duration? duration; @@ -17,13 +13,14 @@ class MediaBadge extends StatelessWidget { return Container( decoration: BoxDecoration( color: context.streamColorScheme.backgroundInverse, - shape: BoxShape.circle, + borderRadius: BorderRadius.all(context.streamRadius.max), ), padding: EdgeInsets.symmetric( horizontal: context.streamSpacing.xs, vertical: context.streamSpacing.xxs, ), - child: Column( + child: Row( + mainAxisSize: MainAxisSize.min, children: [ Icon( switch (type) { @@ -31,10 +28,14 @@ class MediaBadge extends StatelessWidget { MediaBadgeType.audio => context.streamIcons.microphoneSolid, }, size: 12, - color: context.streamColorScheme.textPrimary, + color: context.streamColorScheme.textOnDark, ), - if (duration case final duration?) Text(duration.toReadableString()), + if (duration case final duration?) + Text( + duration.toReadableString(), + style: context.streamTextTheme.numericMd.copyWith(color: context.streamColorScheme.textOnDark), + ), ], ), ); @@ -53,7 +54,4 @@ extension on Duration { } } -enum MediaBadgeType { - video, - audio, -} +enum MediaBadgeType { video, audio } diff --git a/packages/stream_core_flutter/lib/src/components/message_composer.dart b/packages/stream_core_flutter/lib/src/components/message_composer.dart index 998a193..5a57f31 100644 --- a/packages/stream_core_flutter/lib/src/components/message_composer.dart +++ b/packages/stream_core_flutter/lib/src/components/message_composer.dart @@ -1,3 +1,4 @@ +export 'message_composer/attachment/message_composer_attachment_file.dart'; export 'message_composer/attachment/message_composer_attachment_link_preview.dart'; export 'message_composer/attachment/message_composer_attachment_media_file.dart'; export 'message_composer/attachment/message_composer_attachment_reply.dart'; diff --git a/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_file.dart b/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_file.dart new file mode 100644 index 0000000..daa7c78 --- /dev/null +++ b/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_file.dart @@ -0,0 +1,74 @@ +import 'package:flutter/widgets.dart'; + +import '../../../../stream_core_flutter.dart'; +import '../../controls/remove_control.dart'; + +class MessageComposerAttachmentFile extends StatelessWidget { + const MessageComposerAttachmentFile({ + super.key, + this.title, + this.fileTypeIcon, + this.subtitle, + this.onRemovePressed, + }); + + final StreamFileTypeIcon? fileTypeIcon; + final String? title; + final Widget? subtitle; + final VoidCallback? onRemovePressed; + + @override + Widget build(BuildContext context) { + final messageTheme = context.streamMessageTheme.mergeWithDefaults(context); + final textColor = context.streamColorScheme.textPrimary; + + final titleStyle = context.streamTextTheme.captionEmphasis.copyWith(color: textColor); + + final spacing = context.streamSpacing; + return Stack( + children: [ + Container( + margin: EdgeInsets.all(spacing.xxs), + padding: EdgeInsets.fromLTRB(spacing.md, spacing.md, spacing.sm, spacing.md), + foregroundDecoration: BoxDecoration( + borderRadius: BorderRadius.all(context.streamRadius.lg), + border: Border.all( + color: context.streamColorScheme.borderDefault, + ), + ), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(context.streamRadius.lg), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + ?fileTypeIcon, + SizedBox(width: spacing.xs), + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (title case final title?) + Text( + title, + style: titleStyle, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ?subtitle, + ], + ), + ), + ], + ), + ), + if (onRemovePressed case final VoidCallback onRemovePressed?) + Align( + alignment: Alignment.topRight, + child: RemoveControl(onPressed: onRemovePressed), + ), + ], + ); + } +} diff --git a/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_media_file.dart b/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_media_file.dart index 9c4a577..259c3c7 100644 --- a/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_media_file.dart +++ b/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_media_file.dart @@ -4,10 +4,30 @@ import '../../../../stream_core_flutter.dart'; import '../../controls/remove_control.dart'; class MessageComposerAttachmentMediaFile extends StatelessWidget { - const MessageComposerAttachmentMediaFile({super.key, required this.image, required this.onRemovePressed}); + const MessageComposerAttachmentMediaFile({ + super.key, + required this.child, + this.onRemovePressed, + this.mediaBadge, + }); - final ImageProvider image; - final VoidCallback onRemovePressed; + MessageComposerAttachmentMediaFile.image({ + super.key, + required ImageProvider image, + required this.onRemovePressed, + ImageFrameBuilder? frameBuilder, + ImageErrorWidgetBuilder? errorBuilder, + this.mediaBadge, + }) : child = Image( + image: image, + frameBuilder: frameBuilder, + errorBuilder: errorBuilder, + fit: BoxFit.cover, + ); + + final Widget child; + final Widget? mediaBadge; + final VoidCallback? onRemovePressed; @override Widget build(BuildContext context) { @@ -19,19 +39,32 @@ class MessageComposerAttachmentMediaFile extends StatelessWidget { Padding( padding: EdgeInsets.all(context.streamSpacing.xxs), child: Container( - decoration: BoxDecoration( + clipBehavior: Clip.antiAlias, + foregroundDecoration: BoxDecoration( borderRadius: BorderRadius.all(context.streamRadius.lg), border: Border.all( color: context.streamColorScheme.borderDefault.withAlpha(25), ), - image: DecorationImage(image: image, fit: BoxFit.cover), ), + decoration: BoxDecoration( + borderRadius: BorderRadius.all(context.streamRadius.lg), + ), + child: child, ), ), - Align( - alignment: Alignment.topRight, - child: RemoveControl(onPressed: onRemovePressed), - ), + if (onRemovePressed case final VoidCallback onRemovePressed?) + Align( + alignment: Alignment.topRight, + child: RemoveControl(onPressed: onRemovePressed), + ), + if (mediaBadge case final Widget mediaBadge?) + Align( + alignment: Alignment.bottomLeft, + child: Padding( + padding: EdgeInsets.all(context.streamSpacing.xs), + child: mediaBadge, + ), + ), ], ), ); diff --git a/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input.dart b/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input.dart index 7fb96cb..756d0cc 100644 --- a/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input.dart +++ b/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input.dart @@ -24,13 +24,16 @@ class StreamMessageComposerInput extends StatelessWidget { @override Widget build(BuildContext context) { - return DecoratedBox( - decoration: BoxDecoration( - color: context.streamColorScheme.backgroundElevation1, + return Container( + foregroundDecoration: BoxDecoration( borderRadius: BorderRadius.all(context.streamRadius.xxxl), border: Border.all( color: context.streamColorScheme.borderDefault, ), + ), + decoration: BoxDecoration( + color: context.streamColorScheme.backgroundElevation1, + borderRadius: BorderRadius.all(context.streamRadius.xxxl), boxShadow: isFloating ? context.streamBoxShadow.elevation3 : null, ), child: Column( From 10151018c2b6ca75a91e464b636afe176d3554c7 Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Wed, 18 Feb 2026 09:55:25 +0100 Subject: [PATCH 2/8] Allow override of input body --- .../message_composer/message_composer.dart | 3 ++ .../message_composer_input.dart | 14 ++++-- .../message_composer_input_trailing.dart | 47 +++++++++++++++---- 3 files changed, 50 insertions(+), 14 deletions(-) diff --git a/packages/stream_core_flutter/lib/src/components/message_composer/message_composer.dart b/packages/stream_core_flutter/lib/src/components/message_composer/message_composer.dart index d7d38f4..f1a6dee 100644 --- a/packages/stream_core_flutter/lib/src/components/message_composer/message_composer.dart +++ b/packages/stream_core_flutter/lib/src/components/message_composer/message_composer.dart @@ -16,6 +16,7 @@ class StreamBaseMessageComposer extends StatefulWidget { this.composerTrailing, this.inputLeading, this.inputTrailing, + this.inputBody, this.inputHeader, }); @@ -28,6 +29,7 @@ class StreamBaseMessageComposer extends StatefulWidget { final Widget? composerTrailing; final Widget? inputLeading; final Widget? inputTrailing; + final Widget? inputBody; final Widget? inputHeader; @override @@ -98,6 +100,7 @@ class _StreamBaseMessageComposerState extends State { isFloating: widget.isFloating, inputLeading: widget.inputLeading, inputTrailing: widget.inputTrailing, + inputBody: widget.inputBody, inputHeader: widget.inputHeader, focusNode: widget.focusNode, ), diff --git a/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input.dart b/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input.dart index 756d0cc..01f3940 100644 --- a/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input.dart +++ b/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input.dart @@ -10,6 +10,7 @@ class StreamMessageComposerInput extends StatelessWidget { this.isFloating = false, this.inputLeading, this.inputTrailing, + this.inputBody, this.inputHeader, this.focusNode, }); @@ -19,6 +20,7 @@ class StreamMessageComposerInput extends StatelessWidget { final bool isFloating; final Widget? inputLeading; final Widget? inputTrailing; + final Widget? inputBody; final Widget? inputHeader; final FocusNode? focusNode; @@ -45,11 +47,13 @@ class StreamMessageComposerInput extends StatelessWidget { children: [ ?inputLeading, Expanded( - child: _MessageComposerInputField( - controller: controller, - placeholder: placeholder, - focusNode: focusNode, - ), + child: + inputBody ?? + _MessageComposerInputField( + controller: controller, + placeholder: placeholder, + focusNode: focusNode, + ), ), ?inputTrailing, ], diff --git a/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input_trailing.dart b/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input_trailing.dart index c8caed3..65653ab 100644 --- a/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input_trailing.dart +++ b/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input_trailing.dart @@ -8,12 +8,12 @@ class StreamMessageComposerInputTrailing extends StatefulWidget { super.key, required this.controller, required this.onSendPressed, - required this.onMicrophonePressed, + required this.voiceRecordingCallback, }); final TextEditingController controller; final VoidCallback onSendPressed; - final VoidCallback? onMicrophonePressed; + final VoiceRecordingCallback? voiceRecordingCallback; @override State createState() => _StreamMessageComposerInputTrailingState(); @@ -45,11 +45,17 @@ class _StreamMessageComposerInputTrailingState extends State voiceRecordingCallback.onStop(), + behavior: HitTestBehavior.translucent, + child: StreamButton.icon( + icon: context.streamIcons.microphone, + type: StreamButtonType.ghost, + style: StreamButtonStyle.secondary, + size: StreamButtonSize.small, + onTap: () {}, + ), ); } } +class VoiceRecordingCallback { + VoiceRecordingCallback({required this.onStart, required this.onStop}); + + final VoidCallback onStart; + final VoidCallback onStop; +} + final _messageComposerInputTrailingSendKey = UniqueKey(); final _messageComposerInputTrailingMicrophoneKey = UniqueKey(); From 47e78940f0e9d14fe57d5144e7cd123a839aaebf Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Wed, 18 Feb 2026 14:50:11 +0100 Subject: [PATCH 3/8] simplify StreamBaseMessageComposerInputTrailing --- .../message_composer/message_composer.dart | 22 +++- .../message_composer_input.dart | 1 + .../message_composer_input_trailing.dart | 110 +++++++++--------- .../theme/semantics/stream_color_scheme.dart | 58 +++++---- 4 files changed, 98 insertions(+), 93 deletions(-) diff --git a/apps/design_system_gallery/lib/components/message_composer/message_composer.dart b/apps/design_system_gallery/lib/components/message_composer/message_composer.dart index e74dccc..6d9bb1a 100644 --- a/apps/design_system_gallery/lib/components/message_composer/message_composer.dart +++ b/apps/design_system_gallery/lib/components/message_composer/message_composer.dart @@ -7,6 +7,13 @@ import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; // Playground // ============================================================================= +final emptyVoiceRecordingCallback = VoiceRecordingCallback( + onLongPressStart: () {}, + onLongPressCancel: () {}, + onLongPressEnd: (_) {}, + onLongPressMoveUpdate: (_) {}, +); + @widgetbook.UseCase( name: 'Playground', type: StreamBaseMessageComposer, @@ -19,10 +26,11 @@ Widget buildStreamMessageComposerPlayground(BuildContext context) { child: StreamBaseMessageComposer( controller: textEditingController, isFloating: false, - inputTrailing: StreamMessageComposerInputTrailing( + inputTrailing: StreamBaseMessageComposerInputTrailing( controller: textEditingController, onSendPressed: () {}, - onMicrophonePressed: () {}, + voiceRecordingCallback: emptyVoiceRecordingCallback, + buttonState: StreamMessageComposerInputTrailingState.microphone, ), ), ); @@ -129,10 +137,11 @@ Widget buildStreamMessageComposerExample(BuildContext context) { child: StreamBaseMessageComposer( controller: textEditingController, isFloating: true, - inputTrailing: StreamMessageComposerInputTrailing( + inputTrailing: StreamBaseMessageComposerInputTrailing( controller: textEditingController, onSendPressed: () {}, - onMicrophonePressed: () {}, + voiceRecordingCallback: emptyVoiceRecordingCallback, + buttonState: StreamMessageComposerInputTrailingState.microphone, ), ), ), @@ -163,10 +172,11 @@ Widget buildStreamMessageComposerExample(BuildContext context) { StreamBaseMessageComposer( controller: textEditingController, isFloating: false, - inputTrailing: StreamMessageComposerInputTrailing( + inputTrailing: StreamBaseMessageComposerInputTrailing( controller: textEditingController, onSendPressed: () {}, - onMicrophonePressed: () {}, + voiceRecordingCallback: emptyVoiceRecordingCallback, + buttonState: StreamMessageComposerInputTrailingState.microphone, ), ), ], diff --git a/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input.dart b/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input.dart index 01f3940..989f9c6 100644 --- a/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input.dart +++ b/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input.dart @@ -27,6 +27,7 @@ class StreamMessageComposerInput extends StatelessWidget { @override Widget build(BuildContext context) { return Container( + clipBehavior: Clip.antiAlias, foregroundDecoration: BoxDecoration( borderRadius: BorderRadius.all(context.streamRadius.xxxl), border: Border.all( diff --git a/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input_trailing.dart b/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input_trailing.dart index 65653ab..8feb509 100644 --- a/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input_trailing.dart +++ b/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input_trailing.dart @@ -3,98 +3,98 @@ import 'package:flutter/widgets.dart'; import '../../../stream_core_flutter.dart'; -class StreamMessageComposerInputTrailing extends StatefulWidget { - const StreamMessageComposerInputTrailing({ +enum StreamMessageComposerInputTrailingState { + send, + microphone, + voiceRecordingActive, +} + +class StreamBaseMessageComposerInputTrailing extends StatelessWidget { + const StreamBaseMessageComposerInputTrailing({ super.key, required this.controller, required this.onSendPressed, required this.voiceRecordingCallback, + this.buttonState = StreamMessageComposerInputTrailingState.send, }); final TextEditingController controller; final VoidCallback onSendPressed; final VoiceRecordingCallback? voiceRecordingCallback; - - @override - State createState() => _StreamMessageComposerInputTrailingState(); -} - -class _StreamMessageComposerInputTrailingState extends State { - var _hasText = false; - - @override - void initState() { - super.initState(); - widget.controller.addListener(_onInputTextChanged); - _hasText = widget.controller.text.isNotEmpty; - } - - @override - void didUpdateWidget(StreamMessageComposerInputTrailing oldWidget) { - super.didUpdateWidget(oldWidget); - if (widget.controller != oldWidget.controller) { - oldWidget.controller.removeListener(_onInputTextChanged); - widget.controller.addListener(_onInputTextChanged); - } - } - - void _onInputTextChanged() { - final hasText = widget.controller.text.isNotEmpty; - if (_hasText != hasText) { - setState(() => _hasText = hasText); - } - } - - @override - void dispose() { - widget.controller.removeListener(_onInputTextChanged); - super.dispose(); - } + final StreamMessageComposerInputTrailingState buttonState; @override Widget build(BuildContext context) { - // TODO: Implement the trailing component - - if (_hasText || widget.voiceRecordingCallback == null) { + if (buttonState == StreamMessageComposerInputTrailingState.send || voiceRecordingCallback == null) { return StreamButton.icon( key: _messageComposerInputTrailingSendKey, icon: context.streamIcons.paperPlane, size: StreamButtonSize.small, - onTap: widget.onSendPressed, + onTap: onSendPressed, ); } - return StreamVoiceRecordingButton(voiceRecordingCallback: widget.voiceRecordingCallback!); + return StreamVoiceRecordingButton( + voiceRecordingCallback: voiceRecordingCallback!, + isRecording: buttonState == StreamMessageComposerInputTrailingState.voiceRecordingActive, + ); } } class StreamVoiceRecordingButton extends StatelessWidget { - const StreamVoiceRecordingButton({super.key, required this.voiceRecordingCallback}); + const StreamVoiceRecordingButton({ + super.key, + required this.voiceRecordingCallback, + required this.isRecording, + }); final VoiceRecordingCallback voiceRecordingCallback; + final bool isRecording; @override Widget build(BuildContext context) { return GestureDetector( key: _messageComposerInputTrailingMicrophoneKey, - onLongPress: voiceRecordingCallback.onStart, - onLongPressEnd: (details) => voiceRecordingCallback.onStop(), + onLongPress: voiceRecordingCallback.onLongPressStart, + onLongPressCancel: voiceRecordingCallback.onLongPressCancel, + onLongPressEnd: voiceRecordingCallback.onLongPressEnd, + onLongPressMoveUpdate: voiceRecordingCallback.onLongPressMoveUpdate, behavior: HitTestBehavior.translucent, - child: StreamButton.icon( - icon: context.streamIcons.microphone, - type: StreamButtonType.ghost, - style: StreamButtonStyle.secondary, - size: StreamButtonSize.small, - onTap: () {}, + child: StreamButtonTheme( + data: StreamButtonThemeData( + secondary: StreamButtonTypeStyle( + ghost: StreamButtonThemeStyle( + backgroundColor: isRecording + ? WidgetStateProperty.all( + context.streamColorScheme.statePressed, + ) + : null, + ), + ), + ), + child: StreamButton.icon( + icon: context.streamIcons.microphone, + type: StreamButtonType.ghost, + style: StreamButtonStyle.secondary, + size: StreamButtonSize.small, + onTap: () {}, + ), ), ); } } class VoiceRecordingCallback { - VoiceRecordingCallback({required this.onStart, required this.onStop}); + VoiceRecordingCallback({ + required this.onLongPressStart, + required this.onLongPressCancel, + required this.onLongPressEnd, + this.onLongPressMoveUpdate, + }); - final VoidCallback onStart; - final VoidCallback onStop; + final VoidCallback onLongPressStart; + final VoidCallback onLongPressCancel; + final GestureLongPressEndCallback onLongPressEnd; + final GestureLongPressMoveUpdateCallback? onLongPressMoveUpdate; } final _messageComposerInputTrailingSendKey = UniqueKey(); diff --git a/packages/stream_core_flutter/lib/src/theme/semantics/stream_color_scheme.dart b/packages/stream_core_flutter/lib/src/theme/semantics/stream_color_scheme.dart index 1cbcbbe..32ea3f8 100644 --- a/packages/stream_core_flutter/lib/src/theme/semantics/stream_color_scheme.dart +++ b/packages/stream_core_flutter/lib/src/theme/semantics/stream_color_scheme.dart @@ -742,22 +742,19 @@ class StreamBrandColor extends StreamColorSwatch { /// Defaults to blue with shade500 as the primary color. factory StreamBrandColor.light() { final primaryColorValue = light_tokens.StreamTokens.brand500.toARGB32(); - return ._( - primaryColorValue, - { - 50: light_tokens.StreamTokens.brand50, - 100: light_tokens.StreamTokens.brand100, - 150: light_tokens.StreamTokens.brand150, - 200: light_tokens.StreamTokens.brand200, - 300: light_tokens.StreamTokens.brand300, - 400: light_tokens.StreamTokens.brand400, - 500: Color(primaryColorValue), - 600: light_tokens.StreamTokens.brand600, - 700: light_tokens.StreamTokens.brand700, - 800: light_tokens.StreamTokens.brand800, - 900: light_tokens.StreamTokens.brand900, - }, - ); + return ._(primaryColorValue, { + 50: light_tokens.StreamTokens.brand50, + 100: light_tokens.StreamTokens.brand100, + 150: light_tokens.StreamTokens.brand150, + 200: light_tokens.StreamTokens.brand200, + 300: light_tokens.StreamTokens.brand300, + 400: light_tokens.StreamTokens.brand400, + 500: Color(primaryColorValue), + 600: light_tokens.StreamTokens.brand600, + 700: light_tokens.StreamTokens.brand700, + 800: light_tokens.StreamTokens.brand800, + 900: light_tokens.StreamTokens.brand900, + }); } /// Creates a dark theme brand color swatch. @@ -767,22 +764,19 @@ class StreamBrandColor extends StreamColorSwatch { /// vice versa. factory StreamBrandColor.dark() { final primaryColorValue = dark_tokens.StreamTokens.brand500.toARGB32(); - return ._( - primaryColorValue, - { - 50: dark_tokens.StreamTokens.brand50, - 100: dark_tokens.StreamTokens.brand100, - 150: dark_tokens.StreamTokens.brand150, - 200: dark_tokens.StreamTokens.brand200, - 300: dark_tokens.StreamTokens.brand300, - 400: dark_tokens.StreamTokens.brand400, - 500: Color(primaryColorValue), - 600: dark_tokens.StreamTokens.brand600, - 700: dark_tokens.StreamTokens.brand700, - 800: dark_tokens.StreamTokens.brand800, - 900: dark_tokens.StreamTokens.brand900, - }, - ); + return ._(primaryColorValue, { + 50: dark_tokens.StreamTokens.brand50, + 100: dark_tokens.StreamTokens.brand100, + 150: dark_tokens.StreamTokens.brand150, + 200: dark_tokens.StreamTokens.brand200, + 300: dark_tokens.StreamTokens.brand300, + 400: dark_tokens.StreamTokens.brand400, + 500: Color(primaryColorValue), + 600: dark_tokens.StreamTokens.brand600, + 700: dark_tokens.StreamTokens.brand700, + 800: dark_tokens.StreamTokens.brand800, + 900: dark_tokens.StreamTokens.brand900, + }); } } From 6cfa7607961fc46f4d0d30be7f685611cce883f1 Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Wed, 18 Feb 2026 17:13:33 +0100 Subject: [PATCH 4/8] cleanup unnecessary fields --- .../attachment/message_composer_attachment_file.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_file.dart b/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_file.dart index daa7c78..6624c9f 100644 --- a/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_file.dart +++ b/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_file.dart @@ -19,7 +19,6 @@ class MessageComposerAttachmentFile extends StatelessWidget { @override Widget build(BuildContext context) { - final messageTheme = context.streamMessageTheme.mergeWithDefaults(context); final textColor = context.streamColorScheme.textPrimary; final titleStyle = context.streamTextTheme.captionEmphasis.copyWith(color: textColor); @@ -40,7 +39,6 @@ class MessageComposerAttachmentFile extends StatelessWidget { borderRadius: BorderRadius.all(context.streamRadius.lg), ), child: Row( - crossAxisAlignment: CrossAxisAlignment.center, children: [ ?fileTypeIcon, SizedBox(width: spacing.xs), From 73f65917ca877213360c40238ceb4ae3f317254d Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Thu, 19 Feb 2026 09:59:11 +0100 Subject: [PATCH 5/8] formatting --- .../message_composer/message_composer_input_trailing.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input_trailing.dart b/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input_trailing.dart index 8feb509..4329424 100644 --- a/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input_trailing.dart +++ b/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input_trailing.dart @@ -84,7 +84,7 @@ class StreamVoiceRecordingButton extends StatelessWidget { } class VoiceRecordingCallback { - VoiceRecordingCallback({ + VoiceRecordingCallback({ required this.onLongPressStart, required this.onLongPressCancel, required this.onLongPressEnd, From 7084ade1bb7d73dd3c0a7639f2f6107c0ad26908 Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Thu, 19 Feb 2026 12:45:25 +0100 Subject: [PATCH 6/8] publicly export StreamRemoveControl --- packages/stream_core_flutter/lib/src/components.dart | 1 + .../{remove_control.dart => stream_remove_control.dart} | 4 ++-- .../attachment/message_composer_attachment_file.dart | 3 +-- .../attachment/message_composer_attachment_link_preview.dart | 3 +-- .../attachment/message_composer_attachment_media_file.dart | 3 +-- .../attachment/message_composer_attachment_reply.dart | 3 +-- 6 files changed, 7 insertions(+), 10 deletions(-) rename packages/stream_core_flutter/lib/src/components/controls/{remove_control.dart => stream_remove_control.dart} (90%) diff --git a/packages/stream_core_flutter/lib/src/components.dart b/packages/stream_core_flutter/lib/src/components.dart index fec8d66..fff1865 100644 --- a/packages/stream_core_flutter/lib/src/components.dart +++ b/packages/stream_core_flutter/lib/src/components.dart @@ -8,6 +8,7 @@ export 'components/badge/stream_media_badge.dart'; export 'components/badge/stream_online_indicator.dart' hide DefaultStreamOnlineIndicator; export 'components/buttons/stream_button.dart' hide DefaultStreamButton; export 'components/buttons/stream_emoji_button.dart' hide DefaultStreamEmojiButton; +export 'components/controls/stream_remove_control.dart'; export 'components/message_composer.dart'; export 'components/reaction/picker/stream_reaction_picker_sheet.dart'; diff --git a/packages/stream_core_flutter/lib/src/components/controls/remove_control.dart b/packages/stream_core_flutter/lib/src/components/controls/stream_remove_control.dart similarity index 90% rename from packages/stream_core_flutter/lib/src/components/controls/remove_control.dart rename to packages/stream_core_flutter/lib/src/components/controls/stream_remove_control.dart index ca32bd5..58a60cd 100644 --- a/packages/stream_core_flutter/lib/src/components/controls/remove_control.dart +++ b/packages/stream_core_flutter/lib/src/components/controls/stream_remove_control.dart @@ -2,8 +2,8 @@ import 'package:flutter/widgets.dart'; import '../../../stream_core_flutter.dart'; -class RemoveControl extends StatelessWidget { - const RemoveControl({ +class StreamRemoveControl extends StatelessWidget { + const StreamRemoveControl({ super.key, required this.onPressed, }); diff --git a/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_file.dart b/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_file.dart index 6624c9f..7718f5a 100644 --- a/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_file.dart +++ b/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_file.dart @@ -1,7 +1,6 @@ import 'package:flutter/widgets.dart'; import '../../../../stream_core_flutter.dart'; -import '../../controls/remove_control.dart'; class MessageComposerAttachmentFile extends StatelessWidget { const MessageComposerAttachmentFile({ @@ -64,7 +63,7 @@ class MessageComposerAttachmentFile extends StatelessWidget { if (onRemovePressed case final VoidCallback onRemovePressed?) Align( alignment: Alignment.topRight, - child: RemoveControl(onPressed: onRemovePressed), + child: StreamRemoveControl(onPressed: onRemovePressed), ), ], ); diff --git a/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_link_preview.dart b/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_link_preview.dart index 29652bd..66e4cc8 100644 --- a/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_link_preview.dart +++ b/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_link_preview.dart @@ -1,7 +1,6 @@ import 'package:flutter/widgets.dart'; import '../../../../stream_core_flutter.dart'; -import '../../controls/remove_control.dart'; class MessageComposerAttachmentLinkPreview extends StatelessWidget { const MessageComposerAttachmentLinkPreview({ @@ -95,7 +94,7 @@ class MessageComposerAttachmentLinkPreview extends StatelessWidget { if (onRemovePressed case final VoidCallback onRemovePressed?) Align( alignment: Alignment.topRight, - child: RemoveControl(onPressed: onRemovePressed), + child: StreamRemoveControl(onPressed: onRemovePressed), ), ], ); diff --git a/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_media_file.dart b/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_media_file.dart index 259c3c7..4e57694 100644 --- a/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_media_file.dart +++ b/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_media_file.dart @@ -1,7 +1,6 @@ import 'package:flutter/widgets.dart'; import '../../../../stream_core_flutter.dart'; -import '../../controls/remove_control.dart'; class MessageComposerAttachmentMediaFile extends StatelessWidget { const MessageComposerAttachmentMediaFile({ @@ -55,7 +54,7 @@ class MessageComposerAttachmentMediaFile extends StatelessWidget { if (onRemovePressed case final VoidCallback onRemovePressed?) Align( alignment: Alignment.topRight, - child: RemoveControl(onPressed: onRemovePressed), + child: StreamRemoveControl(onPressed: onRemovePressed), ), if (mediaBadge case final Widget mediaBadge?) Align( diff --git a/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_reply.dart b/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_reply.dart index c2dba45..c83b8f7 100644 --- a/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_reply.dart +++ b/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_reply.dart @@ -2,7 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import '../../../../stream_core_flutter.dart'; -import '../../controls/remove_control.dart'; class MessageComposerAttachmentReply extends StatelessWidget { const MessageComposerAttachmentReply({ @@ -96,7 +95,7 @@ class MessageComposerAttachmentReply extends StatelessWidget { if (onRemovePressed case final VoidCallback onRemovePressed?) Align( alignment: Alignment.topRight, - child: RemoveControl(onPressed: onRemovePressed), + child: StreamRemoveControl(onPressed: onRemovePressed), ), ], ); From bab007c72b0fba53391370ffbe2486567716cb26 Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Fri, 20 Feb 2026 14:44:46 +0100 Subject: [PATCH 7/8] attachment and composer renaming --- .../message_composer/message_composer.dart | 16 ++++++------- ...sage_composer_attachment_link_preview.dart | 4 ++-- ...essage_composer_attachment_media_file.dart | 4 ++-- .../message_composer_attachment_reply.dart | 4 ++-- .../lib/src/components/message_composer.dart | 8 +++---- ... => message_composer_file_attachment.dart} | 4 ++-- ...age_composer_link_preview_attachment.dart} | 4 ++-- ...ssage_composer_media_file_attachment.dart} | 6 ++--- ...=> message_composer_reply_attachment.dart} | 4 ++-- .../message_composer/message_composer.dart | 12 +++++----- .../message_composer_input_trailing.dart | 4 ++-- ...r_attachment_link_preview_golden_test.dart | 24 +++++++++---------- ...composer_attachment_reply_golden_test.dart | 10 ++++---- 13 files changed, 52 insertions(+), 52 deletions(-) rename packages/stream_core_flutter/lib/src/components/message_composer/attachment/{message_composer_attachment_file.dart => message_composer_file_attachment.dart} (95%) rename packages/stream_core_flutter/lib/src/components/message_composer/attachment/{message_composer_attachment_link_preview.dart => message_composer_link_preview_attachment.dart} (96%) rename packages/stream_core_flutter/lib/src/components/message_composer/attachment/{message_composer_attachment_media_file.dart => message_composer_media_file_attachment.dart} (92%) rename packages/stream_core_flutter/lib/src/components/message_composer/attachment/{message_composer_attachment_reply.dart => message_composer_reply_attachment.dart} (97%) diff --git a/apps/design_system_gallery/lib/components/message_composer/message_composer.dart b/apps/design_system_gallery/lib/components/message_composer/message_composer.dart index 6d9bb1a..07fed36 100644 --- a/apps/design_system_gallery/lib/components/message_composer/message_composer.dart +++ b/apps/design_system_gallery/lib/components/message_composer/message_composer.dart @@ -16,17 +16,17 @@ final emptyVoiceRecordingCallback = VoiceRecordingCallback( @widgetbook.UseCase( name: 'Playground', - type: StreamBaseMessageComposer, + type: StreamCoreMessageComposer, path: '[Components]/Message Composer', ) Widget buildStreamMessageComposerPlayground(BuildContext context) { final textEditingController = TextEditingController(); return Center( - child: StreamBaseMessageComposer( + child: StreamCoreMessageComposer( controller: textEditingController, isFloating: false, - inputTrailing: StreamBaseMessageComposerInputTrailing( + inputTrailing: StreamCoreMessageComposerInputTrailing( controller: textEditingController, onSendPressed: () {}, voiceRecordingCallback: emptyVoiceRecordingCallback, @@ -42,7 +42,7 @@ Widget buildStreamMessageComposerPlayground(BuildContext context) { @widgetbook.UseCase( name: 'Real-world Example', - type: StreamBaseMessageComposer, + type: StreamCoreMessageComposer, path: '[Components]/Message Composer', ) Widget buildStreamMessageComposerExample(BuildContext context) { @@ -134,10 +134,10 @@ Widget buildStreamMessageComposerExample(BuildContext context) { left: 0, right: 0, bottom: 0, - child: StreamBaseMessageComposer( + child: StreamCoreMessageComposer( controller: textEditingController, isFloating: true, - inputTrailing: StreamBaseMessageComposerInputTrailing( + inputTrailing: StreamCoreMessageComposerInputTrailing( controller: textEditingController, onSendPressed: () {}, voiceRecordingCallback: emptyVoiceRecordingCallback, @@ -169,10 +169,10 @@ Widget buildStreamMessageComposerExample(BuildContext context) { ), ), // Non-floating composer - StreamBaseMessageComposer( + StreamCoreMessageComposer( controller: textEditingController, isFloating: false, - inputTrailing: StreamBaseMessageComposerInputTrailing( + inputTrailing: StreamCoreMessageComposerInputTrailing( controller: textEditingController, onSendPressed: () {}, voiceRecordingCallback: emptyVoiceRecordingCallback, diff --git a/apps/design_system_gallery/lib/components/message_composer/message_composer_attachment_link_preview.dart b/apps/design_system_gallery/lib/components/message_composer/message_composer_attachment_link_preview.dart index 20add47..25d0f9a 100644 --- a/apps/design_system_gallery/lib/components/message_composer/message_composer_attachment_link_preview.dart +++ b/apps/design_system_gallery/lib/components/message_composer/message_composer_attachment_link_preview.dart @@ -9,7 +9,7 @@ import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; @widgetbook.UseCase( name: 'Playground', - type: MessageComposerAttachmentLinkPreview, + type: MessageComposerLinkPreviewAttachment, path: '[Components]/Message Composer', ) Widget buildMessageComposerAttachmentLinkPreviewPlayground(BuildContext context) { @@ -42,7 +42,7 @@ Widget buildMessageComposerAttachmentLinkPreviewPlayground(BuildContext context) return Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 360), - child: MessageComposerAttachmentLinkPreview( + child: MessageComposerLinkPreviewAttachment( title: title.isEmpty ? null : title, subtitle: subtitle.isEmpty ? null : subtitle, url: url.isEmpty ? null : url, diff --git a/apps/design_system_gallery/lib/components/message_composer/message_composer_attachment_media_file.dart b/apps/design_system_gallery/lib/components/message_composer/message_composer_attachment_media_file.dart index 17de6a6..bb79ecb 100644 --- a/apps/design_system_gallery/lib/components/message_composer/message_composer_attachment_media_file.dart +++ b/apps/design_system_gallery/lib/components/message_composer/message_composer_attachment_media_file.dart @@ -8,12 +8,12 @@ import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; @widgetbook.UseCase( name: 'Playground', - type: MessageComposerAttachmentMediaFile, + type: MessageComposerMediaFileAttachment, path: '[Components]/Message Composer', ) Widget buildMessageComposerAttachmentMediaFilePlayground(BuildContext context) { return Center( - child: MessageComposerAttachmentMediaFile.image( + child: MessageComposerMediaFileAttachment.image( image: const AssetImage('assets/attachment_image.png'), onRemovePressed: () {}, ), diff --git a/apps/design_system_gallery/lib/components/message_composer/message_composer_attachment_reply.dart b/apps/design_system_gallery/lib/components/message_composer/message_composer_attachment_reply.dart index fe4db18..2ea43b0 100644 --- a/apps/design_system_gallery/lib/components/message_composer/message_composer_attachment_reply.dart +++ b/apps/design_system_gallery/lib/components/message_composer/message_composer_attachment_reply.dart @@ -9,7 +9,7 @@ import 'package:widgetbook_annotation/widgetbook_annotation.dart' as widgetbook; @widgetbook.UseCase( name: 'Playground', - type: MessageComposerAttachmentReply, + type: MessageComposerReplyAttachment, path: '[Components]/Message Composer', ) Widget buildMessageComposerAttachmentReplyPlayground(BuildContext context) { @@ -24,7 +24,7 @@ Widget buildMessageComposerAttachmentReplyPlayground(BuildContext context) { return Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 360), - child: MessageComposerAttachmentReply( + child: MessageComposerReplyAttachment( title: 'Reply to John Doe', subtitle: 'We had a great time during our holiday.', image: const AssetImage('assets/attachment_image.png'), diff --git a/packages/stream_core_flutter/lib/src/components/message_composer.dart b/packages/stream_core_flutter/lib/src/components/message_composer.dart index 5a57f31..5cf1e94 100644 --- a/packages/stream_core_flutter/lib/src/components/message_composer.dart +++ b/packages/stream_core_flutter/lib/src/components/message_composer.dart @@ -1,7 +1,7 @@ -export 'message_composer/attachment/message_composer_attachment_file.dart'; -export 'message_composer/attachment/message_composer_attachment_link_preview.dart'; -export 'message_composer/attachment/message_composer_attachment_media_file.dart'; -export 'message_composer/attachment/message_composer_attachment_reply.dart'; +export 'message_composer/attachment/message_composer_file_attachment.dart'; +export 'message_composer/attachment/message_composer_link_preview_attachment.dart'; +export 'message_composer/attachment/message_composer_media_file_attachment.dart'; +export 'message_composer/attachment/message_composer_reply_attachment.dart'; export 'message_composer/message_composer.dart'; export 'message_composer/message_composer_input.dart'; export 'message_composer/message_composer_input_trailing.dart'; diff --git a/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_file.dart b/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_file_attachment.dart similarity index 95% rename from packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_file.dart rename to packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_file_attachment.dart index 7718f5a..f5f2ef0 100644 --- a/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_file.dart +++ b/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_file_attachment.dart @@ -2,8 +2,8 @@ import 'package:flutter/widgets.dart'; import '../../../../stream_core_flutter.dart'; -class MessageComposerAttachmentFile extends StatelessWidget { - const MessageComposerAttachmentFile({ +class MessageComposerFileAttachment extends StatelessWidget { + const MessageComposerFileAttachment({ super.key, this.title, this.fileTypeIcon, diff --git a/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_link_preview.dart b/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_link_preview_attachment.dart similarity index 96% rename from packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_link_preview.dart rename to packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_link_preview_attachment.dart index 66e4cc8..cde9dbc 100644 --- a/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_link_preview.dart +++ b/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_link_preview_attachment.dart @@ -2,8 +2,8 @@ import 'package:flutter/widgets.dart'; import '../../../../stream_core_flutter.dart'; -class MessageComposerAttachmentLinkPreview extends StatelessWidget { - const MessageComposerAttachmentLinkPreview({ +class MessageComposerLinkPreviewAttachment extends StatelessWidget { + const MessageComposerLinkPreviewAttachment({ super.key, this.title, this.subtitle, diff --git a/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_media_file.dart b/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_media_file_attachment.dart similarity index 92% rename from packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_media_file.dart rename to packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_media_file_attachment.dart index 4e57694..8ea5756 100644 --- a/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_media_file.dart +++ b/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_media_file_attachment.dart @@ -2,15 +2,15 @@ import 'package:flutter/widgets.dart'; import '../../../../stream_core_flutter.dart'; -class MessageComposerAttachmentMediaFile extends StatelessWidget { - const MessageComposerAttachmentMediaFile({ +class MessageComposerMediaFileAttachment extends StatelessWidget { + const MessageComposerMediaFileAttachment({ super.key, required this.child, this.onRemovePressed, this.mediaBadge, }); - MessageComposerAttachmentMediaFile.image({ + MessageComposerMediaFileAttachment.image({ super.key, required ImageProvider image, required this.onRemovePressed, diff --git a/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_reply.dart b/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_reply_attachment.dart similarity index 97% rename from packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_reply.dart rename to packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_reply_attachment.dart index c83b8f7..3a298b7 100644 --- a/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_attachment_reply.dart +++ b/packages/stream_core_flutter/lib/src/components/message_composer/attachment/message_composer_reply_attachment.dart @@ -3,8 +3,8 @@ import 'package:flutter/widgets.dart'; import '../../../../stream_core_flutter.dart'; -class MessageComposerAttachmentReply extends StatelessWidget { - const MessageComposerAttachmentReply({ +class MessageComposerReplyAttachment extends StatelessWidget { + const MessageComposerReplyAttachment({ super.key, required this.title, required this.subtitle, diff --git a/packages/stream_core_flutter/lib/src/components/message_composer/message_composer.dart b/packages/stream_core_flutter/lib/src/components/message_composer/message_composer.dart index f1a6dee..4ee9f8a 100644 --- a/packages/stream_core_flutter/lib/src/components/message_composer/message_composer.dart +++ b/packages/stream_core_flutter/lib/src/components/message_composer/message_composer.dart @@ -5,8 +5,8 @@ import 'package:flutter/widgets.dart'; import '../../../stream_core_flutter.dart'; -class StreamBaseMessageComposer extends StatefulWidget { - const StreamBaseMessageComposer({ +class StreamCoreMessageComposer extends StatefulWidget { + const StreamCoreMessageComposer({ super.key, required this.controller, required this.isFloating, @@ -33,10 +33,10 @@ class StreamBaseMessageComposer extends StatefulWidget { final Widget? inputHeader; @override - State createState() => _StreamBaseMessageComposerState(); + State createState() => _StreamCoreMessageComposerState(); } -class _StreamBaseMessageComposerState extends State { +class _StreamCoreMessageComposerState extends State { late TextEditingController _controller; @override @@ -46,7 +46,7 @@ class _StreamBaseMessageComposerState extends State { } @override - void didUpdateWidget(StreamBaseMessageComposer oldWidget) { + void didUpdateWidget(StreamCoreMessageComposer oldWidget) { super.didUpdateWidget(oldWidget); if (widget.controller != oldWidget.controller) { _disposeController(oldWidget); @@ -64,7 +64,7 @@ class _StreamBaseMessageComposerState extends State { _controller = widget.controller ?? TextEditingController(); } - void _disposeController(StreamBaseMessageComposer widget) { + void _disposeController(StreamCoreMessageComposer widget) { if (widget.controller == null) { _controller.dispose(); } diff --git a/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input_trailing.dart b/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input_trailing.dart index 4329424..6f7cb77 100644 --- a/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input_trailing.dart +++ b/packages/stream_core_flutter/lib/src/components/message_composer/message_composer_input_trailing.dart @@ -9,8 +9,8 @@ enum StreamMessageComposerInputTrailingState { voiceRecordingActive, } -class StreamBaseMessageComposerInputTrailing extends StatelessWidget { - const StreamBaseMessageComposerInputTrailing({ +class StreamCoreMessageComposerInputTrailing extends StatelessWidget { + const StreamCoreMessageComposerInputTrailing({ super.key, required this.controller, required this.onSendPressed, diff --git a/packages/stream_core_flutter/test/components/message_composer/message_composer_attachment_link_preview_golden_test.dart b/packages/stream_core_flutter/test/components/message_composer/message_composer_attachment_link_preview_golden_test.dart index 1440132..96cf2f6 100644 --- a/packages/stream_core_flutter/test/components/message_composer/message_composer_attachment_link_preview_golden_test.dart +++ b/packages/stream_core_flutter/test/components/message_composer/message_composer_attachment_link_preview_golden_test.dart @@ -18,7 +18,7 @@ void main() { GoldenTestScenario( name: 'full_no_remove', child: _buildLinkPreviewInTheme( - const MessageComposerAttachmentLinkPreview( + const MessageComposerLinkPreviewAttachment( title: 'Getting started with Stream', subtitle: 'Build in-app messaging with our flexible SDKs.', url: 'https://getstream.io/chat/docs/', @@ -29,7 +29,7 @@ void main() { GoldenTestScenario( name: 'full_with_remove', child: _buildLinkPreviewInTheme( - MessageComposerAttachmentLinkPreview( + MessageComposerLinkPreviewAttachment( title: 'Getting started with Stream', subtitle: 'Build in-app messaging with our flexible SDKs.', url: 'https://getstream.io/chat/docs/', @@ -40,7 +40,7 @@ void main() { GoldenTestScenario( name: 'full_with_image_no_remove', child: _buildLinkPreviewInTheme( - MessageComposerAttachmentLinkPreview( + MessageComposerLinkPreviewAttachment( title: 'Getting started with Stream', subtitle: 'Build in-app messaging with our flexible SDKs.', url: 'https://getstream.io/chat/docs/', @@ -52,7 +52,7 @@ void main() { GoldenTestScenario( name: 'full_with_image_with_remove', child: _buildLinkPreviewInTheme( - MessageComposerAttachmentLinkPreview( + MessageComposerLinkPreviewAttachment( title: 'Getting started with Stream', subtitle: 'Build in-app messaging with our flexible SDKs.', url: 'https://getstream.io/chat/docs/', @@ -64,7 +64,7 @@ void main() { GoldenTestScenario( name: 'url_only_no_remove', child: _buildLinkPreviewInTheme( - const MessageComposerAttachmentLinkPreview( + const MessageComposerLinkPreviewAttachment( title: null, subtitle: null, url: 'https://getstream.io/', @@ -75,7 +75,7 @@ void main() { GoldenTestScenario( name: 'url_only_with_remove', child: _buildLinkPreviewInTheme( - MessageComposerAttachmentLinkPreview( + MessageComposerLinkPreviewAttachment( title: null, subtitle: null, url: 'https://getstream.io/', @@ -96,7 +96,7 @@ void main() { GoldenTestScenario( name: 'full_no_remove', child: _buildLinkPreviewInTheme( - const MessageComposerAttachmentLinkPreview( + const MessageComposerLinkPreviewAttachment( title: 'Getting started with Stream', subtitle: 'Build in-app messaging with our flexible SDKs.', url: 'https://getstream.io/chat/docs/', @@ -108,7 +108,7 @@ void main() { GoldenTestScenario( name: 'full_with_remove', child: _buildLinkPreviewInTheme( - MessageComposerAttachmentLinkPreview( + MessageComposerLinkPreviewAttachment( title: 'Getting started with Stream', subtitle: 'Build in-app messaging with our flexible SDKs.', url: 'https://getstream.io/chat/docs/', @@ -120,7 +120,7 @@ void main() { GoldenTestScenario( name: 'full_with_image_no_remove', child: _buildLinkPreviewInTheme( - MessageComposerAttachmentLinkPreview( + MessageComposerLinkPreviewAttachment( title: 'Getting started with Stream', subtitle: 'Build in-app messaging with our flexible SDKs.', url: 'https://getstream.io/chat/docs/', @@ -133,7 +133,7 @@ void main() { GoldenTestScenario( name: 'full_with_image_with_remove', child: _buildLinkPreviewInTheme( - MessageComposerAttachmentLinkPreview( + MessageComposerLinkPreviewAttachment( title: 'Getting started with Stream', subtitle: 'Build in-app messaging with our flexible SDKs.', url: 'https://getstream.io/chat/docs/', @@ -146,7 +146,7 @@ void main() { GoldenTestScenario( name: 'url_only_no_remove', child: _buildLinkPreviewInTheme( - const MessageComposerAttachmentLinkPreview( + const MessageComposerLinkPreviewAttachment( title: null, subtitle: null, url: 'https://getstream.io/', @@ -158,7 +158,7 @@ void main() { GoldenTestScenario( name: 'url_only_with_remove', child: _buildLinkPreviewInTheme( - MessageComposerAttachmentLinkPreview( + MessageComposerLinkPreviewAttachment( title: null, subtitle: null, url: 'https://getstream.io/', diff --git a/packages/stream_core_flutter/test/components/message_composer/message_composer_attachment_reply_golden_test.dart b/packages/stream_core_flutter/test/components/message_composer/message_composer_attachment_reply_golden_test.dart index 6dc694d..5a76147 100644 --- a/packages/stream_core_flutter/test/components/message_composer/message_composer_attachment_reply_golden_test.dart +++ b/packages/stream_core_flutter/test/components/message_composer/message_composer_attachment_reply_golden_test.dart @@ -17,7 +17,7 @@ void main() { GoldenTestScenario( name: '${style.name}_no_remove', child: _buildReplyInTheme( - MessageComposerAttachmentReply( + MessageComposerReplyAttachment( title: 'Reply to John Doe', subtitle: 'We had a great time during our holiday.', onRemovePressed: null, @@ -29,7 +29,7 @@ void main() { GoldenTestScenario( name: '${style.name}_with_remove', child: _buildReplyInTheme( - MessageComposerAttachmentReply( + MessageComposerReplyAttachment( title: 'Reply to John Doe', subtitle: 'We had a great time during our holiday.', onRemovePressed: () {}, @@ -51,7 +51,7 @@ void main() { GoldenTestScenario( name: '${style.name}_no_remove', child: _buildReplyInTheme( - MessageComposerAttachmentReply( + MessageComposerReplyAttachment( title: 'Reply to John Doe', subtitle: 'We had a great time during our holiday.', onRemovePressed: null, @@ -64,7 +64,7 @@ void main() { GoldenTestScenario( name: '${style.name}_with_remove', child: _buildReplyInTheme( - MessageComposerAttachmentReply( + MessageComposerReplyAttachment( title: 'Reply to John Doe', subtitle: 'We had a great time during our holiday.', onRemovePressed: () {}, @@ -100,7 +100,7 @@ void main() { textColor: Colors.white, ), ), - child: MessageComposerAttachmentReply( + child: MessageComposerReplyAttachment( title: 'Reply to John Doe', subtitle: 'We had a great time during our holiday.', onRemovePressed: null, From 0f3311d0b35ab5a1c512de6479ce727263468836 Mon Sep 17 00:00:00 2001 From: Rene Floor Date: Fri, 20 Feb 2026 14:46:40 +0100 Subject: [PATCH 8/8] formatting --- .../theme/semantics/stream_color_scheme.dart | 58 ++++++++++--------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/packages/stream_core_flutter/lib/src/theme/semantics/stream_color_scheme.dart b/packages/stream_core_flutter/lib/src/theme/semantics/stream_color_scheme.dart index 32ea3f8..1cbcbbe 100644 --- a/packages/stream_core_flutter/lib/src/theme/semantics/stream_color_scheme.dart +++ b/packages/stream_core_flutter/lib/src/theme/semantics/stream_color_scheme.dart @@ -742,19 +742,22 @@ class StreamBrandColor extends StreamColorSwatch { /// Defaults to blue with shade500 as the primary color. factory StreamBrandColor.light() { final primaryColorValue = light_tokens.StreamTokens.brand500.toARGB32(); - return ._(primaryColorValue, { - 50: light_tokens.StreamTokens.brand50, - 100: light_tokens.StreamTokens.brand100, - 150: light_tokens.StreamTokens.brand150, - 200: light_tokens.StreamTokens.brand200, - 300: light_tokens.StreamTokens.brand300, - 400: light_tokens.StreamTokens.brand400, - 500: Color(primaryColorValue), - 600: light_tokens.StreamTokens.brand600, - 700: light_tokens.StreamTokens.brand700, - 800: light_tokens.StreamTokens.brand800, - 900: light_tokens.StreamTokens.brand900, - }); + return ._( + primaryColorValue, + { + 50: light_tokens.StreamTokens.brand50, + 100: light_tokens.StreamTokens.brand100, + 150: light_tokens.StreamTokens.brand150, + 200: light_tokens.StreamTokens.brand200, + 300: light_tokens.StreamTokens.brand300, + 400: light_tokens.StreamTokens.brand400, + 500: Color(primaryColorValue), + 600: light_tokens.StreamTokens.brand600, + 700: light_tokens.StreamTokens.brand700, + 800: light_tokens.StreamTokens.brand800, + 900: light_tokens.StreamTokens.brand900, + }, + ); } /// Creates a dark theme brand color swatch. @@ -764,19 +767,22 @@ class StreamBrandColor extends StreamColorSwatch { /// vice versa. factory StreamBrandColor.dark() { final primaryColorValue = dark_tokens.StreamTokens.brand500.toARGB32(); - return ._(primaryColorValue, { - 50: dark_tokens.StreamTokens.brand50, - 100: dark_tokens.StreamTokens.brand100, - 150: dark_tokens.StreamTokens.brand150, - 200: dark_tokens.StreamTokens.brand200, - 300: dark_tokens.StreamTokens.brand300, - 400: dark_tokens.StreamTokens.brand400, - 500: Color(primaryColorValue), - 600: dark_tokens.StreamTokens.brand600, - 700: dark_tokens.StreamTokens.brand700, - 800: dark_tokens.StreamTokens.brand800, - 900: dark_tokens.StreamTokens.brand900, - }); + return ._( + primaryColorValue, + { + 50: dark_tokens.StreamTokens.brand50, + 100: dark_tokens.StreamTokens.brand100, + 150: dark_tokens.StreamTokens.brand150, + 200: dark_tokens.StreamTokens.brand200, + 300: dark_tokens.StreamTokens.brand300, + 400: dark_tokens.StreamTokens.brand400, + 500: Color(primaryColorValue), + 600: dark_tokens.StreamTokens.brand600, + 700: dark_tokens.StreamTokens.brand700, + 800: dark_tokens.StreamTokens.brand800, + 900: dark_tokens.StreamTokens.brand900, + }, + ); } }