Skip to content

Commit b59482d

Browse files
authored
Merge pull request GetStream#60 from GetStream/fix/channel-list-scroll-performance
fix(ui): channel list performance
2 parents cc4fd93 + 95013f7 commit b59482d

File tree

2 files changed

+138
-131
lines changed

2 files changed

+138
-131
lines changed

packages/stream_chat_v1/lib/channel_list.dart

Lines changed: 133 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:example/localizations.dart';
44
import 'package:example/routes/routes.dart';
55
import 'package:example/search_text_field.dart';
66
import 'package:flutter/material.dart';
7+
import 'package:flutter/rendering.dart';
78
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
89

910
import 'channel_page.dart';
@@ -16,6 +17,8 @@ class ChannelList extends StatefulWidget {
1617
}
1718

1819
class _ChannelList extends State<ChannelList> {
20+
ScrollController _scrollController = ScrollController();
21+
1922
TextEditingController? _controller;
2023

2124
String _channelQuery = '';
@@ -46,6 +49,7 @@ class _ChannelList extends State<ChannelList> {
4649
void dispose() {
4750
_controller?.removeListener(_channelQueryListener);
4851
_controller?.dispose();
52+
_scrollController.dispose();
4953
super.dispose();
5054
}
5155

@@ -61,145 +65,144 @@ class _ChannelList extends State<ChannelList> {
6165
}
6266
return true;
6367
},
64-
child: NestedScrollView(
65-
floatHeaderSlivers: true,
66-
headerSliverBuilder: (_, __) => [
67-
SliverToBoxAdapter(
68-
child: SearchTextField(
69-
controller: _controller,
70-
showCloseButton: _isSearchActive,
71-
hintText: AppLocalizations.of(context).search,
68+
child: NotificationListener<ScrollUpdateNotification>(
69+
onNotification: (ScrollNotification scrollInfo) {
70+
if (_scrollController.position.userScrollDirection ==
71+
ScrollDirection.reverse) {
72+
FocusScope.of(context).unfocus();
73+
}
74+
return true;
75+
},
76+
child: NestedScrollView(
77+
controller: _scrollController,
78+
floatHeaderSlivers: false,
79+
headerSliverBuilder: (_, __) => [
80+
SliverToBoxAdapter(
81+
child: SearchTextField(
82+
controller: _controller,
83+
showCloseButton: _isSearchActive,
84+
hintText: AppLocalizations.of(context).search,
85+
),
7286
),
73-
),
74-
],
75-
body: AnimatedSwitcher(
76-
duration: const Duration(milliseconds: 350),
77-
child: GestureDetector(
78-
behavior: HitTestBehavior.opaque,
79-
onPanDown: (_) => FocusScope.of(context).unfocus(),
80-
child: _isSearchActive
81-
? MessageSearchBloc(
82-
child: MessageSearchListView(
83-
showErrorTile: true,
84-
messageQuery: _channelQuery,
85-
filters: Filter.in_('members', [user!.id]),
86-
sortOptions: [
87-
SortOption(
88-
'created_at',
89-
direction: SortOption.ASC,
90-
),
91-
],
92-
pullToRefresh: false,
93-
limit: 20,
94-
emptyBuilder: (_) {
95-
return LayoutBuilder(
96-
builder: (context, viewportConstraints) {
97-
return SingleChildScrollView(
98-
physics: AlwaysScrollableScrollPhysics(),
99-
child: ConstrainedBox(
100-
constraints: BoxConstraints(
101-
minHeight: viewportConstraints.maxHeight,
102-
),
103-
child: Center(
104-
child: Column(
105-
children: [
106-
Padding(
107-
padding: const EdgeInsets.all(24),
108-
child: StreamSvgIcon.search(
109-
size: 96,
110-
color: Colors.grey,
111-
),
112-
),
113-
Text(
114-
AppLocalizations.of(context).noResults,
115-
),
116-
],
87+
],
88+
body: _isSearchActive
89+
? MessageSearchListView(
90+
showErrorTile: true,
91+
messageQuery: _channelQuery,
92+
filters: Filter.in_('members', [user!.id]),
93+
sortOptions: [
94+
SortOption(
95+
'created_at',
96+
direction: SortOption.ASC,
97+
),
98+
],
99+
pullToRefresh: false,
100+
limit: 30,
101+
emptyBuilder: (_) {
102+
return LayoutBuilder(
103+
builder: (context, viewportConstraints) {
104+
return SingleChildScrollView(
105+
physics: AlwaysScrollableScrollPhysics(),
106+
child: ConstrainedBox(
107+
constraints: BoxConstraints(
108+
minHeight: viewportConstraints.maxHeight,
109+
),
110+
child: Center(
111+
child: Column(
112+
children: [
113+
Padding(
114+
padding: const EdgeInsets.all(24),
115+
child: StreamSvgIcon.search(
116+
size: 96,
117+
color: Colors.grey,
118+
),
119+
),
120+
Text(
121+
AppLocalizations.of(context).noResults,
117122
),
118-
),
123+
],
119124
),
120-
);
121-
},
122-
);
123-
},
124-
onItemTap: (messageResponse) async {
125-
FocusScope.of(context).requestFocus(FocusNode());
126-
final client = StreamChat.of(context).client;
127-
final message = messageResponse.message;
128-
final channel = client.channel(
129-
messageResponse.channel!.type,
130-
id: messageResponse.channel!.id,
131-
);
132-
if (channel.state == null) {
133-
await channel.watch();
134-
}
135-
Navigator.pushNamed(
136-
context,
137-
Routes.CHANNEL_PAGE,
138-
arguments: ChannelPageArgs(
139-
channel: channel,
140-
initialMessage: message,
125+
),
141126
),
142127
);
143128
},
144-
),
145-
)
146-
: ChannelsBloc(
147-
child: ChannelListView(
148-
onChannelTap: (channel, _) {
149-
Navigator.pushNamed(
150-
context,
151-
Routes.CHANNEL_PAGE,
152-
arguments: ChannelPageArgs(
129+
);
130+
},
131+
onItemTap: (messageResponse) async {
132+
FocusScope.of(context).requestFocus(FocusNode());
133+
final client = StreamChat.of(context).client;
134+
final message = messageResponse.message;
135+
final channel = client.channel(
136+
messageResponse.channel!.type,
137+
id: messageResponse.channel!.id,
138+
);
139+
if (channel.state == null) {
140+
await channel.watch();
141+
}
142+
Navigator.pushNamed(
143+
context,
144+
Routes.CHANNEL_PAGE,
145+
arguments: ChannelPageArgs(
146+
channel: channel,
147+
initialMessage: message,
148+
),
149+
);
150+
},
151+
)
152+
: ChannelListView(
153+
onChannelTap: (channel, _) {
154+
Navigator.pushNamed(
155+
context,
156+
Routes.CHANNEL_PAGE,
157+
arguments: ChannelPageArgs(
158+
channel: channel,
159+
),
160+
);
161+
},
162+
onStartChatPressed: () {
163+
Navigator.pushNamed(context, Routes.NEW_CHAT);
164+
},
165+
swipeToAction: true,
166+
filter: Filter.in_('members', [user!.id]),
167+
presence: true,
168+
limit: 30,
169+
onViewInfoTap: (channel) {
170+
Navigator.pop(context);
171+
if (channel.memberCount == 2 && channel.isDistinct) {
172+
Navigator.push(
173+
context,
174+
MaterialPageRoute(
175+
builder: (context) => StreamChannel(
153176
channel: channel,
154-
),
155-
);
156-
},
157-
onStartChatPressed: () {
158-
Navigator.pushNamed(context, Routes.NEW_CHAT);
159-
},
160-
swipeToAction: true,
161-
filter: Filter.in_('members', [user!.id]),
162-
presence: true,
163-
limit: 20,
164-
onViewInfoTap: (channel) {
165-
Navigator.pop(context);
166-
if (channel.memberCount == 2 && channel.isDistinct) {
167-
Navigator.push(
168-
context,
169-
MaterialPageRoute(
170-
builder: (context) => StreamChannel(
171-
channel: channel,
172-
child: ChatInfoScreen(
173-
messageTheme: StreamChatTheme.of(context)
174-
.ownMessageTheme,
175-
user: channel.state!.members
176-
.where((m) =>
177-
m.userId !=
178-
channel.client.state.currentUser!.id)
179-
.first
180-
.user,
181-
),
182-
),
177+
child: ChatInfoScreen(
178+
messageTheme:
179+
StreamChatTheme.of(context).ownMessageTheme,
180+
user: channel.state!.members
181+
.where((m) =>
182+
m.userId !=
183+
channel.client.state.currentUser!.id)
184+
.first
185+
.user,
183186
),
184-
);
185-
} else {
186-
Navigator.push(
187-
context,
188-
MaterialPageRoute(
189-
builder: (context) => StreamChannel(
190-
channel: channel,
191-
child: GroupInfoScreen(
192-
messageTheme: StreamChatTheme.of(context)
193-
.ownMessageTheme,
194-
),
195-
),
187+
),
188+
),
189+
);
190+
} else {
191+
Navigator.push(
192+
context,
193+
MaterialPageRoute(
194+
builder: (context) => StreamChannel(
195+
channel: channel,
196+
child: GroupInfoScreen(
197+
messageTheme:
198+
StreamChatTheme.of(context).ownMessageTheme,
196199
),
197-
);
198-
}
199-
},
200-
),
201-
),
202-
),
200+
),
201+
),
202+
);
203+
}
204+
},
205+
),
203206
),
204207
),
205208
);

packages/stream_chat_v1/lib/channel_list_page.dart

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,11 @@ class _ChannelListPageState extends State<ChannelListPage> {
100100
body: IndexedStack(
101101
index: _currentIndex,
102102
children: [
103-
ChannelList(),
103+
ChannelsBloc(
104+
child: MessageSearchBloc(
105+
child: ChannelList(),
106+
),
107+
),
104108
UserMentionsPage(),
105109
],
106110
),

0 commit comments

Comments
 (0)