Skip to content

Commit d208d02

Browse files
committed
fix: mic icon size and ripple
1 parent 713af8a commit d208d02

File tree

3 files changed

+57
-43
lines changed

3 files changed

+57
-43
lines changed

packages/stream_chat_flutter/lib/src/message_input/audio_recorder/stream_audio_recorder.dart

+47-31
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,6 @@ class StreamAudioRecorderButton extends StatelessWidget {
8989

9090
@override
9191
Widget build(BuildContext context) {
92-
final theme = StreamChatTheme.of(context);
93-
9492
final isRecording = recordState is! RecordStateIdle;
9593
final isLocked = isRecording && recordState is! RecordStateRecordingHold;
9694

@@ -128,13 +126,9 @@ class StreamAudioRecorderButton extends StatelessWidget {
128126
},
129127
child: StreamAudioRecorderBuilder(
130128
state: recordState,
131-
button: StreamSvgIcon(
132-
icon: StreamSvgIcons.mic,
133-
size: kDefaultMessageInputIconSize,
134-
color: switch (isRecording) {
135-
true => theme.colorTheme.accentPrimary,
136-
false => theme.colorTheme.textLowEmphasis,
137-
},
129+
button: StreamMessageInputIconButton(
130+
onPressed: () {}, // Allows showing ripple effect on tap.
131+
icon: const StreamSvgIcon(icon: StreamSvgIcons.mic),
138132
),
139133
builder: (context, state, recordButton) => switch (state) {
140134
// Show only the record button if the recording is not in progress.
@@ -188,16 +182,23 @@ class RecordStateIdleContent extends StatelessWidget {
188182

189183
@override
190184
Widget build(BuildContext context) {
185+
final theme = StreamChatTheme.of(context);
186+
187+
final child = IconTheme(
188+
data: IconThemeData(color: theme.colorTheme.textLowEmphasis),
189+
child: recordButton,
190+
);
191+
191192
final info = state.message;
192-
if (info == null || info.isEmpty) return recordButton;
193+
if (info == null || info.isEmpty) return child;
193194

194195
return PortalTarget(
195196
anchor: const Aligned(
196197
target: Alignment.topRight,
197198
follower: Alignment.bottomRight,
198199
),
199200
portalFollower: HoldToRecordInfoTooltip(message: info),
200-
child: recordButton,
201+
child: child,
201202
);
202203
}
203204
}
@@ -246,7 +247,7 @@ class RecordStateHoldRecordingContent extends StatelessWidget {
246247
// Show the swipe to lock button once the recording starts.
247248
visible: recordingTime.inSeconds > 0,
248249
anchor: Aligned(
249-
offset: Offset(0, dragOffset.dy - 16),
250+
offset: Offset(4, dragOffset.dy - 16),
250251
target: Alignment.topRight,
251252
follower: Alignment.bottomRight,
252253
),
@@ -257,19 +258,25 @@ class RecordStateHoldRecordingContent extends StatelessWidget {
257258
),
258259
child: Row(
259260
children: [
260-
PlaybackTimerIndicator(duration: recordingTime),
261+
IgnorePointer(
262+
child: PlaybackTimerIndicator(duration: recordingTime),
263+
),
261264
Expanded(
262-
child: SlideToCancelIndicator(
263-
progress: cancelProgress.toDouble(),
265+
child: IgnorePointer(
266+
child: SlideToCancelIndicator(
267+
progress: cancelProgress.toDouble(),
268+
),
264269
),
265270
),
266-
Container(
267-
padding: const EdgeInsets.all(8),
271+
DecoratedBox(
268272
decoration: BoxDecoration(
269273
shape: BoxShape.circle,
270274
color: theme.colorTheme.inputBg,
271275
),
272-
child: recordButton,
276+
child: IconTheme(
277+
data: IconThemeData(color: theme.colorTheme.accentPrimary),
278+
child: recordButton,
279+
),
273280
),
274281
].insertBetween(const SizedBox(width: 8)),
275282
),
@@ -316,7 +323,7 @@ class RecordStateLockedRecordingContent extends StatelessWidget {
316323

317324
return PortalTarget(
318325
anchor: const Aligned(
319-
offset: Offset(0, -16),
326+
offset: Offset(4, -16),
320327
target: Alignment.topRight,
321328
follower: Alignment.bottomRight,
322329
),
@@ -335,7 +342,7 @@ class RecordStateLockedRecordingContent extends StatelessWidget {
335342
const SizedBox(width: 8),
336343
Expanded(
337344
child: SizedBox(
338-
height: 28,
345+
height: kDefaultMessageInputIconSize,
339346
child: StreamAudioWaveform(
340347
limit: 50,
341348
waveform: state.waveform,
@@ -429,7 +436,7 @@ class _RecordStateStoppedContentState extends State<RecordStateStoppedContent> {
429436

430437
return PortalTarget(
431438
anchor: const Aligned(
432-
offset: Offset(0, -16),
439+
offset: Offset(4, -16),
433440
target: Alignment.topRight,
434441
follower: Alignment.bottomRight,
435442
),
@@ -505,7 +512,7 @@ class _RecordStateStoppedContentState extends State<RecordStateStoppedContent> {
505512
);
506513
},
507514
),
508-
const SizedBox(height: 8),
515+
const SizedBox(height: 2),
509516
Row(
510517
mainAxisAlignment: MainAxisAlignment.spaceBetween,
511518
children: [
@@ -619,15 +626,21 @@ class PlaybackControlButton extends StatelessWidget {
619626
TrackState.paused => onPlay,
620627
},
621628
icon: switch (state) {
622-
TrackState.loading => SizedBox.fromSize(
623-
size: const Size.square(24 - /* Padding */ 2),
624-
child: Center(
625-
child: CircularProgressIndicator.adaptive(
626-
valueColor: AlwaysStoppedAnimation(
627-
theme.colorTheme.accentPrimary,
629+
TrackState.loading => Builder(
630+
builder: (context) {
631+
final iconTheme = IconTheme.of(context);
632+
return SizedBox.fromSize(
633+
size: Size.square(iconTheme.size!),
634+
child: Padding(
635+
padding: const EdgeInsets.all(8),
636+
child: CircularProgressIndicator.adaptive(
637+
valueColor: AlwaysStoppedAnimation(
638+
theme.colorTheme.accentPrimary,
639+
),
640+
),
628641
),
629-
),
630-
),
642+
);
643+
},
631644
),
632645
TrackState.idle => const StreamSvgIcon(icon: StreamSvgIcons.play),
633646
TrackState.paused => const StreamSvgIcon(icon: StreamSvgIcons.play),
@@ -884,7 +897,10 @@ class HoldToRecordInfoTooltip extends StatelessWidget {
884897
Widget build(BuildContext context) {
885898
final theme = StreamChatTheme.of(context);
886899

887-
const arrowSize = Size(kDefaultMessageInputIconSize / 2, 6);
900+
const recordButtonWidth = kDefaultMessageInputIconSize +
901+
kDefaultMessageInputIconPadding * 2; // right, left padding.
902+
903+
const arrowSize = Size(recordButtonWidth / 2, 6);
888904

889905
return Padding(
890906
padding: EdgeInsets.only(bottom: arrowSize.height),

packages/stream_chat_flutter/lib/src/message_input/stream_message_input.dart

+4-2
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ class StreamMessageInput extends StatefulWidget {
113113
this.disableAttachments = false,
114114
this.messageInputController,
115115
this.actionsBuilder,
116-
this.spaceBetweenActions = 8,
116+
this.spaceBetweenActions = 0,
117117
this.actionsLocation = ActionsLocation.left,
118118
this.attachmentListBuilder,
119119
this.fileAttachmentListBuilder,
@@ -787,7 +787,9 @@ class StreamMessageInputState extends State<StreamMessageInput>
787787
if (!_commandEnabled &&
788788
widget.actionsLocation == ActionsLocation.left)
789789
_buildExpandActionsButton(context),
790+
const SizedBox(width: 4),
790791
Expanded(child: _buildTextInput(context)),
792+
const SizedBox(width: 4),
791793
if (!_commandEnabled &&
792794
widget.actionsLocation == ActionsLocation.right)
793795
_buildExpandActionsButton(context),
@@ -835,7 +837,7 @@ class StreamMessageInputState extends State<StreamMessageInput>
835837
},
836838
),
837839
),
838-
].insertBetween(const SizedBox(width: 8)),
840+
],
839841
);
840842
},
841843
);

packages/stream_chat_flutter/lib/src/message_input/stream_message_input_icon_button.dart

+6-10
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ import 'package:flutter/material.dart';
33
/// The default size for the icon inside the message input icon button.
44
const double kDefaultMessageInputIconSize = 32;
55

6+
/// The default padding around the icon inside the message input icon button.
7+
const double kDefaultMessageInputIconPadding = 4;
8+
69
/// {@template streamMessageInputIconButton}
710
/// A customized [IconButton] for the message input.
811
///
@@ -18,8 +21,7 @@ class StreamMessageInputIconButton extends StatelessWidget {
1821
this.color,
1922
this.disabledColor,
2023
this.iconSize = kDefaultMessageInputIconSize,
21-
this.padding = EdgeInsets.zero,
22-
this.tapTargetSize = MaterialTapTargetSize.shrinkWrap,
24+
this.padding = const EdgeInsets.all(kDefaultMessageInputIconPadding),
2325
});
2426

2527
/// The icon to display inside the button.
@@ -51,12 +53,6 @@ class StreamMessageInputIconButton extends StatelessWidget {
5153
/// If this is set to null, the button will be disabled.
5254
final VoidCallback? onPressed;
5355

54-
/// Configures the minimum size of the area within which the button may be
55-
/// pressed.
56-
///
57-
/// Defaults to [MaterialTapTargetSize.shrinkWrap].
58-
final MaterialTapTargetSize tapTargetSize;
59-
6056
@override
6157
Widget build(BuildContext context) {
6258
return IconButton(
@@ -67,8 +63,8 @@ class StreamMessageInputIconButton extends StatelessWidget {
6763
onPressed: onPressed,
6864
padding: padding,
6965
style: ButtonStyle(
70-
tapTargetSize: tapTargetSize,
71-
minimumSize: WidgetStateProperty.all(Size(iconSize, iconSize)),
66+
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
67+
minimumSize: WidgetStateProperty.all(Size.square(iconSize)),
7268
),
7369
);
7470
}

0 commit comments

Comments
 (0)