Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/stream_chat_flutter/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

✅ Added

- Added `bottom` and `bottomOpacity` to the `StreamChannelHeader` widget.
- Added `StreamChat.maybeOf()` method for safe context access in async operations.

🐞 Fixed
Expand Down
17 changes: 15 additions & 2 deletions packages/stream_chat_flutter/lib/src/channel/channel_header.dart
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,11 @@ class StreamChannelHeader extends StatelessWidget
this.centerTitle,
this.leading,
this.actions,
this.bottom,
this.backgroundColor,
this.elevation = 1,
}) : preferredSize = const Size.fromHeight(kToolbarHeight);
this.bottomOpacity = 1,
});

/// Whether to show the leading back button
///
Expand Down Expand Up @@ -106,6 +108,9 @@ class StreamChannelHeader extends StatelessWidget
/// Leading widget
final Widget? leading;

/// The bottom widget
final PreferredSizeWidget? bottom;

/// {@macro flutter.material.appbar.actions}
///
/// The [StreamChannelAvatar] is shown by default
Expand All @@ -117,8 +122,14 @@ class StreamChannelHeader extends StatelessWidget
/// The elevation for this [StreamChannelHeader].
final double elevation;

/// The opacity of the bottom widget.
final double bottomOpacity;

@override
final Size preferredSize;
Size get preferredSize {
final bottomHeight = bottom?.preferredSize.height ?? 0;
return Size.fromHeight(kToolbarHeight + bottomHeight);
}

@override
Widget build(BuildContext context) {
Expand Down Expand Up @@ -169,6 +180,8 @@ class StreamChannelHeader extends StatelessWidget
: SystemUiOverlayStyle.dark,
elevation: elevation,
leading: leadingWidget,
bottom: bottom,
bottomOpacity: bottomOpacity,
backgroundColor: backgroundColor ?? channelHeaderTheme.color,
actions: actions ??
<Widget>[
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:alchemist/alchemist.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
Expand Down Expand Up @@ -476,4 +477,73 @@ void main() {
expect(titleTapped, true);
},
);

goldenTest(
'golden test for StreamChannelHeader with bottom widget',
fileName: 'channel_header_bottom_widget',
constraints: const BoxConstraints.tightFor(width: 300, height: 60),
builder: () {
final client = MockClient();
final clientState = MockClientState();
final channel = MockChannel();
final channelState = MockChannelState();
final user = OwnUser(id: 'user-id');
final lastMessageAt = DateTime.parse('2020-06-22 12:00:00');

when(() => client.state).thenReturn(clientState);
when(() => clientState.currentUser).thenReturn(user);
when(() => clientState.currentUserStream)
.thenAnswer((_) => Stream.value(user));
when(() => channel.lastMessageAt).thenReturn(lastMessageAt);
when(() => channel.state).thenReturn(channelState);
when(() => channel.client).thenReturn(client);
when(() => channel.isMuted).thenReturn(false);
when(() => channel.isMutedStream).thenAnswer((i) => Stream.value(false));
when(() => channel.nameStream).thenAnswer((_) => Stream.value('test'));
when(() => channel.name).thenReturn('test');
when(() => channel.imageStream)
.thenAnswer((i) => Stream.value('https://bit.ly/321RmWb'));
when(() => channel.image).thenReturn('https://bit.ly/321RmWb');
when(() => channelState.unreadCount).thenReturn(1);
when(() => client.wsConnectionStatusStream)
.thenAnswer((_) => Stream.value(ConnectionStatus.connected));
when(() => channelState.unreadCountStream)
.thenAnswer((i) => Stream.value(1));
when(() => clientState.totalUnreadCount).thenAnswer((i) => 1);
when(() => clientState.totalUnreadCountStream)
.thenAnswer((i) => Stream.value(1));
when(() => channelState.membersStream).thenAnswer(
(i) => Stream.value([
Member(
userId: 'user-id',
user: User(id: 'user-id'),
)
]),
);
when(() => channelState.members).thenReturn([
Member(
userId: 'user-id',
user: User(id: 'user-id'),
),
]);

return MaterialAppWrapper(
home: StreamChat(
client: client,
connectivityStream: Stream.value([ConnectivityResult.wifi]),
child: StreamChannel(
channel: channel,
child: const Scaffold(
body: StreamChannelHeader(
bottom: PreferredSize(
preferredSize: Size.fromHeight(1),
child: Divider(height: 1, color: Colors.red),
),
),
),
),
),
);
},
);
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.