@@ -60,6 +60,7 @@ class ChannelListView extends StatefulWidget {
|
||||
this.channelPreviewBuilder,
|
||||
this.errorBuilder,
|
||||
this.onImageTap,
|
||||
this.pullToRefresh = true,
|
||||
}) : super(key: key);
|
||||
|
||||
/// The builder that will be used in case of error
|
||||
@@ -105,6 +106,9 @@ class ChannelListView extends StatefulWidget {
|
||||
/// The function called when the image is tapped
|
||||
final Function(Channel) onImageTap;
|
||||
|
||||
/// Set it to false to disable the pull-to-refresh widget
|
||||
final bool pullToRefresh;
|
||||
|
||||
@override
|
||||
_ChannelListViewState createState() => _ChannelListViewState();
|
||||
}
|
||||
@@ -115,105 +119,115 @@ class _ChannelListViewState extends State<ChannelListView>
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final channelsProvider = ChannelsBloc.of(context);
|
||||
final channelsBloc = ChannelsBloc.of(context);
|
||||
|
||||
if (!widget.pullToRefresh) {
|
||||
return _buildListView(channelsBloc);
|
||||
}
|
||||
|
||||
return RefreshIndicator(
|
||||
onRefresh: () async {
|
||||
return channelsProvider.queryChannels(
|
||||
return channelsBloc.queryChannels(
|
||||
filter: widget.filter,
|
||||
sortOptions: widget.sort,
|
||||
paginationParams: widget.pagination,
|
||||
options: widget.options,
|
||||
);
|
||||
},
|
||||
child: StreamBuilder<List<Channel>>(
|
||||
stream: channelsProvider.channelsStream,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasError) {
|
||||
if (snapshot.error is Error) {
|
||||
print((snapshot.error as Error).stackTrace);
|
||||
}
|
||||
child: _buildListView(channelsBloc),
|
||||
);
|
||||
}
|
||||
|
||||
if (widget.errorBuilder != null) {
|
||||
return widget.errorBuilder(snapshot.error);
|
||||
}
|
||||
StreamBuilder<List<Channel>> _buildListView(
|
||||
ChannelsBlocState channelsBlocState,
|
||||
) {
|
||||
return StreamBuilder<List<Channel>>(
|
||||
stream: channelsBlocState.channelsStream,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasError) {
|
||||
if (snapshot.error is Error) {
|
||||
print((snapshot.error as Error).stackTrace);
|
||||
}
|
||||
|
||||
var message = snapshot.error.toString();
|
||||
if (snapshot.error is DioError) {
|
||||
final dioError = snapshot.error as DioError;
|
||||
if (dioError.type == DioErrorType.RESPONSE) {
|
||||
message = dioError.message;
|
||||
} else {
|
||||
message = 'Check your connection and retry';
|
||||
}
|
||||
if (widget.errorBuilder != null) {
|
||||
return widget.errorBuilder(snapshot.error);
|
||||
}
|
||||
|
||||
var message = snapshot.error.toString();
|
||||
if (snapshot.error is DioError) {
|
||||
final dioError = snapshot.error as DioError;
|
||||
if (dioError.type == DioErrorType.RESPONSE) {
|
||||
message = dioError.message;
|
||||
} else {
|
||||
message = 'Check your connection and retry';
|
||||
}
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
WidgetSpan(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
right: 2.0,
|
||||
),
|
||||
child: Icon(Icons.error_outline),
|
||||
}
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text.rich(
|
||||
TextSpan(
|
||||
children: [
|
||||
WidgetSpan(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
right: 2.0,
|
||||
),
|
||||
child: Icon(Icons.error_outline),
|
||||
),
|
||||
TextSpan(text: 'Error loading channels'),
|
||||
],
|
||||
),
|
||||
style: Theme.of(context).textTheme.headline6,
|
||||
),
|
||||
TextSpan(text: 'Error loading channels'),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 16.0,
|
||||
),
|
||||
child: Text(message),
|
||||
style: Theme.of(context).textTheme.headline6,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 16.0,
|
||||
),
|
||||
FlatButton(
|
||||
onPressed: () {
|
||||
channelsProvider.queryChannels(
|
||||
filter: widget.filter,
|
||||
sortOptions: widget.sort,
|
||||
paginationParams: widget.pagination,
|
||||
options: widget.options,
|
||||
);
|
||||
},
|
||||
child: Text('Retry'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (!snapshot.hasData) {
|
||||
return Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
|
||||
final channels = snapshot.data;
|
||||
return ListView.custom(
|
||||
physics: AlwaysScrollableScrollPhysics(),
|
||||
controller: _scrollController,
|
||||
childrenDelegate: SliverChildBuilderDelegate(
|
||||
(context, i) {
|
||||
return _itemBuilder(context, i, channels);
|
||||
},
|
||||
childCount: (channels.length * 2) + 1,
|
||||
findChildIndexCallback: (key) {
|
||||
final ValueKey<String> valueKey = key;
|
||||
final index = channels.indexWhere(
|
||||
(channel) => 'CHANNEL-${channel.id}' == valueKey.value);
|
||||
return index != -1 ? (index * 2) : null;
|
||||
},
|
||||
child: Text(message),
|
||||
),
|
||||
FlatButton(
|
||||
onPressed: () {
|
||||
channelsBlocState.queryChannels(
|
||||
filter: widget.filter,
|
||||
sortOptions: widget.sort,
|
||||
paginationParams: widget.pagination,
|
||||
options: widget.options,
|
||||
);
|
||||
},
|
||||
child: Text('Retry'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
if (!snapshot.hasData) {
|
||||
return Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
|
||||
final channels = snapshot.data;
|
||||
return ListView.custom(
|
||||
physics: AlwaysScrollableScrollPhysics(),
|
||||
controller: _scrollController,
|
||||
childrenDelegate: SliverChildBuilderDelegate(
|
||||
(context, i) {
|
||||
return _itemBuilder(context, i, channels);
|
||||
},
|
||||
childCount: (channels.length * 2) + 1,
|
||||
findChildIndexCallback: (key) {
|
||||
final ValueKey<String> valueKey = key;
|
||||
final index = channels.indexWhere(
|
||||
(channel) => 'CHANNEL-${channel.id}' == valueKey.value);
|
||||
return index != -1 ? (index * 2) : null;
|
||||
},
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Widget _itemBuilder(context, int i, List<Channel> channels) {
|
||||
|
||||
@@ -11,10 +11,12 @@ class MessageText extends StatelessWidget {
|
||||
@required this.message,
|
||||
@required this.messageTheme,
|
||||
this.onMentionTap,
|
||||
this.onLinkTap,
|
||||
}) : super(key: key);
|
||||
|
||||
final Message message;
|
||||
final void Function(User) onMentionTap;
|
||||
final void Function(String) onLinkTap;
|
||||
final MessageTheme messageTheme;
|
||||
|
||||
@override
|
||||
@@ -35,7 +37,11 @@ class MessageText extends StatelessWidget {
|
||||
print('tap on ${mentionedUser.name}');
|
||||
}
|
||||
} else {
|
||||
launchURL(context, link);
|
||||
if (onLinkTap != null) {
|
||||
onLinkTap(link);
|
||||
} else {
|
||||
launchURL(context, link);
|
||||
}
|
||||
}
|
||||
},
|
||||
styleSheet: MarkdownStyleSheet.fromTheme(
|
||||
|
||||
@@ -97,6 +97,9 @@ class MessageWidget extends StatefulWidget {
|
||||
/// The function called when tapping on UserAvatar
|
||||
final void Function(User) onUserAvatarTap;
|
||||
|
||||
/// The function called when tapping on a link
|
||||
final void Function(String) onLinkTap;
|
||||
|
||||
final List<Read> readList;
|
||||
|
||||
/// If true show the users username next to the timestamp of the message
|
||||
@@ -128,6 +131,7 @@ class MessageWidget extends StatefulWidget {
|
||||
this.showDeleteMessage = true,
|
||||
this.showEditMessage = true,
|
||||
this.onUserAvatarTap,
|
||||
this.onLinkTap,
|
||||
this.onMessageActions,
|
||||
this.editMessageInputBuilder,
|
||||
this.textBuilder,
|
||||
@@ -764,6 +768,7 @@ class _MessageWidgetState extends State<MessageWidget> {
|
||||
return widget.textBuilder != null
|
||||
? widget.textBuilder(context, widget.message)
|
||||
: MessageText(
|
||||
onLinkTap: widget.onLinkTap,
|
||||
message: widget.message,
|
||||
onMentionTap: widget.onMentionTap,
|
||||
messageTheme: widget.messageTheme,
|
||||
|
||||
Reference in New Issue
Block a user