Skip to content

Commit

Permalink
feat(ui): Extract StreamMediaAttachmentBuilder widget (#1816)
Browse files Browse the repository at this point in the history
* feat(ui):Extract_media_attachment_builder_widget

* tests

* changelog

* format

---------

Co-authored-by: Kanat Kiialbaev <[email protected]>
Co-authored-by: Deven Joshi <[email protected]>
  • Loading branch information
3 people authored Jun 10, 2024
1 parent 461986b commit 5ea210e
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 43 deletions.
7 changes: 6 additions & 1 deletion packages/stream_chat_flutter/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## Upcoming

✅ Added

- Added `StreamMediaAttachmentBuilder` widget to show media attachments in a message.

## 7.2.1

✅ Added
Expand Down Expand Up @@ -46,7 +52,6 @@ Added Mark as Unread option to `StreamMessageWidget` context menu that will show
- Removed double focus on `StreamMessageInput` when `focusNode` is provided for web and desktop.
- Optionally call `onThreadTap` in `BottomRow` to avoid `Null check operator used on a null value`


## 7.0.1

🐞 Fixed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,48 +261,9 @@ class MessageInputMediaAttachments extends StatelessWidget {
return builder(context, attachment, onRemovePressed);
}

final colorTheme = StreamChatTheme.of(context).colorTheme;
final shape = RoundedRectangleBorder(
side: BorderSide(
color: colorTheme.borders,
strokeAlign: BorderSide.strokeAlignOutside,
),
borderRadius: BorderRadius.circular(14),
);

return Container(
key: Key(attachment.id),
clipBehavior: Clip.hardEdge,
decoration: ShapeDecoration(shape: shape),
child: AspectRatio(
aspectRatio: 1,
child: Stack(
alignment: Alignment.center,
children: <Widget>[
StreamMediaAttachmentThumbnail(
media: attachment,
width: double.infinity,
height: double.infinity,
fit: BoxFit.cover,
),
if (attachment.type == AttachmentType.video)
Positioned(
left: 8,
bottom: 8,
child: StreamSvgIcon.videoCall(),
),
Positioned(
top: 8,
right: 8,
child: RemoveAttachmentButton(
onPressed: onRemovePressed != null
? () => onRemovePressed!(attachment)
: null,
),
),
],
),
),
return StreamMediaAttachmentBuilder(
attachment: attachment,
onRemovePressed: onRemovePressed,
);
},
).insertBetween(const SizedBox(width: 8)),
Expand All @@ -311,6 +272,66 @@ class MessageInputMediaAttachments extends StatelessWidget {
}
}

/// Widget used to display a media type attachment item.
class StreamMediaAttachmentBuilder extends StatelessWidget {
/// Creates a new media attachment item.
const StreamMediaAttachmentBuilder(
{super.key, required this.attachment, this.onRemovePressed});

/// The media attachment to display.
final Attachment attachment;

/// Callback called when the remove button is pressed.
final ValueSetter<Attachment>? onRemovePressed;

@override
Widget build(BuildContext context) {
final colorTheme = StreamChatTheme.of(context).colorTheme;
final shape = RoundedRectangleBorder(
side: BorderSide(
color: colorTheme.borders,
strokeAlign: BorderSide.strokeAlignOutside,
),
borderRadius: BorderRadius.circular(14),
);

return Container(
key: Key(attachment.id),
clipBehavior: Clip.hardEdge,
decoration: ShapeDecoration(shape: shape),
child: AspectRatio(
aspectRatio: 1,
child: Stack(
alignment: Alignment.center,
children: <Widget>[
StreamMediaAttachmentThumbnail(
media: attachment,
width: double.infinity,
height: double.infinity,
fit: BoxFit.cover,
),
if (attachment.type == AttachmentType.video)
Positioned(
left: 8,
bottom: 8,
child: StreamSvgIcon.videoCall(),
),
Positioned(
top: 8,
right: 8,
child: RemoveAttachmentButton(
onPressed: onRemovePressed != null
? () => onRemovePressed!(attachment)
: null,
),
),
],
),
),
);
}
}

/// Material Button used for removing attachments.
class RemoveAttachmentButton extends StatelessWidget {
/// Creates a new remove attachment button.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -190,4 +190,54 @@ void main() {
},
);
});

group('StreamMediaAttachmentBuilder tests', () {
testWidgets(
'StreamMediaAttachmentBuilder should render media attachment',
(WidgetTester tester) async {
final attachment = Attachment(type: 'media', id: 'media1');

await tester.pumpWidget(
wrapWithStreamChat(
StreamMediaAttachmentBuilder(
attachment: attachment,
onRemovePressed: (attachment) {},
),
),
);

// Expect one media attachment widget
expect(find.byType(StreamMediaAttachmentBuilder), findsOneWidget);
},
);

testWidgets(
'StreamMediaAttachmentBuilder should call onRemovePressed callback',
(WidgetTester tester) async {
Attachment? removedAttachment;

final attachment = Attachment(type: 'file', id: 'file1');

await tester.pumpWidget(
wrapWithStreamChat(
StreamMediaAttachmentBuilder(
attachment: attachment,
onRemovePressed: (attachment) {
removedAttachment = attachment;
},
),
),
);

final removeButton = find.byType(RemoveAttachmentButton);

// Tap the remove button
await tester.tap(removeButton);
await tester.pump();

// Expect the onRemovePressed callback to be called with the attachment
expect(removedAttachment, attachment);
},
);
});
}

0 comments on commit 5ea210e

Please sign in to comment.