Merge pull request #53 from GetStream/chore/update-samples
chore: update dependencies and readme
This commit is contained in:
@@ -25,16 +25,18 @@ With Stream's chat components, developers quickly add chat to their app for a va
|
|||||||
## Repo Overview 😎
|
## Repo Overview 😎
|
||||||
|
|
||||||
This repo contains projects and samples developed by the team and Stream community. Projects are broke up into directories under the `packages` folder.
|
This repo contains projects and samples developed by the team and Stream community. Projects are broke up into directories under the `packages` folder.
|
||||||
|
|
||||||
Each project contains a README with build and execution instructions.
|
Each project contains a README with build and execution instructions.
|
||||||
|
|
||||||
## **Projects 🚀**
|
## **Maintained Projects 🚀**
|
||||||
|
|
||||||
- [Stream Chat v1](https://github.com/GetStream/flutter-samples/tree/main/packages/stream_chat_v1): a sample app implemented using Stream Chat and Flutter. It is a fully fledged messaging app built using a combination of our pre-made widgets and custom Flutter widgets.
|
- [Stream Chat v1](https://github.com/GetStream/flutter-samples/tree/main/packages/stream_chat_v1): a sample app implemented using Stream Chat and Flutter. It is a fully fledged messaging app built using a combination of our pre-made widgets and custom Flutter widgets.
|
||||||
|
- [Chatter YouTube Series](https://github.com/HayesGordon/chatter): an ongoing, beginner friendly, YouTube video series showing how to use Stream's Flutter packages.
|
||||||
- [Stream Chatty](https://github.com/GetStream/flutter-samples/tree/main/packages/chatty) Stream Chatty is a sample chat app made in Flutter using Stream Chat, Firebase, and flutter_bloc. It has full light and dark mode support, real-time chat, and full authentication using Firebase auth.
|
|
||||||
|
|
||||||
- [iMessage clone](https://github.com/GetStream/flutter-samples/tree/main/packages/imessage): an iMessage clone implemented using Flutter and the `stream_chat_flutter_core` package.
|
- [iMessage clone](https://github.com/GetStream/flutter-samples/tree/main/packages/imessage): an iMessage clone implemented using Flutter and the `stream_chat_flutter_core` package.
|
||||||
|
|
||||||
|
## **Historic Projects 📕**
|
||||||
|
*These projects are not actively maintained. They were developed using older versions of our packages and Flutter.*
|
||||||
|
- [Stream Chatty](https://github.com/GetStream/flutter-samples/tree/main/packages/chatty) Stream Chatty is a sample chat app made in Flutter using Stream Chat, Firebase, and flutter_bloc. It has full light and dark mode support, real-time chat, and full authentication using Firebase auth.
|
||||||
|
|
||||||
## Requirements 🛠
|
## Requirements 🛠
|
||||||
|
|
||||||
Before running this project please ensure Flutter is installed and configured on your machine. If you're new to Flutter, please checkout the [official guide](https://flutter.dev/docs/get-started/install) with installation instructions for your OS.
|
Before running this project please ensure Flutter is installed and configured on your machine. If you're new to Flutter, please checkout the [official guide](https://flutter.dev/docs/get-started/install) with installation instructions for your OS.
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
# Stream Chatty
|
# Stream Chatty
|
||||||
|
|
||||||
|
⚠️ **Attention**: This example is no longer maintained. It uses older versions of our packages and was tested on an older version of Flutter.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
Stream Chatty is a sample chat app made in Flutter using [Stream Chat](https://getstream.io/chat/sdk/flutter/), [Firebase](https://firebase.google.com/), and [flutter_bloc](https://bloclibrary.dev/#/). It has full light and dark mode support, real-time chat, and full authentication using Firebase auth.
|
Stream Chatty is a sample chat app made in Flutter using [Stream Chat](https://getstream.io/chat/sdk/flutter/), [Firebase](https://firebase.google.com/), and [flutter_bloc](https://bloclibrary.dev/#/). It has full light and dark mode support, real-time chat, and full authentication using Firebase auth.
|
||||||
|
|
||||||
Stream Chatty was created by [Diego Velasquez](http://www.twitter.com/diegoveloper) as part of a Youtube series. A step by step guide to building Stream Chatty from scratch can be found here:
|
Stream Chatty was created by [Diego Velasquez](http://www.twitter.com/diegoveloper) as part of a Youtube series. A step by step guide to building Stream Chatty from scratch can be found here:
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ class ImagePickerImpl extends ImagePickerRepository {
|
|||||||
@override
|
@override
|
||||||
Future<File?> pickImage() async {
|
Future<File?> pickImage() async {
|
||||||
final picker = ImagePicker();
|
final picker = ImagePicker();
|
||||||
final pickedFile = await picker.getImage(
|
final pickedFile = await picker.pickImage(
|
||||||
source: ImageSource.gallery,
|
source: ImageSource.gallery,
|
||||||
maxWidth: 400,
|
maxWidth: 400,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ class StreamApiLocalImpl extends StreamApiRepository {
|
|||||||
final StreamChatClient _client;
|
final StreamChatClient _client;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<ChatUser> connectUser(ChatUser user, String? token) async {
|
Future<ChatUser> connectUser(ChatUser user, String token) async {
|
||||||
Map<String, dynamic> extraData = {};
|
Map<String, dynamic> extraData = {};
|
||||||
if (user.image != null) {
|
if (user.image != null) {
|
||||||
extraData['image'] = user.image;
|
extraData['image'] = user.image;
|
||||||
@@ -16,7 +16,7 @@ class StreamApiLocalImpl extends StreamApiRepository {
|
|||||||
if (user.name != null) {
|
if (user.name != null) {
|
||||||
extraData['name'] = user.name;
|
extraData['name'] = user.name;
|
||||||
}
|
}
|
||||||
await _client.disconnect();
|
await _client.disconnectUser();
|
||||||
await _client.connectUser(
|
await _client.connectUser(
|
||||||
User(id: user.id!, extraData: extraData as Map<String, Object>),
|
User(id: user.id!, extraData: extraData as Map<String, Object>),
|
||||||
token,
|
token,
|
||||||
@@ -28,7 +28,7 @@ class StreamApiLocalImpl extends StreamApiRepository {
|
|||||||
Future<List<ChatUser>> getChatUsers() async {
|
Future<List<ChatUser>> getChatUsers() async {
|
||||||
final result = await _client.queryUsers();
|
final result = await _client.queryUsers();
|
||||||
final chatUsers = result.users
|
final chatUsers = result.users
|
||||||
.where((element) => element.id != _client.state.user!.id)
|
.where((element) => element.id != _client.state.currentUser!.id)
|
||||||
.map(
|
.map(
|
||||||
(e) => ChatUser(
|
(e) => ChatUser(
|
||||||
id: e.id,
|
id: e.id,
|
||||||
@@ -42,7 +42,7 @@ class StreamApiLocalImpl extends StreamApiRepository {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<String> getToken(String userId) async {
|
Future<String> getToken(String userId) async {
|
||||||
return _client.devToken(userId);
|
return _client.devToken(userId).rawValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -52,7 +52,7 @@ class StreamApiLocalImpl extends StreamApiRepository {
|
|||||||
final channel = _client.channel('messaging', id: channelId, extraData: {
|
final channel = _client.channel('messaging', id: channelId, extraData: {
|
||||||
'name': name!,
|
'name': name!,
|
||||||
'image': image!,
|
'image': image!,
|
||||||
'members': [_client.state.user!.id, ...members!],
|
'members': [_client.state.currentUser!.id, ...members!],
|
||||||
});
|
});
|
||||||
await channel.watch();
|
await channel.watch();
|
||||||
return channel;
|
return channel;
|
||||||
@@ -61,11 +61,11 @@ class StreamApiLocalImpl extends StreamApiRepository {
|
|||||||
@override
|
@override
|
||||||
Future<Channel> createSimpleChat(String? friendId) async {
|
Future<Channel> createSimpleChat(String? friendId) async {
|
||||||
final channel = _client.channel('messaging',
|
final channel = _client.channel('messaging',
|
||||||
id: '${_client.state.user!.id.hashCode}${friendId.hashCode}',
|
id: '${_client.state.currentUser!.id.hashCode}${friendId.hashCode}',
|
||||||
extraData: {
|
extraData: {
|
||||||
'members': [
|
'members': [
|
||||||
friendId,
|
friendId,
|
||||||
_client.state.user!.id,
|
_client.state.currentUser!.id,
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
await channel.watch();
|
await channel.watch();
|
||||||
@@ -74,7 +74,7 @@ class StreamApiLocalImpl extends StreamApiRepository {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> logout() {
|
Future<void> logout() {
|
||||||
return _client.disconnect();
|
return _client.disconnectUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -84,6 +84,6 @@ class StreamApiLocalImpl extends StreamApiRepository {
|
|||||||
User(id: userId),
|
User(id: userId),
|
||||||
token,
|
token,
|
||||||
);
|
);
|
||||||
return _client.state.user!.name != userId;
|
return _client.state.currentUser!.name != userId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class StreamApiImpl extends StreamApiRepository {
|
|||||||
final StreamChatClient _client;
|
final StreamChatClient _client;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<ChatUser> connectUser(ChatUser user, String? token) async {
|
Future<ChatUser> connectUser(ChatUser user, String token) async {
|
||||||
Map<String, dynamic> extraData = {};
|
Map<String, dynamic> extraData = {};
|
||||||
if (user.image != null) {
|
if (user.image != null) {
|
||||||
extraData['image'] = user.image;
|
extraData['image'] = user.image;
|
||||||
@@ -19,7 +19,7 @@ class StreamApiImpl extends StreamApiRepository {
|
|||||||
if (user.name != null) {
|
if (user.name != null) {
|
||||||
extraData['name'] = user.name;
|
extraData['name'] = user.name;
|
||||||
}
|
}
|
||||||
await _client.disconnect();
|
await _client.disconnectUser();
|
||||||
await _client.connectUser(
|
await _client.connectUser(
|
||||||
User(id: user.id!, extraData: extraData as Map<String, Object>),
|
User(id: user.id!, extraData: extraData as Map<String, Object>),
|
||||||
token,
|
token,
|
||||||
@@ -31,7 +31,7 @@ class StreamApiImpl extends StreamApiRepository {
|
|||||||
Future<List<ChatUser>> getChatUsers() async {
|
Future<List<ChatUser>> getChatUsers() async {
|
||||||
final result = await _client.queryUsers();
|
final result = await _client.queryUsers();
|
||||||
final chatUsers = result.users
|
final chatUsers = result.users
|
||||||
.where((element) => element.id != _client.state.user!.id)
|
.where((element) => element.id != _client.state.currentUser!.id)
|
||||||
.map(
|
.map(
|
||||||
(e) => ChatUser(
|
(e) => ChatUser(
|
||||||
id: e.id,
|
id: e.id,
|
||||||
@@ -44,7 +44,7 @@ class StreamApiImpl extends StreamApiRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<String?> getToken(String userId) async {
|
Future<String> getToken(String userId) async {
|
||||||
//TODO: use your own implementation in Production
|
//TODO: use your own implementation in Production
|
||||||
final response = await http.post(
|
final response = await http.post(
|
||||||
Uri.parse('your_backend_url'),
|
Uri.parse('your_backend_url'),
|
||||||
@@ -62,12 +62,13 @@ class StreamApiImpl extends StreamApiRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Channel> createGroupChat(String id, String? name, List<String?>? members,
|
Future<Channel> createGroupChat(
|
||||||
|
String id, String? name, List<String?>? members,
|
||||||
{String? image}) async {
|
{String? image}) async {
|
||||||
final channel = _client.channel('messaging', id: id, extraData: {
|
final channel = _client.channel('messaging', id: id, extraData: {
|
||||||
'name': name!,
|
'name': name!,
|
||||||
'image': image!,
|
'image': image!,
|
||||||
'members': [_client.state.user!.id, ...members!],
|
'members': [_client.state.currentUser!.id, ...members!],
|
||||||
});
|
});
|
||||||
await channel.watch();
|
await channel.watch();
|
||||||
return channel;
|
return channel;
|
||||||
@@ -76,11 +77,11 @@ class StreamApiImpl extends StreamApiRepository {
|
|||||||
@override
|
@override
|
||||||
Future<Channel> createSimpleChat(String? friendId) async {
|
Future<Channel> createSimpleChat(String? friendId) async {
|
||||||
final channel = _client.channel('messaging',
|
final channel = _client.channel('messaging',
|
||||||
id: '${_client.state.user!.id.hashCode}${friendId.hashCode}',
|
id: '${_client.state.currentUser!.id.hashCode}${friendId.hashCode}',
|
||||||
extraData: {
|
extraData: {
|
||||||
'members': [
|
'members': [
|
||||||
friendId,
|
friendId,
|
||||||
_client.state.user!.id,
|
_client.state.currentUser!.id,
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
await channel.watch();
|
await channel.watch();
|
||||||
@@ -89,7 +90,7 @@ class StreamApiImpl extends StreamApiRepository {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> logout() async {
|
Future<void> logout() async {
|
||||||
return _client.disconnect();
|
return _client.disconnectUser();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -99,6 +100,6 @@ class StreamApiImpl extends StreamApiRepository {
|
|||||||
User(id: userId),
|
User(id: userId),
|
||||||
token,
|
token,
|
||||||
);
|
);
|
||||||
return _client.state.user!.name != userId;
|
return _client.state.currentUser!.name != userId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,21 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|||||||
|
|
||||||
abstract class StreamApiRepository {
|
abstract class StreamApiRepository {
|
||||||
Future<List<ChatUser>> getChatUsers();
|
Future<List<ChatUser>> getChatUsers();
|
||||||
Future<String?> getToken(String userId);
|
|
||||||
|
Future<String> getToken(String userId);
|
||||||
|
|
||||||
Future<bool> connectIfExist(String userId);
|
Future<bool> connectIfExist(String userId);
|
||||||
Future<ChatUser> connectUser(ChatUser user, String? token);
|
|
||||||
|
Future<ChatUser> connectUser(ChatUser user, String token);
|
||||||
|
|
||||||
Future<Channel> createGroupChat(
|
Future<Channel> createGroupChat(
|
||||||
String channelId, String? name, List<String?>? members,
|
String channelId,
|
||||||
{String? image});
|
String? name,
|
||||||
|
List<String?>? members, {
|
||||||
|
String? image,
|
||||||
|
});
|
||||||
|
|
||||||
Future<Channel> createSimpleChat(String? friendId);
|
Future<Channel> createSimpleChat(String? friendId);
|
||||||
|
|
||||||
Future<void> logout();
|
Future<void> logout();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import '../exceptions/auth_exception.dart';
|
|||||||
|
|
||||||
class ProfileInput {
|
class ProfileInput {
|
||||||
ProfileInput({this.imageFile, this.name});
|
ProfileInput({this.imageFile, this.name});
|
||||||
|
|
||||||
final File? imageFile;
|
final File? imageFile;
|
||||||
final String? name;
|
final String? name;
|
||||||
}
|
}
|
||||||
@@ -36,11 +37,12 @@ class ProfileSignInUseCase {
|
|||||||
input.imageFile, 'users/${auth.id}');
|
input.imageFile, 'users/${auth.id}');
|
||||||
}
|
}
|
||||||
await _streamApiRepository.connectUser(
|
await _streamApiRepository.connectUser(
|
||||||
ChatUser(
|
ChatUser(
|
||||||
name: input.name,
|
name: input.name,
|
||||||
id: auth.id,
|
id: auth.id,
|
||||||
image: image,
|
image: image,
|
||||||
),
|
),
|
||||||
token);
|
token,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,10 @@ class MyApp extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.bottom]);
|
SystemChrome.setEnabledSystemUIMode(
|
||||||
|
SystemUiMode.manual,
|
||||||
|
overlays: [SystemUiOverlay.bottom],
|
||||||
|
);
|
||||||
|
|
||||||
return MultiRepositoryProvider(
|
return MultiRepositoryProvider(
|
||||||
providers: buildRepositories(_streamChatClient),
|
providers: buildRepositories(_streamChatClient),
|
||||||
@@ -36,9 +39,10 @@ class MyApp extends StatelessWidget {
|
|||||||
client: _streamChatClient,
|
client: _streamChatClient,
|
||||||
streamChatThemeData:
|
streamChatThemeData:
|
||||||
StreamChatThemeData.fromTheme(Theme.of(context)).copyWith(
|
StreamChatThemeData.fromTheme(Theme.of(context)).copyWith(
|
||||||
ownMessageTheme: MessageTheme(
|
ownMessageTheme: MessageThemeData(
|
||||||
messageBackgroundColor: Theme.of(context).accentColor,
|
messageBackgroundColor:
|
||||||
messageText: TextStyle(color: Colors.white),
|
Theme.of(context).colorScheme.secondary,
|
||||||
|
messageTextStyle: TextStyle(color: Colors.white),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ class MyChannelPreview extends StatelessWidget {
|
|||||||
tag: heroTag!,
|
tag: heroTag!,
|
||||||
child: StreamChannel(
|
child: StreamChannel(
|
||||||
channel: channel,
|
channel: channel,
|
||||||
child: ChannelImage(
|
child: ChannelAvatar(
|
||||||
onTap: onImageTap,
|
onTap: onImageTap,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -91,8 +91,9 @@ class MyChannelPreview extends StatelessWidget {
|
|||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Flexible(
|
Flexible(
|
||||||
child: ChannelName(
|
child: ChannelName(
|
||||||
textStyle:
|
textStyle: StreamChatTheme.of(context)
|
||||||
StreamChatTheme.of(context).channelPreviewTheme.title,
|
.channelPreviewTheme
|
||||||
|
.titleStyle,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
StreamBuilder<List<Member>>(
|
StreamBuilder<List<Member>>(
|
||||||
@@ -102,7 +103,8 @@ class MyChannelPreview extends StatelessWidget {
|
|||||||
if (!snapshot.hasData ||
|
if (!snapshot.hasData ||
|
||||||
snapshot.data!.isEmpty ||
|
snapshot.data!.isEmpty ||
|
||||||
!snapshot.data!.any((Member e) =>
|
!snapshot.data!.any((Member e) =>
|
||||||
e.user!.id == channel.client.state.user!.id)) {
|
e.user!.id ==
|
||||||
|
channel.client.state.currentUser!.id)) {
|
||||||
return SizedBox();
|
return SizedBox();
|
||||||
}
|
}
|
||||||
return ChannelUnreadIndicator(
|
return ChannelUnreadIndicator(
|
||||||
@@ -122,7 +124,7 @@ class MyChannelPreview extends StatelessWidget {
|
|||||||
(m) => !m.isDeleted && m.shadowed != true,
|
(m) => !m.isDeleted && m.shadowed != true,
|
||||||
);
|
);
|
||||||
if (lastMessage?.user?.id ==
|
if (lastMessage?.user?.id ==
|
||||||
StreamChat.of(context).user!.id) {
|
StreamChat.of(context).currentUser!.id) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.only(right: 4.0),
|
padding: const EdgeInsets.only(right: 4.0),
|
||||||
child: SendingIndicator(
|
child: SendingIndicator(
|
||||||
@@ -131,9 +133,9 @@ class MyChannelPreview extends StatelessWidget {
|
|||||||
.channelPreviewTheme
|
.channelPreviewTheme
|
||||||
.indicatorIconSize,
|
.indicatorIconSize,
|
||||||
isMessageRead: channel.state!.read
|
isMessageRead: channel.state!.read
|
||||||
?.where((element) =>
|
.where((element) =>
|
||||||
element.user.id !=
|
element.user.id !=
|
||||||
channel.client.state.user!.id)
|
channel.client.state.currentUser!.id)
|
||||||
.where((element) => element.lastRead
|
.where((element) => element.lastRead
|
||||||
.isAfter(lastMessage.createdAt))
|
.isAfter(lastMessage.createdAt))
|
||||||
.isNotEmpty ==
|
.isNotEmpty ==
|
||||||
@@ -181,7 +183,9 @@ class MyChannelPreview extends StatelessWidget {
|
|||||||
|
|
||||||
return Text(
|
return Text(
|
||||||
stringDate,
|
stringDate,
|
||||||
style: StreamChatTheme.of(context).channelPreviewTheme.lastMessageAt,
|
style: StreamChatTheme.of(context)
|
||||||
|
.channelPreviewTheme
|
||||||
|
.lastMessageAtStyle,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -199,11 +203,11 @@ class MyChannelPreview extends StatelessWidget {
|
|||||||
' Channel is muted',
|
' Channel is muted',
|
||||||
style: StreamChatTheme.of(context)
|
style: StreamChatTheme.of(context)
|
||||||
.channelPreviewTheme
|
.channelPreviewTheme
|
||||||
.subtitle!
|
.subtitleStyle!
|
||||||
.copyWith(
|
.copyWith(
|
||||||
color: StreamChatTheme.of(context)
|
color: StreamChatTheme.of(context)
|
||||||
.channelPreviewTheme
|
.channelPreviewTheme
|
||||||
.subtitle!
|
.subtitleStyle!
|
||||||
.color,
|
.color,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -213,9 +217,14 @@ class MyChannelPreview extends StatelessWidget {
|
|||||||
return TypingIndicator(
|
return TypingIndicator(
|
||||||
channel: channel,
|
channel: channel,
|
||||||
alternativeWidget: _buildLastMessage(context),
|
alternativeWidget: _buildLastMessage(context),
|
||||||
style: StreamChatTheme.of(context).channelPreviewTheme.subtitle!.copyWith(
|
style: StreamChatTheme.of(context)
|
||||||
color:
|
.channelPreviewTheme
|
||||||
StreamChatTheme.of(context).channelPreviewTheme.subtitle!.color,
|
.subtitleStyle!
|
||||||
|
.copyWith(
|
||||||
|
color: StreamChatTheme.of(context)
|
||||||
|
.channelPreviewTheme
|
||||||
|
.subtitleStyle!
|
||||||
|
.color,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -255,23 +264,31 @@ class MyChannelPreview extends StatelessWidget {
|
|||||||
text,
|
text,
|
||||||
lastMessage.mentionedUsers,
|
lastMessage.mentionedUsers,
|
||||||
lastMessage.attachments,
|
lastMessage.attachments,
|
||||||
StreamChatTheme.of(context).channelPreviewTheme.subtitle!.copyWith(
|
StreamChatTheme.of(context)
|
||||||
color: StreamChatTheme.of(context)
|
.channelPreviewTheme
|
||||||
.channelPreviewTheme
|
.subtitleStyle!
|
||||||
.subtitle!
|
.copyWith(
|
||||||
.color,
|
color:
|
||||||
fontStyle: (lastMessage.isSystem || lastMessage.isDeleted)
|
StreamChatTheme.of(context)
|
||||||
? FontStyle.italic
|
.channelPreviewTheme
|
||||||
: FontStyle.normal),
|
.subtitleStyle!
|
||||||
StreamChatTheme.of(context).channelPreviewTheme.subtitle!.copyWith(
|
.color,
|
||||||
color: StreamChatTheme.of(context)
|
fontStyle: (lastMessage.isSystem || lastMessage.isDeleted)
|
||||||
.channelPreviewTheme
|
? FontStyle.italic
|
||||||
.subtitle!
|
: FontStyle.normal),
|
||||||
.color,
|
StreamChatTheme.of(context)
|
||||||
fontStyle: (lastMessage.isSystem || lastMessage.isDeleted)
|
.channelPreviewTheme
|
||||||
? FontStyle.italic
|
.subtitleStyle!
|
||||||
: FontStyle.normal,
|
.copyWith(
|
||||||
fontWeight: FontWeight.bold),
|
color:
|
||||||
|
StreamChatTheme.of(context)
|
||||||
|
.channelPreviewTheme
|
||||||
|
.subtitleStyle!
|
||||||
|
.color,
|
||||||
|
fontStyle: (lastMessage.isSystem || lastMessage.isDeleted)
|
||||||
|
? FontStyle.italic
|
||||||
|
: FontStyle.normal,
|
||||||
|
fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|||||||
class ChatView extends StatelessWidget {
|
class ChatView extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final textColor = Theme.of(context).appBarTheme.color;
|
final textColor = Theme.of(context).appBarTheme.backgroundColor;
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: Theme.of(context).canvasColor,
|
backgroundColor: Theme.of(context).canvasColor,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
@@ -25,7 +25,7 @@ class ChatView extends StatelessWidget {
|
|||||||
child: ChannelListView(
|
child: ChannelListView(
|
||||||
filter: Filter.in_(
|
filter: Filter.in_(
|
||||||
'members',
|
'members',
|
||||||
[StreamChat.of(context).user!.id],
|
[StreamChat.of(context).currentUser!.id],
|
||||||
),
|
),
|
||||||
sort: [SortOption('last_message_at')],
|
sort: [SortOption('last_message_at')],
|
||||||
channelPreviewBuilder: (context, channel) {
|
channelPreviewBuilder: (context, channel) {
|
||||||
@@ -37,10 +37,11 @@ class ChatView extends StatelessWidget {
|
|||||||
onImageTap: () {
|
onImageTap: () {
|
||||||
String? name;
|
String? name;
|
||||||
String? image;
|
String? image;
|
||||||
final currentUser = StreamChat.of(context).client.state.user;
|
final currentUser =
|
||||||
|
StreamChat.of(context).client.state.currentUser;
|
||||||
if (channel.isGroup) {
|
if (channel.isGroup) {
|
||||||
name = channel.extraData['name'];
|
name = channel.extraData['name'] as String?;
|
||||||
image = channel.extraData['image'];
|
image = channel.extraData['image'] as String?;
|
||||||
} else {
|
} else {
|
||||||
final friend = channel.state!.members
|
final friend = channel.state!.members
|
||||||
.where((element) => element.userId != currentUser!.id)
|
.where((element) => element.userId != currentUser!.id)
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ class FriendsSelectionView extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final textColor = Theme.of(context).appBarTheme.color;
|
final textColor = Theme.of(context).appBarTheme.backgroundColor;
|
||||||
final accentColor = Theme.of(context).accentColor;
|
final accentColor = Theme.of(context).colorScheme.secondary;
|
||||||
return MultiBlocProvider(
|
return MultiBlocProvider(
|
||||||
providers: [
|
providers: [
|
||||||
BlocProvider(
|
BlocProvider(
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class GroupSelectionView extends StatelessWidget {
|
|||||||
'New Group',
|
'New Group',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 24,
|
fontSize: 24,
|
||||||
color: Theme.of(context).appBarTheme.color,
|
color: Theme.of(context).appBarTheme.backgroundColor,
|
||||||
fontWeight: FontWeight.w800,
|
fontWeight: FontWeight.w800,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ import 'package:stream_chat_flutter/stream_chat_flutter.dart';
|
|||||||
class SettingsView extends StatelessWidget {
|
class SettingsView extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final user = StreamChat.of(context).client.state.user!;
|
final user = StreamChat.of(context).client.state.currentUser!;
|
||||||
final image = user.extraData['image'];
|
final image = user.extraData['image'];
|
||||||
final textColor = Theme.of(context).appBarTheme.color;
|
final textColor = Theme.of(context).appBarTheme.backgroundColor;
|
||||||
return MultiBlocProvider(
|
return MultiBlocProvider(
|
||||||
providers: [
|
providers: [
|
||||||
BlocProvider(
|
BlocProvider(
|
||||||
@@ -44,7 +44,6 @@ class SettingsView extends StatelessWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
AvatarImageView(
|
AvatarImageView(
|
||||||
//TODO: implement change avatar
|
|
||||||
onTap: () => null,
|
onTap: () => null,
|
||||||
child: image != null
|
child: image != null
|
||||||
? Image.network(
|
? Image.network(
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ class ProfileVerifyView extends StatelessWidget {
|
|||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
),
|
),
|
||||||
color: Theme.of(context).accentColor,
|
color: Theme.of(context).colorScheme.secondary,
|
||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
context.read<ProfileVerifyCubit>().startChatting();
|
context.read<ProfileVerifyCubit>().startChatting();
|
||||||
|
|||||||
@@ -10,7 +10,8 @@ class Themes {
|
|||||||
static final themeLight = ThemeData.light().copyWith(
|
static final themeLight = ThemeData.light().copyWith(
|
||||||
backgroundColor: backgroundLightColor,
|
backgroundColor: backgroundLightColor,
|
||||||
// selected color
|
// selected color
|
||||||
accentColor: primaryColor,
|
colorScheme:
|
||||||
|
ThemeData.light().colorScheme.copyWith(secondary: primaryColor),
|
||||||
// floating action button
|
// floating action button
|
||||||
floatingActionButtonTheme: FloatingActionButtonThemeData(
|
floatingActionButtonTheme: FloatingActionButtonThemeData(
|
||||||
backgroundColor: primaryColor,
|
backgroundColor: primaryColor,
|
||||||
@@ -32,7 +33,8 @@ class Themes {
|
|||||||
static final themeDark = ThemeData.dark().copyWith(
|
static final themeDark = ThemeData.dark().copyWith(
|
||||||
backgroundColor: backgroundDarkColor,
|
backgroundColor: backgroundDarkColor,
|
||||||
// selected color
|
// selected color
|
||||||
accentColor: primaryColor,
|
colorScheme:
|
||||||
|
ThemeData.dark().colorScheme.copyWith(secondary: primaryColor),
|
||||||
// floating action button
|
// floating action button
|
||||||
floatingActionButtonTheme: FloatingActionButtonThemeData(
|
floatingActionButtonTheme: FloatingActionButtonThemeData(
|
||||||
backgroundColor: primaryColor,
|
backgroundColor: primaryColor,
|
||||||
|
|||||||
@@ -10,9 +10,9 @@ dependencies:
|
|||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
|
||||||
flutter_bloc: ^7.0.0
|
flutter_bloc: ^7.1.0
|
||||||
stream_chat_flutter: ^2.0.0-nullsafety.3
|
stream_chat_flutter: ^2.0.0
|
||||||
uuid: ^3.0.4
|
uuid: ^3.0.5
|
||||||
|
|
||||||
firebase_core: ^1.2.0
|
firebase_core: ^1.2.0
|
||||||
google_sign_in: ^5.0.3
|
google_sign_in: ^5.0.3
|
||||||
@@ -20,7 +20,7 @@ dependencies:
|
|||||||
firebase_storage: ^8.1.0
|
firebase_storage: ^8.1.0
|
||||||
shared_preferences: ^2.0.5
|
shared_preferences: ^2.0.5
|
||||||
http: any
|
http: any
|
||||||
collection: ^1.15.0-nullsafety.4
|
collection: ^1.15.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|||||||
@@ -2,14 +2,14 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
iMessage Clone is a sample app implemented using Stream Chat and Flutter. It is a fully fledged messaging app built using core packages.
|
iMessage Clone is a sample app implemented using Stream Chat and Flutter. It's a fully fledged messaging app built using the core Stream packages.
|
||||||
|
|
||||||
|
See our [blog post](https://getstream.io/blog/build-an-imessage-clone-with-streams-flutter-chat-sdk/) for a step-by-step guide on how to build this application.
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
Before running this project please ensure Flutter is installed and configured on your machine. If you're new to Flutter, please checkout the [official guide](https://flutter.dev/docs/get-started/install) with installation instructions for your OS.
|
Before running this project please ensure Flutter is installed and configured on your machine. If you're new to Flutter, please checkout the [official guide](https://flutter.dev/docs/get-started/install) with installation instructions for your OS.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
This project is only configured to support the following platforms:
|
This project is only configured to support the following platforms:
|
||||||
|
|
||||||
- Android
|
- Android
|
||||||
|
|||||||
@@ -26,7 +26,9 @@ Future<void> main() async {
|
|||||||
|
|
||||||
class IMessage extends StatelessWidget {
|
class IMessage extends StatelessWidget {
|
||||||
final StreamChatClient client;
|
final StreamChatClient client;
|
||||||
|
|
||||||
IMessage({required this.client});
|
IMessage({required this.client});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
initializeDateFormatting('en_US', null);
|
initializeDateFormatting('en_US', null);
|
||||||
@@ -58,9 +60,7 @@ class ChatLoader extends StatelessWidget {
|
|||||||
Filter.equal('type', 'messaging'),
|
Filter.equal('type', 'messaging'),
|
||||||
]),
|
]),
|
||||||
sort: [SortOption('last_message_at')],
|
sort: [SortOption('last_message_at')],
|
||||||
pagination: PaginationParams(
|
limit: 20,
|
||||||
limit: 20,
|
|
||||||
),
|
|
||||||
emptyBuilder: (BuildContext context) {
|
emptyBuilder: (BuildContext context) {
|
||||||
return Center(
|
return Center(
|
||||||
child: Text('Looks like you are not in any channels'),
|
child: Text('Looks like you are not in any channels'),
|
||||||
|
|||||||
@@ -24,20 +24,20 @@ dependencies:
|
|||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
intl: ^0.17.0
|
intl: ^0.17.0
|
||||||
stream_chat_flutter: ^2.2.0
|
stream_chat_flutter: ^3.0.0
|
||||||
animations: ^2.0.0
|
animations: ^2.0.1
|
||||||
collection: ^1.15.0
|
collection: ^1.15.0
|
||||||
cached_network_image: ^3.0.0
|
cached_network_image: ^3.1.0
|
||||||
|
|
||||||
|
|
||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
cupertino_icons: ^1.0.0
|
cupertino_icons: ^1.0.3
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
pedantic: ^1.9.0
|
pedantic: ^1.11.1
|
||||||
# For information on the generic Dart part of this file, see the
|
# For information on the generic Dart part of this file, see the
|
||||||
# following page: https://dart.dev/tools/pub/pubspec
|
# following page: https://dart.dev/tools/pub/pubspec
|
||||||
|
|
||||||
|
|||||||
@@ -251,7 +251,6 @@
|
|||||||
"${BUILT_PRODUCTS_DIR}/connectivity_plus/connectivity_plus.framework",
|
"${BUILT_PRODUCTS_DIR}/connectivity_plus/connectivity_plus.framework",
|
||||||
"${BUILT_PRODUCTS_DIR}/file_picker/file_picker.framework",
|
"${BUILT_PRODUCTS_DIR}/file_picker/file_picker.framework",
|
||||||
"${BUILT_PRODUCTS_DIR}/flutter_app_badger/flutter_app_badger.framework",
|
"${BUILT_PRODUCTS_DIR}/flutter_app_badger/flutter_app_badger.framework",
|
||||||
"${BUILT_PRODUCTS_DIR}/flutter_keyboard_visibility/flutter_keyboard_visibility.framework",
|
|
||||||
"${BUILT_PRODUCTS_DIR}/flutter_local_notifications/flutter_local_notifications.framework",
|
"${BUILT_PRODUCTS_DIR}/flutter_local_notifications/flutter_local_notifications.framework",
|
||||||
"${BUILT_PRODUCTS_DIR}/flutter_secure_storage/flutter_secure_storage.framework",
|
"${BUILT_PRODUCTS_DIR}/flutter_secure_storage/flutter_secure_storage.framework",
|
||||||
"${BUILT_PRODUCTS_DIR}/image_gallery_saver/image_gallery_saver.framework",
|
"${BUILT_PRODUCTS_DIR}/image_gallery_saver/image_gallery_saver.framework",
|
||||||
@@ -281,7 +280,6 @@
|
|||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/connectivity_plus.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/connectivity_plus.framework",
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_picker.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_picker.framework",
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_app_badger.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_app_badger.framework",
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_keyboard_visibility.framework",
|
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_local_notifications.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_local_notifications.framework",
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_secure_storage.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_secure_storage.framework",
|
||||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_gallery_saver.framework",
|
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/image_gallery_saver.framework",
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ class _AdvancedOptionsPageState extends State<AdvancedOptionsPage> {
|
|||||||
backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg,
|
backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg,
|
||||||
elevation: 1,
|
elevation: 1,
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
brightness: Theme.of(context).brightness,
|
|
||||||
title: Text(
|
title: Text(
|
||||||
AppLocalizations.of(context).advancedOptions,
|
AppLocalizations.of(context).advancedOptions,
|
||||||
style: StreamChatTheme.of(context).textTheme.headlineBold.copyWith(
|
style: StreamChatTheme.of(context).textTheme.headlineBold.copyWith(
|
||||||
|
|||||||
@@ -13,14 +13,14 @@ class ChannelFileDisplayScreen extends StatefulWidget {
|
|||||||
/// limit: the number of users to return (max is 30)
|
/// limit: the number of users to return (max is 30)
|
||||||
/// offset: the offset (max is 1000)
|
/// offset: the offset (max is 1000)
|
||||||
/// message_limit: how many messages should be included to each channel
|
/// message_limit: how many messages should be included to each channel
|
||||||
final PaginationParams? paginationParams;
|
final PaginationParams paginationParams;
|
||||||
|
|
||||||
/// The builder used when the file list is empty.
|
/// The builder used when the file list is empty.
|
||||||
final WidgetBuilder? emptyBuilder;
|
final WidgetBuilder? emptyBuilder;
|
||||||
|
|
||||||
const ChannelFileDisplayScreen({
|
const ChannelFileDisplayScreen({
|
||||||
this.sortOptions,
|
this.sortOptions,
|
||||||
this.paginationParams,
|
this.paginationParams = const PaginationParams(limit: 20),
|
||||||
this.emptyBuilder,
|
this.emptyBuilder,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -53,7 +53,6 @@ class _ChannelFileDisplayScreenState extends State<ChannelFileDisplayScreen> {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg,
|
backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
brightness: Theme.of(context).brightness,
|
|
||||||
elevation: 1,
|
elevation: 1,
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
title: Text(
|
title: Text(
|
||||||
@@ -151,7 +150,7 @@ class _ChannelFileDisplayScreenState extends State<ChannelFileDisplayScreen> {
|
|||||||
['file'],
|
['file'],
|
||||||
),
|
),
|
||||||
sort: widget.sortOptions,
|
sort: widget.sortOptions,
|
||||||
pagination: widget.paginationParams!.copyWith(
|
pagination: widget.paginationParams.copyWith(
|
||||||
offset: messageSearchBloc.messageResponses?.length ?? 0,
|
offset: messageSearchBloc.messageResponses?.length ?? 0,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ class _ChannelList extends State<ChannelList> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
pullToRefresh: false,
|
pullToRefresh: false,
|
||||||
paginationParams: PaginationParams(limit: 20),
|
limit: 20,
|
||||||
emptyBuilder: (_) {
|
emptyBuilder: (_) {
|
||||||
return LayoutBuilder(
|
return LayoutBuilder(
|
||||||
builder: (context, viewportConstraints) {
|
builder: (context, viewportConstraints) {
|
||||||
@@ -160,9 +160,7 @@ class _ChannelList extends State<ChannelList> {
|
|||||||
swipeToAction: true,
|
swipeToAction: true,
|
||||||
filter: Filter.in_('members', [user!.id]),
|
filter: Filter.in_('members', [user!.id]),
|
||||||
presence: true,
|
presence: true,
|
||||||
pagination: PaginationParams(
|
limit: 20,
|
||||||
limit: 20,
|
|
||||||
),
|
|
||||||
onViewInfoTap: (channel) {
|
onViewInfoTap: (channel) {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
if (channel.memberCount == 2 && channel.isDistinct) {
|
if (channel.memberCount == 2 && channel.isDistinct) {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class ChannelMediaDisplayScreen extends StatefulWidget {
|
|||||||
/// limit: the number of users to return (max is 30)
|
/// limit: the number of users to return (max is 30)
|
||||||
/// offset: the offset (max is 1000)
|
/// offset: the offset (max is 1000)
|
||||||
/// message_limit: how many messages should be included to each channel
|
/// message_limit: how many messages should be included to each channel
|
||||||
final PaginationParams? paginationParams;
|
final PaginationParams paginationParams;
|
||||||
|
|
||||||
/// The builder used when the file list is empty.
|
/// The builder used when the file list is empty.
|
||||||
final WidgetBuilder? emptyBuilder;
|
final WidgetBuilder? emptyBuilder;
|
||||||
@@ -26,7 +26,7 @@ class ChannelMediaDisplayScreen extends StatefulWidget {
|
|||||||
const ChannelMediaDisplayScreen({
|
const ChannelMediaDisplayScreen({
|
||||||
required this.messageTheme,
|
required this.messageTheme,
|
||||||
this.sortOptions,
|
this.sortOptions,
|
||||||
this.paginationParams,
|
this.paginationParams = const PaginationParams(limit: 20),
|
||||||
this.emptyBuilder,
|
this.emptyBuilder,
|
||||||
this.onShowMessage,
|
this.onShowMessage,
|
||||||
});
|
});
|
||||||
@@ -62,7 +62,6 @@ class _ChannelMediaDisplayScreenState extends State<ChannelMediaDisplayScreen> {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg,
|
backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
brightness: Theme.of(context).brightness,
|
|
||||||
elevation: 1,
|
elevation: 1,
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
title: Text(
|
title: Text(
|
||||||
@@ -163,7 +162,7 @@ class _ChannelMediaDisplayScreenState extends State<ChannelMediaDisplayScreen> {
|
|||||||
['image', 'video'],
|
['image', 'video'],
|
||||||
),
|
),
|
||||||
sort: widget.sortOptions,
|
sort: widget.sortOptions,
|
||||||
pagination: widget.paginationParams!.copyWith(
|
pagination: widget.paginationParams.copyWith(
|
||||||
offset: messageSearchBloc.messageResponses?.length ?? 0,
|
offset: messageSearchBloc.messageResponses?.length ?? 0,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -235,7 +235,6 @@ class _ChatInfoScreenState extends State<ChatInfoScreen> {
|
|||||||
direction: SortOption.ASC,
|
direction: SortOption.ASC,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
paginationParams: PaginationParams(limit: 20),
|
|
||||||
onShowMessage: (m, c) async {
|
onShowMessage: (m, c) async {
|
||||||
final client = StreamChat.of(context).client;
|
final client = StreamChat.of(context).client;
|
||||||
final message = m;
|
final message = m;
|
||||||
@@ -296,7 +295,6 @@ class _ChatInfoScreenState extends State<ChatInfoScreen> {
|
|||||||
direction: SortOption.ASC,
|
direction: SortOption.ASC,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
paginationParams: PaginationParams(limit: 20),
|
|
||||||
onShowMessage: (m, c) async {
|
onShowMessage: (m, c) async {
|
||||||
final client = StreamChat.of(context).client;
|
final client = StreamChat.of(context).client;
|
||||||
final message = m;
|
final message = m;
|
||||||
@@ -356,7 +354,6 @@ class _ChatInfoScreenState extends State<ChatInfoScreen> {
|
|||||||
direction: SortOption.ASC,
|
direction: SortOption.ASC,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
paginationParams: PaginationParams(limit: 20),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -508,7 +505,6 @@ class __SharedGroupsScreenState extends State<_SharedGroupsScreen> {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: StreamChatTheme.of(context).colorTheme.appBg,
|
backgroundColor: StreamChatTheme.of(context).colorTheme.appBg,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
brightness: Theme.of(context).brightness,
|
|
||||||
elevation: 1,
|
elevation: 1,
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
title: Text(
|
title: Text(
|
||||||
|
|||||||
@@ -62,7 +62,6 @@ class _GroupChatDetailsScreenState extends State<GroupChatDetailsScreen> {
|
|||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
backgroundColor: StreamChatTheme.of(context).colorTheme.appBg,
|
backgroundColor: StreamChatTheme.of(context).colorTheme.appBg,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
brightness: Theme.of(context).brightness,
|
|
||||||
elevation: 1,
|
elevation: 1,
|
||||||
backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg,
|
backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg,
|
||||||
leading: const StreamBackButton(),
|
leading: const StreamBackButton(),
|
||||||
|
|||||||
@@ -93,7 +93,6 @@ class _GroupInfoScreenState extends State<GroupInfoScreen> {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: StreamChatTheme.of(context).colorTheme.appBg,
|
backgroundColor: StreamChatTheme.of(context).colorTheme.appBg,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
brightness: Theme.of(context).brightness,
|
|
||||||
elevation: 1.0,
|
elevation: 1.0,
|
||||||
toolbarHeight: 56.0,
|
toolbarHeight: 56.0,
|
||||||
backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg,
|
backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg,
|
||||||
@@ -525,7 +524,6 @@ class _GroupInfoScreenState extends State<GroupInfoScreen> {
|
|||||||
direction: SortOption.ASC,
|
direction: SortOption.ASC,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
paginationParams: PaginationParams(limit: 20),
|
|
||||||
onShowMessage: (m, c) async {
|
onShowMessage: (m, c) async {
|
||||||
final client = StreamChat.of(context).client;
|
final client = StreamChat.of(context).client;
|
||||||
final message = m;
|
final message = m;
|
||||||
@@ -737,9 +735,7 @@ class _GroupInfoScreenState extends State<GroupInfoScreen> {
|
|||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
crossAxisCount: 4,
|
crossAxisCount: 4,
|
||||||
pagination: PaginationParams(
|
limit: 25,
|
||||||
limit: 25,
|
|
||||||
),
|
|
||||||
filter: Filter.and(
|
filter: Filter.and(
|
||||||
[
|
[
|
||||||
if (_searchController!.text.isNotEmpty)
|
if (_searchController!.text.isNotEmpty)
|
||||||
|
|||||||
@@ -120,7 +120,6 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: StreamChatTheme.of(context).colorTheme.appBg,
|
backgroundColor: StreamChatTheme.of(context).colorTheme.appBg,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
brightness: Theme.of(context).brightness,
|
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg,
|
backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg,
|
||||||
leading: const StreamBackButton(),
|
leading: const StreamBackButton(),
|
||||||
@@ -303,9 +302,7 @@ class _NewChatScreenState extends State<NewChatScreen> {
|
|||||||
_chipInputTextFieldState!.removeItem(user);
|
_chipInputTextFieldState!.removeItem(user);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
pagination: PaginationParams(
|
limit: 25,
|
||||||
limit: 25,
|
|
||||||
),
|
|
||||||
filter: Filter.and([
|
filter: Filter.and([
|
||||||
if (_userNameQuery.isNotEmpty)
|
if (_userNameQuery.isNotEmpty)
|
||||||
Filter.autoComplete('name', _userNameQuery),
|
Filter.autoComplete('name', _userNameQuery),
|
||||||
|
|||||||
@@ -244,9 +244,7 @@ class _NewGroupChatScreenState extends State<NewGroupChatScreen> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
pagination: PaginationParams(
|
limit: 25,
|
||||||
limit: 25,
|
|
||||||
),
|
|
||||||
filter: Filter.and([
|
filter: Filter.and([
|
||||||
if (_userNameQuery.isNotEmpty)
|
if (_userNameQuery.isNotEmpty)
|
||||||
Filter.autoComplete('name', _userNameQuery),
|
Filter.autoComplete('name', _userNameQuery),
|
||||||
|
|||||||
@@ -63,7 +63,8 @@ void showLocalNotification(
|
|||||||
android: AndroidNotificationDetails(
|
android: AndroidNotificationDetails(
|
||||||
'message channel',
|
'message channel',
|
||||||
AppLocalizations.of(context).messageChannelName,
|
AppLocalizations.of(context).messageChannelName,
|
||||||
AppLocalizations.of(context).messageChannelDescription,
|
channelDescription:
|
||||||
|
AppLocalizations.of(context).messageChannelDescription,
|
||||||
priority: Priority.high,
|
priority: Priority.high,
|
||||||
importance: Importance.high,
|
importance: Importance.high,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class PinnedMessagesScreen extends StatefulWidget {
|
|||||||
/// limit: the number of users to return (max is 30)
|
/// limit: the number of users to return (max is 30)
|
||||||
/// offset: the offset (max is 1000)
|
/// offset: the offset (max is 1000)
|
||||||
/// message_limit: how many messages should be included to each channel
|
/// message_limit: how many messages should be included to each channel
|
||||||
final PaginationParams? paginationParams;
|
final PaginationParams paginationParams;
|
||||||
|
|
||||||
/// The builder used when the file list is empty.
|
/// The builder used when the file list is empty.
|
||||||
final WidgetBuilder? emptyBuilder;
|
final WidgetBuilder? emptyBuilder;
|
||||||
@@ -26,7 +26,7 @@ class PinnedMessagesScreen extends StatefulWidget {
|
|||||||
const PinnedMessagesScreen({
|
const PinnedMessagesScreen({
|
||||||
required this.messageTheme,
|
required this.messageTheme,
|
||||||
this.sortOptions,
|
this.sortOptions,
|
||||||
this.paginationParams,
|
this.paginationParams = const PaginationParams(limit: 20),
|
||||||
this.emptyBuilder,
|
this.emptyBuilder,
|
||||||
this.onShowMessage,
|
this.onShowMessage,
|
||||||
});
|
});
|
||||||
@@ -61,7 +61,6 @@ class _PinnedMessagesScreenState extends State<PinnedMessagesScreen> {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg,
|
backgroundColor: StreamChatTheme.of(context).colorTheme.barsBg,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
brightness: Theme.of(context).brightness,
|
|
||||||
elevation: 1,
|
elevation: 1,
|
||||||
centerTitle: true,
|
centerTitle: true,
|
||||||
title: Text(
|
title: Text(
|
||||||
@@ -156,7 +155,7 @@ class _PinnedMessagesScreenState extends State<PinnedMessagesScreen> {
|
|||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
sort: widget.sortOptions,
|
sort: widget.sortOptions,
|
||||||
pagination: widget.paginationParams!.copyWith(
|
pagination: widget.paginationParams.copyWith(
|
||||||
offset: messageSearchBloc.messageResponses?.length ?? 0,
|
offset: messageSearchBloc.messageResponses?.length ?? 0,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class UserMentionsPage extends StatelessWidget {
|
|||||||
direction: SortOption.ASC,
|
direction: SortOption.ASC,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
paginationParams: PaginationParams(limit: 20),
|
limit: 20,
|
||||||
showResultCount: false,
|
showResultCount: false,
|
||||||
emptyBuilder: (_) {
|
emptyBuilder: (_) {
|
||||||
return LayoutBuilder(
|
return LayoutBuilder(
|
||||||
|
|||||||
@@ -7,25 +7,54 @@ environment:
|
|||||||
sdk: '>=2.12.0 <3.0.0'
|
sdk: '>=2.12.0 <3.0.0'
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
flutter_app_badger: ^1.2.0
|
flutter_app_badger: ^1.3.0
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
stream_chat_flutter: ^2.2.0
|
stream_chat_flutter:
|
||||||
stream_chat_persistence: ^2.2.0
|
git:
|
||||||
stream_chat_localizations: ^1.1.0
|
url: https://github.com/GetStream/stream-chat-flutter.git
|
||||||
flutter_local_notifications: ^5.0.0+4
|
ref: develop
|
||||||
|
path: packages/stream_chat_flutter
|
||||||
|
stream_chat_persistence:
|
||||||
|
git:
|
||||||
|
url: https://github.com/GetStream/stream-chat-flutter.git
|
||||||
|
ref: develop
|
||||||
|
path: packages/stream_chat_persistence
|
||||||
|
stream_chat_localizations:
|
||||||
|
git:
|
||||||
|
url: https://github.com/GetStream/stream-chat-flutter.git
|
||||||
|
ref: develop
|
||||||
|
path: packages/stream_chat_localizations
|
||||||
|
flutter_local_notifications: ^9.0.0
|
||||||
flutter_svg: ^0.22.0
|
flutter_svg: ^0.22.0
|
||||||
flutter_secure_storage: ^4.2.0
|
flutter_secure_storage: ^4.2.1
|
||||||
yaml: ^3.1.0
|
yaml: ^3.1.0
|
||||||
uuid: ^3.0.4
|
uuid: ^3.0.5
|
||||||
streaming_shared_preferences: ^2.0.0
|
streaming_shared_preferences: ^2.0.0
|
||||||
lottie: ^1.0.1
|
lottie: ^1.2.1
|
||||||
collection: ^1.15.0-nullsafety.4
|
collection: ^1.15.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_launcher_icons: ^0.9.0
|
flutter_launcher_icons: ^0.9.2
|
||||||
test: any
|
test: any
|
||||||
|
|
||||||
|
dependency_overrides:
|
||||||
|
stream_chat:
|
||||||
|
git:
|
||||||
|
url: https://github.com/GetStream/stream-chat-flutter.git
|
||||||
|
ref: develop
|
||||||
|
path: packages/stream_chat
|
||||||
|
stream_chat_flutter_core:
|
||||||
|
git:
|
||||||
|
url: https://github.com/GetStream/stream-chat-flutter.git
|
||||||
|
ref: develop
|
||||||
|
path: packages/stream_chat_flutter_core
|
||||||
|
stream_chat_flutter:
|
||||||
|
git:
|
||||||
|
url: https://github.com/GetStream/stream-chat-flutter.git
|
||||||
|
ref: develop
|
||||||
|
path: packages/stream_chat_flutter
|
||||||
|
|
||||||
flutter:
|
flutter:
|
||||||
assets:
|
assets:
|
||||||
- assets/
|
- assets/
|
||||||
|
|||||||
Reference in New Issue
Block a user