Merge branch 'master' into feature/new-ui
This commit is contained in:
@@ -78,7 +78,7 @@ class ChannelImage extends StatelessWidget {
|
||||
String image;
|
||||
if (snapshot.data?.containsKey('image') == true) {
|
||||
image = snapshot.data['image'];
|
||||
} else if (channel.state.members.length == 2) {
|
||||
} else if (channel.state.members?.length == 2) {
|
||||
final otherMember = channel.state.members
|
||||
.firstWhere((member) => member.user.id != streamChat.user.id);
|
||||
return StreamBuilder<User>(
|
||||
|
||||
+128
-83
@@ -66,6 +66,7 @@ class ChannelListView extends StatefulWidget {
|
||||
this.errorBuilder,
|
||||
this.onImageTap,
|
||||
this.swipeToAction = false,
|
||||
this.pullToRefresh = true,
|
||||
}) : super(key: key);
|
||||
|
||||
/// The builder that will be used in case of error
|
||||
@@ -114,6 +115,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();
|
||||
}
|
||||
@@ -124,105 +128,146 @@ 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 LayoutBuilder(
|
||||
builder: (context, viewportConstraints) {
|
||||
return SingleChildScrollView(
|
||||
physics: AlwaysScrollableScrollPhysics(),
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
minHeight: viewportConstraints.maxHeight,
|
||||
),
|
||||
child: Center(
|
||||
child: CircularProgressIndicator(),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
final channels = snapshot.data;
|
||||
|
||||
if (channels.isEmpty) {
|
||||
return LayoutBuilder(
|
||||
builder: (context, viewportConstraints) {
|
||||
return SingleChildScrollView(
|
||||
physics: AlwaysScrollableScrollPhysics(),
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
minHeight: viewportConstraints.maxHeight,
|
||||
),
|
||||
child: Center(
|
||||
child: Text('You have no channels currently'),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -430,7 +475,7 @@ class _ChannelListViewState extends State<ChannelListView>
|
||||
filter: widget.filter,
|
||||
sortOptions: widget.sort,
|
||||
paginationParams: widget.pagination.copyWith(
|
||||
offset: channelsProvider.channels.length,
|
||||
offset: channelsProvider.channels?.length ?? 0,
|
||||
),
|
||||
options: widget.options,
|
||||
);
|
||||
@@ -482,7 +527,7 @@ class _ChannelListViewState extends State<ChannelListView>
|
||||
void didUpdateWidget(ChannelListView oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
|
||||
if (widget.filter != oldWidget.filter ||
|
||||
if (widget.filter?.toString() != oldWidget.filter?.toString() ||
|
||||
widget.sort != oldWidget.sort ||
|
||||
widget.pagination != oldWidget.pagination ||
|
||||
widget.options != oldWidget.options) {
|
||||
|
||||
+25
-19
@@ -11,7 +11,7 @@ class ChannelsBloc extends StatefulWidget {
|
||||
/// The widget child
|
||||
final Widget child;
|
||||
|
||||
/// Set this to false to prevent channels to be brought to the top of the list when a new message arrives
|
||||
/// Set this to true to prevent channels to be brought to the top of the list when a new message arrives
|
||||
final bool lockChannelsOrder;
|
||||
|
||||
/// Instantiate a new ChannelsBloc
|
||||
@@ -56,8 +56,7 @@ class ChannelsBlocState extends State<ChannelsBloc>
|
||||
final BehaviorSubject<bool> _queryChannelsLoadingController =
|
||||
BehaviorSubject.seeded(false);
|
||||
|
||||
final BehaviorSubject<List<Channel>> _channelsController =
|
||||
BehaviorSubject.seeded([]);
|
||||
final BehaviorSubject<List<Channel>> _channelsController = BehaviorSubject();
|
||||
|
||||
/// The stream notifying the state of queryChannel call
|
||||
Stream<bool> get queryChannelsLoading =>
|
||||
@@ -73,7 +72,10 @@ class ChannelsBlocState extends State<ChannelsBloc>
|
||||
Map<String, dynamic> options,
|
||||
bool onlyOffline = false,
|
||||
}) async {
|
||||
if (_queryChannelsLoadingController.value == true) {
|
||||
final client = StreamChat.of(context).client;
|
||||
|
||||
if (client.state?.user == null ||
|
||||
_queryChannelsLoadingController.value == true) {
|
||||
return;
|
||||
}
|
||||
_queryChannelsLoadingController.sink.add(true);
|
||||
@@ -82,16 +84,15 @@ class ChannelsBlocState extends State<ChannelsBloc>
|
||||
final clear = paginationParams == null ||
|
||||
paginationParams.offset == null ||
|
||||
paginationParams.offset == 0;
|
||||
final oldChannels = List<Channel>.from(channels);
|
||||
StreamChat.of(context)
|
||||
.client
|
||||
final oldChannels = List<Channel>.from(channels ?? []);
|
||||
client
|
||||
.queryChannels(
|
||||
filter: filter,
|
||||
sort: sortOptions,
|
||||
options: options,
|
||||
paginationParams: paginationParams,
|
||||
onlyOffline: onlyOffline,
|
||||
)
|
||||
filter: filter,
|
||||
sort: sortOptions,
|
||||
options: options,
|
||||
paginationParams: paginationParams,
|
||||
onlyOffline: onlyOffline,
|
||||
)
|
||||
.listen((channels) {
|
||||
if (clear) {
|
||||
_channelsController.add(channels);
|
||||
@@ -123,23 +124,28 @@ class ChannelsBlocState extends State<ChannelsBloc>
|
||||
_subscriptions.add(client.on(EventType.messageNew).listen((e) {
|
||||
final newChannels = List<Channel>.from(channels ?? []);
|
||||
final index = newChannels.indexWhere((c) => c.cid == e.cid);
|
||||
if (index > 0) {
|
||||
final channel = newChannels.removeAt(index);
|
||||
newChannels.insert(0, channel);
|
||||
_channelsController.add(newChannels);
|
||||
if (index > -1) {
|
||||
if (index > 0) {
|
||||
final channel = newChannels.removeAt(index);
|
||||
newChannels.insert(0, channel);
|
||||
}
|
||||
} else {
|
||||
final hiddenIndex = _hiddenChannels.indexWhere((c) => c.cid == e.cid);
|
||||
if (hiddenIndex > -1) {
|
||||
newChannels.insert(0, _hiddenChannels[hiddenIndex]);
|
||||
_hiddenChannels.removeAt(hiddenIndex);
|
||||
_channelsController.add(newChannels);
|
||||
} else {
|
||||
if (client.state.channels[e.cid] != null) {
|
||||
newChannels.insert(0, client.state.channels[e.cid]);
|
||||
}
|
||||
}
|
||||
}
|
||||
_channelsController.add(newChannels);
|
||||
}));
|
||||
}
|
||||
|
||||
_subscriptions.add(client.on(EventType.channelHidden).listen((event) async {
|
||||
final newChannels = List<Channel>.from(channels);
|
||||
final newChannels = List<Channel>.from(channels ?? []);
|
||||
final channelIndex = newChannels.indexWhere((c) => c.cid == event.cid);
|
||||
if (channelIndex > -1) {
|
||||
final channel = newChannels.removeAt(channelIndex);
|
||||
|
||||
@@ -15,12 +15,20 @@ class FullScreenImage extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return PhotoView(
|
||||
imageProvider: CachedNetworkImageProvider(url),
|
||||
maxScale: PhotoViewComputedScale.covered,
|
||||
minScale: PhotoViewComputedScale.contained,
|
||||
heroAttributes: PhotoViewHeroAttributes(
|
||||
tag: url,
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.black,
|
||||
iconTheme: IconThemeData(
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
body: PhotoView(
|
||||
imageProvider: CachedNetworkImageProvider(url),
|
||||
maxScale: PhotoViewComputedScale.covered,
|
||||
minScale: PhotoViewComputedScale.contained,
|
||||
heroAttributes: PhotoViewHeroAttributes(
|
||||
tag: url,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -26,6 +26,12 @@ class _FullScreenVideoState extends State<FullScreenVideo> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
backgroundColor: Colors.black,
|
||||
iconTheme: IconThemeData(
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
body: Builder(
|
||||
key: _scaffoldKey,
|
||||
builder: (context) {
|
||||
|
||||
@@ -182,7 +182,7 @@ class MessageInputState extends State<MessageInput> {
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Stack(
|
||||
overflow: Overflow.visible,
|
||||
clipBehavior: Clip.none,
|
||||
children: <Widget>[
|
||||
_buildBorder(context),
|
||||
Column(
|
||||
@@ -738,7 +738,10 @@ class MessageInputState extends State<MessageInput> {
|
||||
} else if (fileType == DefaultAttachmentTypes.file) {
|
||||
type = FileType.any;
|
||||
}
|
||||
file = await FilePicker.getFile(type: type);
|
||||
final res = await FilePicker.platform.pickFiles(type: type);
|
||||
if (res?.files?.isNotEmpty == true) {
|
||||
file = File(res.files.first.path);
|
||||
}
|
||||
}
|
||||
|
||||
setState(() {
|
||||
@@ -909,9 +912,9 @@ class MessageInputState extends State<MessageInput> {
|
||||
);
|
||||
}
|
||||
|
||||
return sendingFuture.whenComplete(() {
|
||||
return sendingFuture.then((resp) {
|
||||
if (widget.onMessageSent != null) {
|
||||
widget.onMessageSent(message);
|
||||
widget.onMessageSent(resp.message);
|
||||
} else {
|
||||
if (widget.editMessage != null) {
|
||||
Navigator.pop(context);
|
||||
|
||||
@@ -104,6 +104,7 @@ class MessageListView extends StatefulWidget {
|
||||
this.onThreadTap,
|
||||
this.dateDividerBuilder,
|
||||
this.scrollPhysics = const AlwaysScrollableScrollPhysics(),
|
||||
this.keyboardDismissBehavior = ScrollViewKeyboardDismissBehavior.manual,
|
||||
}) : super(key: key);
|
||||
|
||||
/// Function used to build a custom message widget
|
||||
@@ -128,6 +129,9 @@ class MessageListView extends StatefulWidget {
|
||||
/// The ScrollPhysics used by the ListView
|
||||
final ScrollPhysics scrollPhysics;
|
||||
|
||||
/// The [ScrollViewKeyboardDismissBehavior] used by the ListView
|
||||
final ScrollViewKeyboardDismissBehavior keyboardDismissBehavior;
|
||||
|
||||
@override
|
||||
_MessageListViewState createState() => _MessageListViewState();
|
||||
}
|
||||
@@ -159,6 +163,7 @@ class _MessageListViewState extends State<MessageListView> {
|
||||
child: ListView.custom(
|
||||
key: Key('messageListView'),
|
||||
physics: widget.scrollPhysics,
|
||||
keyboardDismissBehavior: widget.keyboardDismissBehavior,
|
||||
controller: _scrollController,
|
||||
reverse: true,
|
||||
childrenDelegate: SliverChildBuilderDelegate(
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -101,6 +101,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
|
||||
@@ -132,6 +135,7 @@ class MessageWidget extends StatefulWidget {
|
||||
this.showDeleteMessage = true,
|
||||
this.showEditMessage = true,
|
||||
this.onUserAvatarTap,
|
||||
this.onLinkTap,
|
||||
this.onMessageActions,
|
||||
this.editMessageInputBuilder,
|
||||
this.textBuilder,
|
||||
@@ -814,6 +818,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,
|
||||
|
||||
+49
-46
@@ -176,55 +176,58 @@ class StreamChatState extends State<StreamChat> with WidgetsBindingObserver {
|
||||
|
||||
@override
|
||||
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||
if (state == AppLifecycleState.paused) {
|
||||
if (client.showLocalNotification != null) {
|
||||
_newMessageSubscription = client
|
||||
.on(EventType.messageNew)
|
||||
.where((e) => e.user?.id != user.id)
|
||||
.where((e) => e.message.silent != true)
|
||||
.listen((event) async {
|
||||
var channel = client.state.channels[event.cid];
|
||||
if (client.state?.user != null) {
|
||||
if (state == AppLifecycleState.paused) {
|
||||
if (client.showLocalNotification != null) {
|
||||
_newMessageSubscription = client
|
||||
.on(EventType.messageNew)
|
||||
.where((e) => e.user?.id != user.id)
|
||||
.where((e) => e.message.silent != true)
|
||||
.listen((event) async {
|
||||
var channel = client.state.channels[event.cid];
|
||||
|
||||
if (channel == null) {
|
||||
channel = client.channel(
|
||||
event.type,
|
||||
id: event.cid.split(':')[1],
|
||||
if (channel == null) {
|
||||
channel = client.channel(
|
||||
event.type,
|
||||
id: event.cid.split(':')[1],
|
||||
);
|
||||
await channel.query();
|
||||
}
|
||||
|
||||
client.showLocalNotification(
|
||||
event.message,
|
||||
ChannelModel(
|
||||
id: channel.id,
|
||||
createdAt: channel.createdAt,
|
||||
extraData: channel.extraData,
|
||||
type: channel.type,
|
||||
memberCount: channel.memberCount,
|
||||
frozen: channel.frozen,
|
||||
cid: channel.cid,
|
||||
deletedAt: channel.deletedAt,
|
||||
config: channel.config,
|
||||
createdBy: channel.createdBy,
|
||||
updatedAt: channel.updatedAt,
|
||||
lastMessageAt: channel.lastMessageAt,
|
||||
),
|
||||
);
|
||||
await channel.query();
|
||||
}
|
||||
|
||||
client.showLocalNotification(
|
||||
event.message,
|
||||
ChannelModel(
|
||||
id: channel.id,
|
||||
createdAt: channel.createdAt,
|
||||
extraData: channel.extraData,
|
||||
type: channel.type,
|
||||
memberCount: channel.memberCount,
|
||||
frozen: channel.frozen,
|
||||
cid: channel.cid,
|
||||
deletedAt: channel.deletedAt,
|
||||
config: channel.config,
|
||||
createdBy: channel.createdBy,
|
||||
updatedAt: channel.updatedAt,
|
||||
lastMessageAt: channel.lastMessageAt,
|
||||
),
|
||||
);
|
||||
});
|
||||
_disconnectTimer = Timer(client.backgroundKeepAlive, () {
|
||||
});
|
||||
_disconnectTimer = Timer(client.backgroundKeepAlive, () {
|
||||
client.disconnect();
|
||||
});
|
||||
} else {
|
||||
client.disconnect();
|
||||
});
|
||||
} else {
|
||||
client.disconnect();
|
||||
}
|
||||
} else if (state == AppLifecycleState.resumed) {
|
||||
_newMessageSubscription?.cancel();
|
||||
if (_disconnectTimer?.isActive == true) {
|
||||
_disconnectTimer.cancel();
|
||||
} else {
|
||||
if (client.wsConnectionStatus.value == ConnectionStatus.disconnected) {
|
||||
NotificationService.handleIosMessageQueue(client);
|
||||
client.connect();
|
||||
}
|
||||
} else if (state == AppLifecycleState.resumed) {
|
||||
_newMessageSubscription?.cancel();
|
||||
if (_disconnectTimer?.isActive == true) {
|
||||
_disconnectTimer.cancel();
|
||||
} else {
|
||||
if (client.wsConnectionStatus.value ==
|
||||
ConnectionStatus.disconnected) {
|
||||
NotificationService.handleIosMessageQueue(client);
|
||||
client.connect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ class TypingIndicator extends StatelessWidget {
|
||||
builder: (context, snapshot) {
|
||||
return AnimatedSwitcher(
|
||||
duration: Duration(milliseconds: 300),
|
||||
child: snapshot.data.isNotEmpty
|
||||
child: snapshot.data?.isNotEmpty == true
|
||||
? Align(
|
||||
key: Key('typings'),
|
||||
alignment: alignment,
|
||||
|
||||
Reference in New Issue
Block a user