migrate chatty

This commit is contained in:
Salvatore Giordano
2021-05-18 17:15:37 +02:00
parent 33622093e0
commit bc655e0dc4
27 changed files with 181 additions and 159 deletions
@@ -1,9 +1,9 @@
import 'package:flutter/material.dart';
class AvatarImageView extends StatelessWidget {
const AvatarImageView({Key key, this.onTap, this.child}) : super(key: key);
final Widget child;
final VoidCallback onTap;
const AvatarImageView({Key? key, this.onTap, this.child}) : super(key: key);
final Widget? child;
final VoidCallback? onTap;
@override
Widget build(BuildContext context) {
@@ -5,8 +5,8 @@ class LoadingView extends StatelessWidget {
final Widget child;
const LoadingView({
Key key,
@required this.child,
Key? key,
required this.child,
this.isLoading = false,
}) : super(key: key);
@@ -1,3 +1,4 @@
import 'package:collection/collection.dart' show IterableExtension;
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:jiffy/jiffy.dart';
@@ -30,22 +31,22 @@ import 'package:stream_chat_flutter_core/stream_chat_flutter_core.dart';
/// Modify it to change the widget appearance.
class MyChannelPreview extends StatelessWidget {
/// Function called when tapping this widget
final void Function(Channel) onTap;
final void Function(Channel)? onTap;
/// Function called when long pressing this widget
final void Function(Channel) onLongPress;
final void Function(Channel)? onLongPress;
/// Channel displayed
final Channel channel;
/// The function called when the image is tapped
final VoidCallback onImageTap;
final VoidCallback? onImageTap;
final String heroTag;
final String? heroTag;
MyChannelPreview({
@required this.channel,
Key key,
required this.channel,
Key? key,
this.onTap,
this.onLongPress,
this.onImageTap,
@@ -59,24 +60,24 @@ class MyChannelPreview extends StatelessWidget {
initialData: channel.isMuted,
builder: (context, snapshot) {
return Opacity(
opacity: snapshot.data ? 0.5 : 1,
opacity: snapshot.data! ? 0.5 : 1,
child: ListTile(
contentPadding: const EdgeInsets.symmetric(
horizontal: 8,
),
onTap: () {
if (onTap != null) {
onTap(channel);
onTap!(channel);
}
},
onLongPress: () {
if (onLongPress != null) {
onLongPress(channel);
onLongPress!(channel);
}
},
leading: Material(
child: Hero(
tag: heroTag,
tag: heroTag!,
child: StreamChannel(
channel: channel,
child: ChannelImage(
@@ -95,13 +96,13 @@ class MyChannelPreview extends StatelessWidget {
),
),
StreamBuilder<List<Member>>(
stream: channel.state.membersStream,
initialData: channel.state.members,
stream: channel.state!.membersStream,
initialData: channel.state!.members,
builder: (context, snapshot) {
if (!snapshot.hasData ||
snapshot.data.isEmpty ||
!snapshot.data.any((Member e) =>
e.user.id == channel.client.state.user.id)) {
snapshot.data!.isEmpty ||
!snapshot.data!.any((Member e) =>
e.user!.id == channel.client.state.user!.id)) {
return SizedBox();
}
return ChannelUnreadIndicator(
@@ -116,26 +117,26 @@ class MyChannelPreview extends StatelessWidget {
Flexible(child: _buildSubtitle(context)),
Builder(
builder: (context) {
final lastMessage = channel.state.messages.lastWhere(
final lastMessage =
channel.state!.messages.lastWhereOrNull(
(m) => !m.isDeleted && m.shadowed != true,
orElse: () => null,
);
if (lastMessage?.user?.id ==
StreamChat.of(context).user.id) {
StreamChat.of(context).user!.id) {
return Padding(
padding: const EdgeInsets.only(right: 4.0),
child: SendingIndicator(
message: lastMessage,
message: lastMessage!,
size: StreamChatTheme.of(context)
.channelPreviewTheme
.indicatorIconSize,
isMessageRead: channel.state.read
isMessageRead: channel.state!.read
?.where((element) =>
element.user.id !=
channel.client.state.user.id)
?.where((element) => element.lastRead
channel.client.state.user!.id)
.where((element) => element.lastRead
.isAfter(lastMessage.createdAt))
?.isNotEmpty ==
.isNotEmpty ==
true,
),
);
@@ -152,14 +153,14 @@ class MyChannelPreview extends StatelessWidget {
}
Widget _buildDate(BuildContext context) {
return StreamBuilder<DateTime>(
return StreamBuilder<DateTime?>(
stream: channel.lastMessageAtStream,
initialData: channel.lastMessageAt,
builder: (context, snapshot) {
if (!snapshot.hasData) {
return SizedBox();
}
final lastMessageAt = snapshot.data.toLocal();
final lastMessageAt = snapshot.data!.toLocal();
String stringDate;
final now = DateTime.now();
@@ -198,11 +199,11 @@ class MyChannelPreview extends StatelessWidget {
' Channel is muted',
style: StreamChatTheme.of(context)
.channelPreviewTheme
.subtitle
.subtitle!
.copyWith(
color: StreamChatTheme.of(context)
.channelPreviewTheme
.subtitle
.subtitle!
.color,
),
),
@@ -212,21 +213,20 @@ class MyChannelPreview extends StatelessWidget {
return TypingIndicator(
channel: channel,
alternativeWidget: _buildLastMessage(context),
style: StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith(
style: StreamChatTheme.of(context).channelPreviewTheme.subtitle!.copyWith(
color:
StreamChatTheme.of(context).channelPreviewTheme.subtitle.color,
StreamChatTheme.of(context).channelPreviewTheme.subtitle!.color,
),
);
}
Widget _buildLastMessage(BuildContext context) {
return StreamBuilder<List<Message>>(
stream: channel.state.messagesStream,
initialData: channel.state.messages,
return StreamBuilder<List<Message>?>(
stream: channel.state!.messagesStream,
initialData: channel.state!.messages,
builder: (context, snapshot) {
final lastMessage = snapshot.data?.lastWhere(
(m) => m.shadowed != true && !m.isDeleted,
orElse: () => null);
final lastMessage = snapshot.data
?.lastWhereOrNull((m) => m.shadowed != true && !m.isDeleted);
if (lastMessage == null) {
return SizedBox();
}
@@ -254,21 +254,21 @@ class MyChannelPreview extends StatelessWidget {
return Text.rich(
_getDisplayText(
text,
text!,
lastMessage.mentionedUsers,
lastMessage.attachments,
StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith(
StreamChatTheme.of(context).channelPreviewTheme.subtitle!.copyWith(
color: StreamChatTheme.of(context)
.channelPreviewTheme
.subtitle
.subtitle!
.color,
fontStyle: (lastMessage.isSystem || lastMessage.isDeleted)
? FontStyle.italic
: FontStyle.normal),
StreamChatTheme.of(context).channelPreviewTheme.subtitle.copyWith(
StreamChatTheme.of(context).channelPreviewTheme.subtitle!.copyWith(
color: StreamChatTheme.of(context)
.channelPreviewTheme
.subtitle
.subtitle!
.color,
fontStyle: (lastMessage.isSystem || lastMessage.isDeleted)
? FontStyle.italic
@@ -321,8 +321,8 @@ class MyChannelPreview extends StatelessWidget {
class ChannelUnreadIndicator extends StatelessWidget {
const ChannelUnreadIndicator({
Key key,
@required this.channel,
Key? key,
required this.channel,
}) : super(key: key);
final Channel channel;
@@ -330,8 +330,8 @@ class ChannelUnreadIndicator extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StreamBuilder<int>(
stream: channel.state.unreadCountStream,
initialData: channel.state.unreadCount,
stream: channel.state!.unreadCountStream,
initialData: channel.state!.unreadCount,
builder: (context, snapshot) {
if (!snapshot.hasData || snapshot.data == 0) {
return SizedBox();
@@ -351,7 +351,7 @@ class ChannelUnreadIndicator extends StatelessWidget {
),
child: Center(
child: Text(
'${snapshot.data > 99 ? '99+' : snapshot.data}',
'${snapshot.data! > 99 ? '99+' : snapshot.data}',
style: TextStyle(
fontSize: 11,
color: Colors.white,
+18 -19
View File
@@ -23,11 +23,10 @@ class ChatView extends StatelessWidget {
),
body: ChannelsBloc(
child: ChannelListView(
filter: {
'members': {
'\$in': [StreamChat.of(context).user?.id],
}
},
filter: Filter.in_(
'members',
[StreamChat.of(context).user!.id],
),
sort: [SortOption('last_message_at')],
channelPreviewBuilder: (context, channel) {
return Container(
@@ -36,22 +35,22 @@ class ChatView extends StatelessWidget {
channel: channel,
heroTag: channel.id,
onImageTap: () {
String name;
String image;
String? name;
String? image;
final currentUser = StreamChat.of(context).client.state.user;
if (channel.isGroup) {
name = channel.extraData['name'];
image = channel.extraData['image'];
} else {
final friend = channel.state.members
.where((element) => element.userId != currentUser.id)
final friend = channel.state!.members
.where((element) => element.userId != currentUser!.id)
.first
.user;
.user!;
name = friend.name;
image = friend.extraData['image'];
image = friend.extraData['image'] as String?;
}
return Navigator.of(context).push(
Navigator.of(context).push(
PageRouteBuilder(
barrierColor: Colors.black45,
barrierDismissible: true,
@@ -110,15 +109,15 @@ class ChannelPage extends StatelessWidget {
class ChatDetailView extends StatelessWidget {
const ChatDetailView({
Key key,
Key? key,
this.image,
this.name,
this.channelId,
}) : super(key: key);
final String image;
final String name;
final String channelId;
final String? image;
final String? name;
final String? channelId;
@override
Widget build(BuildContext context) {
@@ -135,10 +134,10 @@ class ChatDetailView extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
Hero(
tag: channelId,
tag: channelId!,
child: ClipOval(
child: Image.network(
image,
image!,
height: 180,
width: 180,
fit: BoxFit.cover,
@@ -146,7 +145,7 @@ class ChatDetailView extends StatelessWidget {
),
),
Text(
name,
name!,
style: TextStyle(
fontWeight: FontWeight.w700,
fontSize: 22,
@@ -143,9 +143,9 @@ class FriendsSelectionView extends StatelessWidget {
CircleAvatar(
radius: 30,
backgroundImage: NetworkImage(
chatUserState.chatUser.image),
chatUserState.chatUser.image!),
),
Text(chatUserState.chatUser.name),
Text(chatUserState.chatUser.name!),
],
),
Positioned(
@@ -178,9 +178,9 @@ class FriendsSelectionView extends StatelessWidget {
},
leading: CircleAvatar(
backgroundImage:
NetworkImage(chatUserState.chatUser.image),
NetworkImage(chatUserState.chatUser.image!),
),
title: Text(chatUserState.chatUser.name),
title: Text(chatUserState.chatUser.name!),
trailing: isGroup
? Checkbox(
value: chatUserState.selected,
@@ -13,8 +13,8 @@ class GroupSelectionState {
this.channel,
this.isLoading = false,
});
final File file;
final Channel channel;
final File? file;
final Channel? channel;
final bool isLoading;
}
@@ -28,7 +28,7 @@ class GroupSelectionView extends StatelessWidget {
context,
Scaffold(
body: StreamChannel(
channel: snapshot.channel,
channel: snapshot.channel!,
child: ChannelPage(),
),
),
@@ -60,9 +60,9 @@ class GroupSelectionView extends StatelessWidget {
children: [
AvatarImageView(
onTap: context.read<GroupSelectionCubit>().pickImage,
child: snapshot?.file != null
child: snapshot.file != null
? Image.file(
snapshot?.file,
snapshot.file!,
fit: BoxFit.cover,
)
: Icon(
@@ -104,9 +104,9 @@ class GroupSelectionView extends StatelessWidget {
CircleAvatar(
radius: 30,
backgroundImage:
NetworkImage(chatUserState.chatUser.image),
NetworkImage(chatUserState.chatUser.image!),
),
Text(chatUserState.chatUser.name),
Text(chatUserState.chatUser.name!),
],
),
);
+6 -6
View File
@@ -36,7 +36,7 @@ class HomeView extends StatelessWidget {
class HomeNavigationBar extends StatelessWidget {
const HomeNavigationBar({
Key key,
Key? key,
}) : super(key: key);
@override
@@ -110,16 +110,16 @@ class HomeNavigationBar extends StatelessWidget {
class _HomeNavItem extends StatelessWidget {
const _HomeNavItem({
Key key,
Key? key,
this.iconData,
this.text,
this.onTap,
this.selected = false,
}) : super(key: key);
final IconData iconData;
final String text;
final VoidCallback onTap;
final IconData? iconData;
final String? text;
final VoidCallback? onTap;
final bool selected;
@override
@@ -135,7 +135,7 @@ class _HomeNavItem extends StatelessWidget {
mainAxisSize: MainAxisSize.min,
children: [
Icon(iconData, color: color),
Text(text, style: TextStyle(color: color)),
Text(text!, style: TextStyle(color: color)),
],
),
);
@@ -10,8 +10,8 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
class SettingsView extends StatelessWidget {
@override
Widget build(BuildContext context) {
final user = StreamChat.of(context).client.state.user;
final image = user?.extraData['image'];
final user = StreamChat.of(context).client.state.user!;
final image = user.extraData['image'];
final textColor = Theme.of(context).appBarTheme.color;
return MultiBlocProvider(
providers: [
@@ -48,7 +48,7 @@ class SettingsView extends StatelessWidget {
onTap: () => null,
child: image != null
? Image.network(
image,
image as String,
fit: BoxFit.cover,
)
: Icon(
@@ -11,7 +11,7 @@ class ProfileState {
this.success = false,
this.loading = false,
});
final File file;
final File? file;
final bool success;
final bool loading;
}
@@ -39,7 +39,7 @@ class ProfileVerifyView extends StatelessWidget {
onTap: context.read<ProfileVerifyCubit>().pickImage,
child: snapshot.file != null
? Image.file(
snapshot.file,
snapshot.file!,
fit: BoxFit.cover,
)
: Icon(