diff --git a/example/assets/logo.svg b/example/assets/logo.svg
new file mode 100644
index 00000000..49eecf7c
--- /dev/null
+++ b/example/assets/logo.svg
@@ -0,0 +1,3 @@
+
diff --git a/example/lib/advanced_options_page.dart b/example/lib/advanced_options_page.dart
new file mode 100644
index 00000000..4d1de2ae
--- /dev/null
+++ b/example/lib/advanced_options_page.dart
@@ -0,0 +1,266 @@
+import 'dart:io';
+
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_apns/flutter_apns.dart';
+import 'package:flutter_local_notifications/flutter_local_notifications.dart'
+ hide Message;
+import 'package:stream_chat_flutter/stream_chat_flutter.dart';
+
+import 'main.dart';
+
+void showLocalNotification(Message message, ChannelModel channel) async {
+ FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
+ FlutterLocalNotificationsPlugin();
+ final initializationSettingsAndroid =
+ AndroidInitializationSettings('launch_background');
+ final initializationSettingsIOS = IOSInitializationSettings();
+ final initializationSettings = InitializationSettings(
+ android: initializationSettingsAndroid,
+ iOS: initializationSettingsIOS,
+ );
+ await flutterLocalNotificationsPlugin.initialize(initializationSettings);
+ await flutterLocalNotificationsPlugin.show(
+ message.id.hashCode,
+ '${message.user.name} @ ${channel.name}',
+ message.text,
+ NotificationDetails(
+ android: AndroidNotificationDetails(
+ 'message channel',
+ 'Message channel',
+ 'Channel used for showing messages',
+ priority: Priority.high,
+ importance: Importance.high,
+ ),
+ iOS: IOSNotificationDetails(),
+ ),
+ );
+}
+
+Future backgroundHandler(Map notification) async {
+ final messageId = notification['data']['message_id'];
+
+ final notificationData =
+ await NotificationService.getAndStoreMessage(messageId);
+
+ showLocalNotification(
+ notificationData.message,
+ notificationData.channel,
+ );
+}
+
+void _initNotifications(Client client) {
+ final connector = createPushConnector();
+ connector.configure(
+ onBackgroundMessage: backgroundHandler,
+ );
+
+ connector.requestNotificationPermissions();
+ connector.token.addListener(() {
+ if (connector.token.value != null) {
+ client.addDevice(
+ connector.token.value,
+ Platform.isAndroid ? 'firebase' : 'apn',
+ );
+ }
+ });
+}
+
+class AdvancedOptionsPage extends StatelessWidget {
+ final _formKey = GlobalKey();
+ final TextEditingController _apiKeyController = TextEditingController();
+ final TextEditingController _userIdController = TextEditingController();
+ final TextEditingController _userTokenController = TextEditingController();
+ final TextEditingController _usernameController = TextEditingController();
+
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ resizeToAvoidBottomPadding: false,
+ appBar: AppBar(
+ backgroundColor: StreamChatTheme.of(context).primaryColor,
+ elevation: 1,
+ centerTitle: true,
+ title: Text(
+ 'Advanced Options',
+ style: Theme.of(context).textTheme.subtitle1.copyWith(
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ leading: IconButton(
+ icon: Icon(
+ StreamIcons.left,
+ color: Colors.black,
+ ),
+ onPressed: () {
+ Navigator.pop(context);
+ },
+ ),
+ ),
+ body: Padding(
+ padding: const EdgeInsets.symmetric(
+ horizontal: 16,
+ vertical: 16,
+ ),
+ child: Form(
+ key: _formKey,
+ onChanged: () {},
+ child: Column(
+ children: [
+ TextFormField(
+ controller: _apiKeyController,
+ validator: (value) {
+ if (value.isEmpty) {
+ return 'Please enter the user Chat API Key';
+ }
+ return null;
+ },
+ decoration: InputDecoration(
+ labelStyle: TextStyle(
+ fontSize: 14,
+ color: Colors.black.withOpacity(.5),
+ ),
+ border: UnderlineInputBorder(
+ borderRadius: BorderRadius.circular(8),
+ borderSide: BorderSide.none,
+ ),
+ fillColor: Color(0xffF5F5F5),
+ filled: true,
+ labelText: 'Chat API Key',
+ ),
+ textInputAction: TextInputAction.next,
+ ),
+ Padding(
+ padding: const EdgeInsets.only(top: 8.0),
+ child: TextFormField(
+ controller: _userIdController,
+ validator: (value) {
+ if (value.isEmpty) {
+ return 'Please enter the User ID';
+ }
+ return null;
+ },
+ textInputAction: TextInputAction.next,
+ decoration: InputDecoration(
+ labelStyle: TextStyle(
+ fontSize: 14,
+ color: Colors.black.withOpacity(.5),
+ ),
+ border: UnderlineInputBorder(
+ borderRadius: BorderRadius.circular(8),
+ borderSide: BorderSide.none,
+ ),
+ fillColor: Color(0xffF5F5F5),
+ filled: true,
+ labelText: 'User ID',
+ ),
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(top: 8.0),
+ child: TextFormField(
+ controller: _userTokenController,
+ validator: (value) {
+ if (value.isEmpty) {
+ return 'Please enter the user token';
+ }
+ return null;
+ },
+ textInputAction: TextInputAction.next,
+ decoration: InputDecoration(
+ labelStyle: TextStyle(
+ fontSize: 14,
+ color: Colors.black.withOpacity(.5),
+ ),
+ border: UnderlineInputBorder(
+ borderRadius: BorderRadius.circular(8),
+ borderSide: BorderSide.none,
+ ),
+ fillColor: Color(0xffF5F5F5),
+ filled: true,
+ labelText: 'User Token',
+ ),
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(top: 8.0),
+ child: TextFormField(
+ controller: _usernameController,
+ textInputAction: TextInputAction.done,
+ decoration: InputDecoration(
+ labelStyle: TextStyle(
+ fontSize: 14,
+ color: Colors.black.withOpacity(.5),
+ ),
+ border: UnderlineInputBorder(
+ borderRadius: BorderRadius.circular(8),
+ borderSide: BorderSide.none,
+ ),
+ fillColor: Color(0xffF5F5F5),
+ filled: true,
+ labelText: 'Username (optional)',
+ ),
+ ),
+ ),
+ Expanded(
+ child: Align(
+ alignment: Alignment.bottomCenter,
+ child: FlatButton(
+ color: StreamChatTheme.of(context).accentColor,
+ minWidth: double.infinity,
+ height: 48,
+ child: Text(
+ 'Login',
+ style: TextStyle(
+ color: Colors.white,
+ fontSize: 16,
+ ),
+ ),
+ shape: RoundedRectangleBorder(
+ borderRadius: BorderRadius.circular(26),
+ ),
+ onPressed: () async {
+ if (_formKey.currentState.validate()) {
+ final apiKey = _apiKeyController.text;
+ final userId = _userIdController.text;
+ final userToken = _userTokenController.text;
+ final username = _usernameController.text;
+
+ final client = StreamChat.of(context).client;
+ client.apiKey = apiKey;
+
+ await client.setUser(
+ User(id: userId, extraData: {
+ 'name': username,
+ }),
+ userToken,
+ );
+
+ if (!kIsWeb) {
+ _initNotifications(client);
+ }
+
+ Navigator.pop(context);
+ await Navigator.pushReplacement(
+ context,
+ MaterialPageRoute(
+ builder: (context) {
+ return StreamChat(
+ client: client,
+ child: ChannelListPage(),
+ );
+ },
+ ),
+ );
+ }
+ },
+ ),
+ ),
+ )
+ ],
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/example/lib/choose_user_page.dart b/example/lib/choose_user_page.dart
new file mode 100644
index 00000000..2d9f1c7a
--- /dev/null
+++ b/example/lib/choose_user_page.dart
@@ -0,0 +1,227 @@
+import 'dart:io';
+
+import 'package:example/advanced_options_page.dart';
+import 'package:example/main.dart';
+import 'package:flutter/foundation.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_apns/flutter_apns.dart';
+import 'package:flutter_local_notifications/flutter_local_notifications.dart'
+ hide Message;
+import 'package:flutter_svg/flutter_svg.dart';
+import 'package:stream_chat_flutter/stream_chat_flutter.dart';
+
+void showLocalNotification(Message message, ChannelModel channel) async {
+ FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
+ FlutterLocalNotificationsPlugin();
+ final initializationSettingsAndroid =
+ AndroidInitializationSettings('launch_background');
+ final initializationSettingsIOS = IOSInitializationSettings();
+ final initializationSettings = InitializationSettings(
+ android: initializationSettingsAndroid,
+ iOS: initializationSettingsIOS,
+ );
+ await flutterLocalNotificationsPlugin.initialize(initializationSettings);
+ await flutterLocalNotificationsPlugin.show(
+ message.id.hashCode,
+ '${message.user.name} @ ${channel.name}',
+ message.text,
+ NotificationDetails(
+ android: AndroidNotificationDetails(
+ 'message channel',
+ 'Message channel',
+ 'Channel used for showing messages',
+ priority: Priority.high,
+ importance: Importance.high,
+ ),
+ iOS: IOSNotificationDetails(),
+ ),
+ );
+}
+
+Future backgroundHandler(Map notification) async {
+ final messageId = notification['data']['message_id'];
+
+ final notificationData =
+ await NotificationService.getAndStoreMessage(messageId);
+
+ showLocalNotification(
+ notificationData.message,
+ notificationData.channel,
+ );
+}
+
+void _initNotifications(Client client) {
+ final connector = createPushConnector();
+ connector.configure(
+ onBackgroundMessage: backgroundHandler,
+ );
+
+ connector.requestNotificationPermissions();
+ connector.token.addListener(() {
+ if (connector.token.value != null) {
+ client.addDevice(
+ connector.token.value,
+ Platform.isAndroid ? 'firebase' : 'apn',
+ );
+ }
+ });
+}
+
+class ChooseUserPage extends StatelessWidget {
+ @override
+ Widget build(BuildContext context) {
+ final users = {
+ 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidmlzaGFsIn0._JHWzo92fpTWZMZriJHXqOng6ShYVmWrdaIaPwEPKBg':
+ User(
+ id: 'vishal',
+ extraData: {
+ 'name': 'Vishal',
+ },
+ ),
+ 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A':
+ User(
+ id: 'super-band-9',
+ extraData: {
+ 'name': 'John Doe',
+ },
+ ),
+ 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoic2FsdmF0b3JlIn0.GMEKyEhONmFnqtkf1TR1A3oUOSIWhjfQv5RpI906dAM':
+ User(
+ id: 'salvatore',
+ extraData: {
+ 'name': 'Salvatore',
+ },
+ ),
+ 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoidG9tbWFzbyJ9.GTalMeZHaBdpIM5w-KWrVIDSy-ODkHTRkf1GZbWAveM':
+ User(
+ id: 'tommaso',
+ extraData: {
+ 'name': 'Tommaso',
+ },
+ ),
+ 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiamFhcCJ9.xpGE2lu4OoYS7-2yy6PbF0gJnxOaxeGO4EU6xo4EdMU':
+ User(
+ id: 'jaap',
+ extraData: {
+ 'name': 'Jaap',
+ },
+ ),
+ };
+ return Scaffold(
+ body: Column(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(
+ top: 34,
+ bottom: 20,
+ ),
+ child: Center(
+ child: SvgPicture.asset(
+ 'assets/logo.svg',
+ height: 40,
+ ),
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(bottom: 13.0),
+ child: Text(
+ 'Welcome to Stream Chat',
+ style: TextStyle(
+ fontSize: 22,
+ color: Colors.black,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ ),
+ Text(
+ 'Select a user to try the Flutter SDK:',
+ style: TextStyle(
+ fontSize: 14.5,
+ color: Colors.black,
+ ),
+ ),
+ Expanded(
+ child: ListView(
+ children: [
+ ...users.entries.map((entry) {
+ final token = entry.key;
+ final user = entry.value;
+ return ListTile(
+ onTap: () async {
+ final client = StreamChat.of(context).client;
+
+ await client.setUser(
+ User(id: user.id, extraData: {
+ 'name': user.name,
+ }),
+ token,
+ );
+
+ if (!kIsWeb) {
+ _initNotifications(client);
+ }
+
+ await Navigator.pushReplacement(
+ context,
+ MaterialPageRoute(
+ builder: (context) {
+ return StreamChat(
+ client: client,
+ child: ChannelListPage(),
+ );
+ },
+ ),
+ );
+ },
+ leading: UserAvatar(
+ user: user,
+ constraints: BoxConstraints.tight(
+ Size.fromRadius(20),
+ ),
+ ),
+ title: Text(
+ user.name,
+ style: TextStyle(fontWeight: FontWeight.bold),
+ ),
+ subtitle: Text('Stream test account'),
+ trailing: Icon(
+ StreamIcons.arrow_right,
+ color: StreamChatTheme.of(context).accentColor,
+ ),
+ );
+ }),
+ ListTile(
+ onTap: () {
+ Navigator.push(
+ context,
+ MaterialPageRoute(
+ builder: (context) => AdvancedOptionsPage(),
+ ),
+ );
+ },
+ leading: CircleAvatar(
+ child: Icon(
+ StreamIcons.settings,
+ color: Colors.black,
+ ),
+ backgroundColor: StreamChatTheme.of(context).secondaryColor,
+ ),
+ title: Text(
+ 'Advanced Options',
+ style: TextStyle(fontWeight: FontWeight.bold),
+ ),
+ subtitle: Text('Custom settings'),
+ trailing: Icon(
+ StreamIcons.arrow_right,
+ color: StreamChatTheme.of(context).accentColor,
+ ),
+ ),
+ ],
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+}
diff --git a/example/lib/main.dart b/example/lib/main.dart
index ca727cf7..8218f203 100644
--- a/example/lib/main.dart
+++ b/example/lib/main.dart
@@ -1,70 +1,11 @@
import 'dart:io';
+import 'package:example/choose_user_page.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
-import 'package:flutter_apns/apns.dart';
-import 'package:flutter_local_notifications/flutter_local_notifications.dart'
- hide Message;
import 'package:stream_chat_flutter/stream_chat_flutter.dart';
-void showLocalNotification(Message message, ChannelModel channel) async {
- FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin =
- FlutterLocalNotificationsPlugin();
- final initializationSettingsAndroid =
- AndroidInitializationSettings('launch_background');
- final initializationSettingsIOS = IOSInitializationSettings();
- final initializationSettings = InitializationSettings(
- android: initializationSettingsAndroid,
- iOS: initializationSettingsIOS,
- );
- await flutterLocalNotificationsPlugin.initialize(initializationSettings);
- await flutterLocalNotificationsPlugin.show(
- message.id.hashCode,
- '${message.user.name} @ ${channel.name}',
- message.text,
- NotificationDetails(
- android: AndroidNotificationDetails(
- 'message channel',
- 'Message channel',
- 'Channel used for showing messages',
- priority: Priority.high,
- importance: Importance.high,
- ),
- iOS: IOSNotificationDetails(),
- ),
- );
-}
-
-Future backgroundHandler(Map notification) async {
- final messageId = notification['data']['message_id'];
-
- final notificationData =
- await NotificationService.getAndStoreMessage(messageId);
-
- showLocalNotification(
- notificationData.message,
- notificationData.channel,
- );
-}
-
-void _initNotifications(Client client) {
- final connector = createPushConnector();
- connector.configure(
- onBackgroundMessage: backgroundHandler,
- );
-
- connector.requestNotificationPermissions();
- connector.token.addListener(() {
- if (connector.token.value != null) {
- client.addDevice(
- connector.token.value,
- Platform.isAndroid ? 'firebase' : 'apn',
- );
- }
- });
-}
-
void main() async {
final client = Client(
's2dxdhpxd94g',
@@ -74,17 +15,6 @@ void main() async {
persistenceEnabled: true,
);
- await client.setUser(
- User(id: 'super-band-9', extraData: {
- 'name': 'Jonathan Doe',
- }),
- 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A',
- );
-
- if (!kIsWeb) {
- _initNotifications(client);
- }
-
runApp(MyApp(client));
}
@@ -98,16 +28,15 @@ class MyApp extends StatelessWidget {
return MaterialApp(
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
+ //TODO change to system once dark theme is implemented
themeMode: ThemeMode.light,
-
- ///TODO change to system once dark theme is implemented
builder: (context, widget) {
return StreamChat(
child: widget,
client: client,
);
},
- home: ChannelListPage(),
+ home: ChooseUserPage(),
);
}
}
diff --git a/example/pubspec.yaml b/example/pubspec.yaml
index 1e527964..e4604f44 100644
--- a/example/pubspec.yaml
+++ b/example/pubspec.yaml
@@ -1,7 +1,7 @@
name: example
description: A new Flutter project.
-version: 1.0.42+44
+version: 1.0.43+45
environment:
sdk: ">=2.2.2 <3.0.0"
@@ -13,6 +13,7 @@ dependencies:
path: ../
flutter_apns: ^1.3.1
flutter_local_notifications: ^2.0.0
+ flutter_svg: ^0.19.1
dev_dependencies:
flutter_test:
@@ -23,6 +24,8 @@ dev_dependencies:
test: any
flutter:
+ assets:
+ - assets/
uses-material-design: true
flutter_icons:
diff --git a/lib/src/stream_chat_theme.dart b/lib/src/stream_chat_theme.dart
index cc959a35..1dfd42b7 100644
--- a/lib/src/stream_chat_theme.dart
+++ b/lib/src/stream_chat_theme.dart
@@ -218,6 +218,7 @@ class StreamChatThemeData {
final accentColor = Color(0xff006cff);
final isDark = theme.brightness == Brightness.dark;
return StreamChatThemeData(
+ secondaryColor: Color(0xffEAEAEA),
accentColor: accentColor,
primaryColor: isDark ? Colors.black : Colors.white,
primaryIconTheme: IconThemeData(
diff --git a/lib/src/user_avatar.dart b/lib/src/user_avatar.dart
index a86206eb..ce3d29ec 100644
--- a/lib/src/user_avatar.dart
+++ b/lib/src/user_avatar.dart
@@ -55,9 +55,7 @@ class UserAvatar extends StatelessWidget {
errorWidget: (_, __, ___) {
return Center(
child: Text(
- user.extraData?.containsKey('name') ?? false
- ? user.extraData['name'][0]
- : '',
+ user.name[0],
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
diff --git a/pubspec.yaml b/pubspec.yaml
index 0e768587..e5c57193 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -26,7 +26,8 @@ dependencies:
file_picker: ^2.0.8+1
image_picker: ^0.6.7+2
flutter_keyboard_visibility: ^3.2.1
- stream_chat: ^0.2.10+1
+ stream_chat:
+ path: ../stream_chat_dart
emojis: ^0.9.3
mime: ^0.9.6+3
visibility_detector: ^0.1.5