From 2fffa2297542536c1bfd73374aebe9f5b300778e Mon Sep 17 00:00:00 2001 From: Manuel Rasinger Date: Tue, 31 Mar 2026 10:59:51 +0200 Subject: [PATCH 1/4] refactor: add wrapper object to control style --- lib/message_bars/message_bar.dart | 188 ++++++++++++------------ lib/message_bars/message_bar_style.dart | 50 +++++++ 2 files changed, 142 insertions(+), 96 deletions(-) create mode 100644 lib/message_bars/message_bar_style.dart diff --git a/lib/message_bars/message_bar.dart b/lib/message_bars/message_bar.dart index 9f2de69..2b3eca5 100644 --- a/lib/message_bars/message_bar.dart +++ b/lib/message_bars/message_bar.dart @@ -1,3 +1,4 @@ +import 'package:chat_bubbles/message_bars/message_bar_style.dart'; import 'package:flutter/material.dart'; ///Normal Message bar with more actions @@ -62,11 +63,16 @@ class MessageBar extends StatelessWidget { final void Function(String)? onSend; /// callback function triggered when close reply button is pressed final void Function()? onTapCloseReply; + /// config to control appearance of the MessageBar textfield + final MessageBarStyle messageBarStyle; + /// optional custom widget to use as a send button + final Widget? sendButton; /// [MessageBar] constructor /// /// - MessageBar({Key? key, + MessageBar({ + Key? key, this.replying = false, this.replyingTo = "", this.actions = const [], @@ -81,6 +87,8 @@ class MessageBar extends StatelessWidget { this.onTextChanged, this.onSend, this.onTapCloseReply, + this.messageBarStyle = const MessageBarStyle(), + this.sendButton, }) : super(key: key); /// [MessageBar] builder method @@ -92,108 +100,96 @@ class MessageBar extends StatelessWidget { child: Column( mainAxisAlignment: MainAxisAlignment.end, children: [ - replying - ? Container( - color: replyWidgetColor, - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 16, - ), - child: Row( - children: [ - Icon( - Icons.reply, - color: replyIconColor, - size: 24, - ), - Expanded( - child: Text( - 'Re : $replyingTo', - overflow: TextOverflow.ellipsis, - ), - ), - InkWell( - onTap: onTapCloseReply, - child: Icon( - Icons.close, - color: replyCloseColor, - size: 24, - ), + replying + ? Container( + color: replyWidgetColor, + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 16, + ), + child: Row( + children: [ + Icon( + Icons.reply, + color: replyIconColor, + size: 24, + ), + Expanded( + child: Text( + 'Re : $replyingTo', + overflow: TextOverflow.ellipsis, ), - ], - )) - : Container(), - replying - ? Container( - height: 1, - color: Colors.grey.shade300, - ) - : Container(), - Container( - color: messageBarColor, - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 16, - ), - child: Row( - children: [ - ...actions, - Expanded( - child: TextField( - controller: _textController, - keyboardType: TextInputType.multiline, - textCapitalization: TextCapitalization.sentences, - minLines: 1, - maxLines: 3, - onChanged: onTextChanged, - style: textFieldTextStyle, - decoration: InputDecoration( - hintText: messageBarHintText, - hintMaxLines: 1, - contentPadding: const EdgeInsets.symmetric( - horizontal: 8.0, vertical: 10), - hintStyle: messageBarHintStyle, - fillColor: Colors.white, - filled: true, - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(30.0), - borderSide: const BorderSide( - color: Colors.white, - width: 0.2, - ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(30.0), - borderSide: const BorderSide( - color: Colors.black26, - width: 0.2, - ), - ), + ), + InkWell( + onTap: onTapCloseReply, + child: Icon( + Icons.close, + color: replyCloseColor, + size: 24, ), + ), + ], + )) + : Container(), + replying + ? Container( + height: 1, + color: Colors.grey.shade300, + ) + : Container(), + Container( + color: messageBarColor, + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 16, + ), + child: Row( + children: [ + ...actions, + Expanded( + child: TextField( + controller: _textController, + keyboardType: messageBarStyle.textInputType, + textCapitalization: messageBarStyle.textCapitalization, + minLines: 1, + maxLines: 3, + onChanged: onTextChanged, + style: textFieldTextStyle, + decoration: InputDecoration( + hintText: messageBarHintText, + hintMaxLines: 1, + contentPadding: messageBarStyle.contentPadding, + hintStyle: messageBarHintStyle, + fillColor: messageBarStyle.fillColor, + filled: true, + enabledBorder: messageBarStyle.enabledBorder, + focusedBorder: messageBarStyle.focusedBorder, ), ), - Padding( - padding: const EdgeInsets.only(left: 16), - child: InkWell( - child: Icon( - Icons.send, - color: sendButtonColor, - size: 24, - ), - onTap: () { - if (_textController.text.trim() != '') { - if (onSend != null) { - onSend!(_textController.text.trim()); - } - _textController.text = ''; + ), + Padding( + padding: const EdgeInsets.only(left: 16), + child: InkWell( + child: sendButton ?? + Icon( + Icons.send, + color: sendButtonColor, + size: 24, + ), + onTap: () { + if (_textController.text.trim() != '') { + if (onSend != null) { + onSend!(_textController.text.trim()); } - }, - ), + _textController.text = ''; + } + }, ), - ], - ), + ), + ], ), - ], + ), + ], ), ); } diff --git a/lib/message_bars/message_bar_style.dart b/lib/message_bars/message_bar_style.dart new file mode 100644 index 0000000..5b8a17b --- /dev/null +++ b/lib/message_bars/message_bar_style.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; + +/// Style configuration for a `MessageBar`. +/// +/// Groups commonly used appearance and input properties such as borders, +/// padding, keyboard type, and background color. +class MessageBarStyle { + /// Border when the input is enabled but not focused. + final InputBorder enabledBorder; + + /// Border when the input is focused. + final InputBorder focusedBorder; + + /// Keyboard type for the input field. + final TextInputType textInputType; + + /// Text capitalization behavior. + final TextCapitalization textCapitalization; + + /// Inner padding of the input field. + final EdgeInsetsGeometry contentPadding; + + /// Background color of the input field. + final Color fillColor; + + /// Creates a `MessageBarStyle`. + /// + /// All parameters are optional and default to the standard `MessageBar` style. + const MessageBarStyle({ + this.enabledBorder = const OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(30)), + borderSide: BorderSide( + color: Colors.white, + width: 0.2, + ), + ), + this.focusedBorder = const OutlineInputBorder( + borderRadius: BorderRadius.all(Radius.circular(30)), + borderSide: BorderSide( + color: Colors.black26, + width: 0.2, + ), + ), + this.textInputType = TextInputType.multiline, + this.textCapitalization = TextCapitalization.sentences, + this.contentPadding = + const EdgeInsets.symmetric(horizontal: 8.0, vertical: 10), + this.fillColor = Colors.white, + }); +} From 39792b3d84f26bea6b878b47b0d49271b845176d Mon Sep 17 00:00:00 2001 From: Manuel Rasinger Date: Tue, 31 Mar 2026 11:25:02 +0200 Subject: [PATCH 2/4] chore: make changes less verbose --- lib/message_bars/message_bar.dart | 182 +++++++++++++----------- lib/message_bars/message_bar_style.dart | 4 +- 2 files changed, 101 insertions(+), 85 deletions(-) diff --git a/lib/message_bars/message_bar.dart b/lib/message_bars/message_bar.dart index 2b3eca5..e74f2b4 100644 --- a/lib/message_bars/message_bar.dart +++ b/lib/message_bars/message_bar.dart @@ -25,11 +25,15 @@ import 'package:flutter/material.dart'; /// [messageBarColor] is the color of the message bar /// [sendButtonColor] is the color of the send button /// [messageBarHintStyle] is the style of the message bar hint +/// [sendButton] provides an optional widget for the send button /// /// # METHODS /// [onTextChanged] is the function which triggers after text every text change /// [onSend] is the send button action /// [onTapCloseReply] is the close button action of the close button on the +/// +/// # CLASSES +/// [messageBarStyle] contains styling information for the textfield /// reply widget usually change [replying] attribute to `false` class MessageBar extends StatelessWidget { @@ -100,96 +104,108 @@ class MessageBar extends StatelessWidget { child: Column( mainAxisAlignment: MainAxisAlignment.end, children: [ - replying - ? Container( - color: replyWidgetColor, - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 16, - ), - child: Row( - children: [ - Icon( - Icons.reply, - color: replyIconColor, - size: 24, - ), - Expanded( - child: Text( - 'Re : $replyingTo', - overflow: TextOverflow.ellipsis, - ), - ), - InkWell( - onTap: onTapCloseReply, - child: Icon( - Icons.close, - color: replyCloseColor, - size: 24, - ), - ), - ], - )) - : Container(), - replying - ? Container( - height: 1, - color: Colors.grey.shade300, - ) - : Container(), - Container( - color: messageBarColor, - padding: const EdgeInsets.symmetric( - vertical: 8, - horizontal: 16, - ), - child: Row( - children: [ - ...actions, - Expanded( - child: TextField( - controller: _textController, - keyboardType: messageBarStyle.textInputType, - textCapitalization: messageBarStyle.textCapitalization, - minLines: 1, - maxLines: 3, - onChanged: onTextChanged, - style: textFieldTextStyle, - decoration: InputDecoration( - hintText: messageBarHintText, - hintMaxLines: 1, - contentPadding: messageBarStyle.contentPadding, - hintStyle: messageBarHintStyle, - fillColor: messageBarStyle.fillColor, - filled: true, - enabledBorder: messageBarStyle.enabledBorder, - focusedBorder: messageBarStyle.focusedBorder, + replying + ? Container( + color: replyWidgetColor, + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 16, ), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 16), - child: InkWell( - child: sendButton ?? + child: Row( + children: [ Icon( - Icons.send, - color: sendButtonColor, + Icons.reply, + color: replyIconColor, size: 24, ), - onTap: () { - if (_textController.text.trim() != '') { - if (onSend != null) { - onSend!(_textController.text.trim()); + Expanded( + child: Text( + 'Re : $replyingTo', + overflow: TextOverflow.ellipsis, + ), + ), + InkWell( + onTap: onTapCloseReply, + child: Icon( + Icons.close, + color: replyCloseColor, + size: 24, + ), + ), + ], + )) + : Container(), + replying + ? Container( + height: 1, + color: Colors.grey.shade300, + ) + : Container(), + Container( + color: messageBarColor, + padding: const EdgeInsets.symmetric( + vertical: 8, + horizontal: 16, + ), + child: Row( + children: [ + ...actions, + Expanded( + child: TextField( + controller: _textController, + keyboardType: TextInputType.multiline, + textCapitalization: TextCapitalization.sentences, + minLines: 1, + maxLines: 3, + onChanged: onTextChanged, + style: textFieldTextStyle, + decoration: InputDecoration( + hintText: messageBarHintText, + hintMaxLines: 1, + contentPadding: const EdgeInsets.symmetric( + horizontal: 8.0, vertical: 10), + hintStyle: messageBarHintStyle, + fillColor: Colors.white, + filled: true, + enabledBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(30.0), + borderSide: const BorderSide( + color: Colors.white, + width: 0.2, + ), + ), + focusedBorder: OutlineInputBorder( + borderRadius: BorderRadius.circular(30.0), + borderSide: const BorderSide( + color: Colors.black26, + width: 0.2, + ), + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 16), + child: InkWell( + child: Icon( + Icons.send, + color: sendButtonColor, + size: 24, + ), + onTap: () { + if (_textController.text.trim() != '') { + if (onSend != null) { + onSend!(_textController.text.trim()); + } + _textController.text = ''; } - _textController.text = ''; - } - }, + }, + ), ), - ), - ], + ], + ), ), - ), - ], + ], ), ); } diff --git a/lib/message_bars/message_bar_style.dart b/lib/message_bars/message_bar_style.dart index 5b8a17b..314b4c6 100644 --- a/lib/message_bars/message_bar_style.dart +++ b/lib/message_bars/message_bar_style.dart @@ -12,7 +12,7 @@ class MessageBarStyle { final InputBorder focusedBorder; /// Keyboard type for the input field. - final TextInputType textInputType; + final TextInputType keyboardType; /// Text capitalization behavior. final TextCapitalization textCapitalization; @@ -41,7 +41,7 @@ class MessageBarStyle { width: 0.2, ), ), - this.textInputType = TextInputType.multiline, + this.keyboardType = TextInputType.multiline, this.textCapitalization = TextCapitalization.sentences, this.contentPadding = const EdgeInsets.symmetric(horizontal: 8.0, vertical: 10), From 55759e5059ad2280e48977af049192c19534d252 Mon Sep 17 00:00:00 2001 From: Manuel Rasinger Date: Tue, 31 Mar 2026 11:26:01 +0200 Subject: [PATCH 3/4] feat: use message bar style --- lib/message_bars/message_bar.dart | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/lib/message_bars/message_bar.dart b/lib/message_bars/message_bar.dart index e74f2b4..3978db9 100644 --- a/lib/message_bars/message_bar.dart +++ b/lib/message_bars/message_bar.dart @@ -153,8 +153,8 @@ class MessageBar extends StatelessWidget { Expanded( child: TextField( controller: _textController, - keyboardType: TextInputType.multiline, - textCapitalization: TextCapitalization.sentences, + keyboardType: messageBarStyle.keyboardType, + textCapitalization: messageBarStyle.textCapitalization, minLines: 1, maxLines: 3, onChanged: onTextChanged, @@ -162,32 +162,19 @@ class MessageBar extends StatelessWidget { decoration: InputDecoration( hintText: messageBarHintText, hintMaxLines: 1, - contentPadding: const EdgeInsets.symmetric( - horizontal: 8.0, vertical: 10), + contentPadding: messageBarStyle.contentPadding, hintStyle: messageBarHintStyle, - fillColor: Colors.white, + fillColor: messageBarStyle.fillColor, filled: true, - enabledBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(30.0), - borderSide: const BorderSide( - color: Colors.white, - width: 0.2, - ), - ), - focusedBorder: OutlineInputBorder( - borderRadius: BorderRadius.circular(30.0), - borderSide: const BorderSide( - color: Colors.black26, - width: 0.2, - ), - ), + enabledBorder: messageBarStyle.enabledBorder, + focusedBorder: messageBarStyle.focusedBorder, ), ), ), Padding( padding: const EdgeInsets.only(left: 16), child: InkWell( - child: Icon( + child: sendButton ?? Icon( Icons.send, color: sendButtonColor, size: 24, From b6e6e7896a20718b9be8f4e3d91c75082793db3b Mon Sep 17 00:00:00 2001 From: Manuel Rasinger Date: Tue, 31 Mar 2026 13:39:27 +0200 Subject: [PATCH 4/4] feat: also include min- and maxLine --- lib/message_bars/message_bar.dart | 4 ++-- lib/message_bars/message_bar_style.dart | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/message_bars/message_bar.dart b/lib/message_bars/message_bar.dart index 3978db9..b2ccc3b 100644 --- a/lib/message_bars/message_bar.dart +++ b/lib/message_bars/message_bar.dart @@ -155,8 +155,8 @@ class MessageBar extends StatelessWidget { controller: _textController, keyboardType: messageBarStyle.keyboardType, textCapitalization: messageBarStyle.textCapitalization, - minLines: 1, - maxLines: 3, + minLines: messageBarStyle.minLines, + maxLines: messageBarStyle.maxLines, onChanged: onTextChanged, style: textFieldTextStyle, decoration: InputDecoration( diff --git a/lib/message_bars/message_bar_style.dart b/lib/message_bars/message_bar_style.dart index 314b4c6..eec75f3 100644 --- a/lib/message_bars/message_bar_style.dart +++ b/lib/message_bars/message_bar_style.dart @@ -23,6 +23,12 @@ class MessageBarStyle { /// Background color of the input field. final Color fillColor; + /// minimum number of lines of the input field. + final int minLines; + + /// maximum number of lines of the input field. + final int maxLines; + /// Creates a `MessageBarStyle`. /// /// All parameters are optional and default to the standard `MessageBar` style. @@ -46,5 +52,7 @@ class MessageBarStyle { this.contentPadding = const EdgeInsets.symmetric(horizontal: 8.0, vertical: 10), this.fillColor = Colors.white, + this.minLines = 1, + this.maxLines = 3, }); }