Merge branch 'master' into feature/new-ui

This commit is contained in:
Salvatore Giordano
2021-02-02 15:23:17 +01:00
19 changed files with 4964 additions and 3 deletions
+1
View File
@@ -0,0 +1 @@
c1153e968f5d6bcc19c41ac2592825f6
+263
View File
@@ -0,0 +1,263 @@
PODS:
- DKImagePickerController/Core (4.3.2):
- DKImagePickerController/ImageDataManager
- DKImagePickerController/Resource
- DKImagePickerController/ImageDataManager (4.3.2)
- DKImagePickerController/PhotoGallery (4.3.2):
- DKImagePickerController/Core
- DKPhotoGallery
- DKImagePickerController/Resource (4.3.2)
- DKPhotoGallery (0.0.17):
- DKPhotoGallery/Core (= 0.0.17)
- DKPhotoGallery/Model (= 0.0.17)
- DKPhotoGallery/Preview (= 0.0.17)
- DKPhotoGallery/Resource (= 0.0.17)
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Core (0.0.17):
- DKPhotoGallery/Model
- DKPhotoGallery/Preview
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Model (0.0.17):
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Preview (0.0.17):
- DKPhotoGallery/Model
- DKPhotoGallery/Resource
- SDWebImage
- SwiftyGif
- DKPhotoGallery/Resource (0.0.17):
- SDWebImage
- SwiftyGif
- file_picker (0.0.1):
- DKImagePickerController/PhotoGallery
- Flutter
- Firebase/CoreOnly (6.33.0):
- FirebaseCore (= 6.10.3)
- Firebase/Messaging (6.33.0):
- Firebase/CoreOnly
- FirebaseMessaging (~> 4.7.0)
- firebase_core (0.5.3):
- Firebase/CoreOnly (~> 6.33.0)
- Flutter
- firebase_messaging (7.0.3):
- Firebase/CoreOnly (~> 6.33.0)
- Firebase/Messaging (~> 6.33.0)
- firebase_core
- Flutter
- FirebaseCore (6.10.3):
- FirebaseCoreDiagnostics (~> 1.6)
- GoogleUtilities/Environment (~> 6.7)
- GoogleUtilities/Logger (~> 6.7)
- FirebaseCoreDiagnostics (1.7.0):
- GoogleDataTransport (~> 7.4)
- GoogleUtilities/Environment (~> 6.7)
- GoogleUtilities/Logger (~> 6.7)
- nanopb (~> 1.30906.0)
- FirebaseInstallations (1.7.0):
- FirebaseCore (~> 6.10)
- GoogleUtilities/Environment (~> 6.7)
- GoogleUtilities/UserDefaults (~> 6.7)
- PromisesObjC (~> 1.2)
- FirebaseInstanceID (4.8.0):
- FirebaseCore (~> 6.10)
- FirebaseInstallations (~> 1.6)
- GoogleUtilities/Environment (~> 6.7)
- GoogleUtilities/UserDefaults (~> 6.7)
- FirebaseMessaging (4.7.1):
- FirebaseCore (~> 6.10)
- FirebaseInstanceID (~> 4.7)
- GoogleUtilities/AppDelegateSwizzler (~> 6.7)
- GoogleUtilities/Environment (~> 6.7)
- GoogleUtilities/Reachability (~> 6.7)
- GoogleUtilities/UserDefaults (~> 6.7)
- Protobuf (>= 3.9.2, ~> 3.9)
- Flutter (1.0.0)
- flutter_apns (0.0.1):
- Flutter
- flutter_keyboard_visibility (0.0.1):
- Flutter
- flutter_local_notifications (0.0.1):
- Flutter
- FMDB (2.7.5):
- FMDB/standard (= 2.7.5)
- FMDB/standard (2.7.5)
- GoogleDataTransport (7.5.1):
- nanopb (~> 1.30906.0)
- GoogleUtilities/AppDelegateSwizzler (6.7.2):
- GoogleUtilities/Environment
- GoogleUtilities/Logger
- GoogleUtilities/Network
- GoogleUtilities/Environment (6.7.2):
- PromisesObjC (~> 1.2)
- GoogleUtilities/Logger (6.7.2):
- GoogleUtilities/Environment
- GoogleUtilities/Network (6.7.2):
- GoogleUtilities/Logger
- "GoogleUtilities/NSData+zlib"
- GoogleUtilities/Reachability
- "GoogleUtilities/NSData+zlib (6.7.2)"
- GoogleUtilities/Reachability (6.7.2):
- GoogleUtilities/Logger
- GoogleUtilities/UserDefaults (6.7.2):
- GoogleUtilities/Logger
- image_picker (0.0.1):
- Flutter
- nanopb (1.30906.0):
- nanopb/decode (= 1.30906.0)
- nanopb/encode (= 1.30906.0)
- nanopb/decode (1.30906.0)
- nanopb/encode (1.30906.0)
- path_provider (0.0.1):
- Flutter
- PromisesObjC (1.2.11)
- Protobuf (3.13.0)
- SDWebImage (5.10.0):
- SDWebImage/Core (= 5.10.0)
- SDWebImage/Core (5.10.0)
- shared_preferences (0.0.1):
- Flutter
- sqflite (0.0.2):
- Flutter
- FMDB (>= 2.7.5)
- sqlite3 (3.32.3):
- sqlite3/common (= 3.32.3)
- sqlite3/common (3.32.3)
- sqlite3/fts5 (3.32.3):
- sqlite3/common
- sqlite3/json1 (3.32.3):
- sqlite3/common
- sqlite3/perf-threadsafe (3.32.3):
- sqlite3/common
- sqlite3/rtree (3.32.3):
- sqlite3/common
- sqlite3_flutter_libs (0.0.1):
- Flutter
- sqlite3 (~> 3.32.3)
- sqlite3/fts5
- sqlite3/json1
- sqlite3/perf-threadsafe
- sqlite3/rtree
- Starscream (4.0.4)
- StreamChatClient (2.4.2):
- Starscream (~> 4.0)
- SwiftyGif (5.3.0)
- url_launcher (0.0.1):
- Flutter
- video_player (0.0.1):
- Flutter
- wakelock (0.0.1):
- Flutter
DEPENDENCIES:
- file_picker (from `.symlinks/plugins/file_picker/ios`)
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
- Flutter (from `Flutter`)
- flutter_apns (from `.symlinks/plugins/flutter_apns/ios`)
- flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
- image_picker (from `.symlinks/plugins/image_picker/ios`)
- path_provider (from `.symlinks/plugins/path_provider/ios`)
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`)
- sqlite3_flutter_libs (from `.symlinks/plugins/sqlite3_flutter_libs/ios`)
- StreamChatClient
- url_launcher (from `.symlinks/plugins/url_launcher/ios`)
- video_player (from `.symlinks/plugins/video_player/ios`)
- wakelock (from `.symlinks/plugins/wakelock/ios`)
SPEC REPOS:
trunk:
- DKImagePickerController
- DKPhotoGallery
- Firebase
- FirebaseCore
- FirebaseCoreDiagnostics
- FirebaseInstallations
- FirebaseInstanceID
- FirebaseMessaging
- FMDB
- GoogleDataTransport
- GoogleUtilities
- nanopb
- PromisesObjC
- Protobuf
- SDWebImage
- sqlite3
- Starscream
- StreamChatClient
- SwiftyGif
EXTERNAL SOURCES:
file_picker:
:path: ".symlinks/plugins/file_picker/ios"
firebase_core:
:path: ".symlinks/plugins/firebase_core/ios"
firebase_messaging:
:path: ".symlinks/plugins/firebase_messaging/ios"
Flutter:
:path: Flutter
flutter_apns:
:path: ".symlinks/plugins/flutter_apns/ios"
flutter_keyboard_visibility:
:path: ".symlinks/plugins/flutter_keyboard_visibility/ios"
flutter_local_notifications:
:path: ".symlinks/plugins/flutter_local_notifications/ios"
image_picker:
:path: ".symlinks/plugins/image_picker/ios"
path_provider:
:path: ".symlinks/plugins/path_provider/ios"
shared_preferences:
:path: ".symlinks/plugins/shared_preferences/ios"
sqflite:
:path: ".symlinks/plugins/sqflite/ios"
sqlite3_flutter_libs:
:path: ".symlinks/plugins/sqlite3_flutter_libs/ios"
url_launcher:
:path: ".symlinks/plugins/url_launcher/ios"
video_player:
:path: ".symlinks/plugins/video_player/ios"
wakelock:
:path: ".symlinks/plugins/wakelock/ios"
SPEC CHECKSUMS:
DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1
Firebase: 8db6f2d1b2c5e2984efba4949a145875a8f65fe5
firebase_core: 5d6a02f3d85acd5f8321c2d6d62877626a670659
firebase_messaging: 0aea2cd5885b65e19ede58ee3507f485c992cc75
FirebaseCore: d889d9e12535b7f36ac8bfbf1713a0836a3012cd
FirebaseCoreDiagnostics: 770ac5958e1372ce67959ae4b4f31d8e127c3ac1
FirebaseInstallations: 466c7b4d1f58fe16707693091da253726a731ed2
FirebaseInstanceID: bd3ffc24367f901a43c063b36c640b345a4a5dd1
FirebaseMessaging: 5eca4ef173de76253352511aafef774caa1cba2a
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
flutter_apns: ddc629f26016140bf52165040b0a8e8869f9ce32
flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
flutter_local_notifications: 0c0b1ae97e741e1521e4c1629a459d04b9aec743
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
GoogleDataTransport: f56af7caa4ed338dc8e138a5d7c5973e66440833
GoogleUtilities: 7f2f5a07f888cdb145101d6042bc4422f57e70b3
image_picker: 9c3312491f862b28d21ecd8fdf0ee14e601b3f09
nanopb: 59317e09cf1f1a0af72f12af412d54edf52603fc
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
PromisesObjC: 8c196f5a328c2cba3e74624585467a557dcb482f
Protobuf: 3dac39b34a08151c6d949560efe3f86134a3f748
SDWebImage: 9169792e9eec3e45bba2a0c02f74bf8bd922d1ee
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
sqlite3: 8f7d2078ae27778699a622a94b853285793422a2
sqlite3_flutter_libs: 5651f8ff48e3b44d910863c4ea5916085b1b245f
Starscream: 5178aed56b316f13fa3bc55694e583d35dd414d9
StreamChatClient: fc6419fa7ceda9c048188bb7c8e9f07755ced05f
SwiftyGif: e466e86c660d343357ab944a819a101c4127cb40
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
video_player: 9cc823b1d9da7e8427ee591e8438bfbcde500e6e
wakelock: bfc7955c418d0db797614075aabbc58a39ab5107
PODFILE CHECKSUM: eb001256612a59f8f9e4d083ad8b9671e69dd184
COCOAPODS: 1.10.0
+45
View File
@@ -0,0 +1,45 @@
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
let sharedDefaults = UserDefaults(suiteName: "group.io.stream.flutter")
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
if #available(iOS 10.0, *) {
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
}
if let messageQueue = sharedDefaults?.stringArray(forKey: "messageQueue") {
UserDefaults.standard.setValue(messageQueue, forKey: "flutter.messageQueue")
sharedDefaults?.removeObject(forKey: "messageQueue")
}
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
override func applicationDidEnterBackground(_ application: UIApplication) {
if let apiKey = UserDefaults.standard.string(forKey: "flutter.KEY_API_KEY") {
sharedDefaults?.setValue(apiKey, forKey: "KEY_API_KEY")
}
if let token = UserDefaults.standard.string(forKey: "flutter.KEY_TOKEN") {
sharedDefaults?.setValue(token, forKey: "KEY_TOKEN")
}
if let userId = UserDefaults.standard.string(forKey: "flutter.KEY_USER_ID") {
sharedDefaults?.setValue(userId, forKey: "KEY_USER_ID")
}
}
override func applicationWillEnterForeground(_ application: UIApplication) {
if let messageQueue = sharedDefaults?.stringArray(forKey: "messageQueue") {
UserDefaults.standard.setValue(messageQueue, forKey: "flutter.messageQueue")
sharedDefaults?.removeObject(forKey: "messageQueue")
}
}
}
+398
View File
@@ -0,0 +1,398 @@
import 'dart:io';
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<String, dynamic> 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 ? PushProvider.firebase : PushProvider.apn,
);
}
});
}
void main() async {
final client = Client(
's2dxdhpxd94g',
logLevel: Level.INFO,
showLocalNotification:
(!kIsWeb && Platform.isAndroid) ? showLocalNotification : null,
persistenceEnabled: true,
);
await client.setUser(
User(id: 'super-band-9'),
'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoic3VwZXItYmFuZC05In0.0L6lGoeLwkz0aZRUcpZKsvaXtNEDHBcezVTZ0oPq40A',
);
if (!kIsWeb) {
_initNotifications(client);
}
runApp(MyApp(client));
}
class MyApp extends StatelessWidget {
final Client client;
MyApp(this.client);
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
themeMode: ThemeMode.system,
builder: (context, widget) {
return StreamChat(
child: widget,
client: client,
);
},
home: ChannelListPage(),
);
}
}
class ChannelListPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context) {
return CreateChannelPage();
}));
},
),
body: ChannelsBloc(
child: ChannelListView(
filter: {
'members': {
'\$in': [StreamChat.of(context).user.id],
}
},
sort: [SortOption('last_message_at')],
pagination: PaginationParams(
limit: 20,
),
channelWidget: ChannelPage(),
),
),
);
}
}
class ChannelPage extends StatelessWidget {
const ChannelPage({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: ChannelHeader(),
body: Column(
children: <Widget>[
Expanded(
child: Stack(
children: <Widget>[
MessageListView(
threadBuilder: (_, parentMessage) {
return ThreadPage(
parent: parentMessage,
);
},
),
Positioned.fill(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8.0,
vertical: 4,
),
child: TypingIndicator(
alignment: Alignment.bottomRight,
),
),
),
],
),
),
MessageInput(),
],
),
);
}
}
class ThreadPage extends StatelessWidget {
final Message parent;
ThreadPage({
Key key,
this.parent,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: ThreadHeader(
parent: parent,
),
body: Column(
children: <Widget>[
Expanded(
child: MessageListView(
parentMessage: parent,
),
),
if (parent.type != 'deleted')
MessageInput(
parentMessage: parent,
),
],
),
);
}
}
class CreateChannelPage extends StatefulWidget {
@override
_CreateChannelPageState createState() => _CreateChannelPageState();
}
class _CreateChannelPageState extends State<CreateChannelPage> {
final ScrollController _scrollController = ScrollController();
Client client;
List<User> users = [];
List<User> selectedUsers = [];
int offset = 0;
bool loading = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
backgroundColor: Colors.transparent,
title: Text(
'Create a channel',
style: Theme.of(context).textTheme.headline6,
),
),
floatingActionButton:
selectedUsers.isNotEmpty ? _buildFAB(context) : SizedBox(),
body: _buildListView(),
);
}
ListView _buildListView() {
return ListView.builder(
controller: _scrollController,
itemBuilder: _itemBuilder,
itemCount: users.length,
);
}
Widget _itemBuilder(context, i) {
final user = users[i];
return ListTile(
onLongPress: () {
_selectUser(user);
},
selected: selectedUsers.contains(user),
onTap: () {
if (selectedUsers.isNotEmpty) {
return _selectUser(user);
}
_createChannel(context, [user]);
},
leading: UserAvatar(
user: user,
),
title: Text(user.name),
);
}
Widget _buildFAB(BuildContext context) {
return FloatingActionButton(
child: Icon(Icons.done),
onPressed: () async {
String name;
if (selectedUsers.length > 1) {
name = await _showEnterNameDialog(context);
if (name?.isNotEmpty != true) {
return;
}
}
_createChannel(context, selectedUsers, name);
},
);
}
Future<String> _showEnterNameDialog(BuildContext context) {
final controller = TextEditingController();
return showDialog(
context: context,
builder: (context) => SimpleDialog(
contentPadding: const EdgeInsets.all(16),
title: Text('Enter a name for the channel'),
children: [
TextField(
controller: controller,
decoration: InputDecoration(
border: OutlineInputBorder(),
),
),
ButtonBar(
children: [
FlatButton(
onPressed: () => Navigator.pop(context),
child: Text('Cancel'),
),
FlatButton(
onPressed: () => Navigator.pop(context, controller.text),
child: Text('Ok'),
),
],
),
],
),
);
}
Future _createChannel(
BuildContext context,
List<User> users, [
String name,
]) async {
final channel = client.channel('messaging', extraData: {
'members': [
client.state.user.id,
...users.map((e) => e.id),
],
if (name != null) 'name': name,
});
await channel.watch();
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) {
return StreamChannel(
child: ChannelPage(),
channel: channel,
);
},
),
);
}
void _selectUser(User user) {
if (!selectedUsers.contains(user)) {
setState(() {
selectedUsers.add(user);
});
} else {
setState(() {
selectedUsers.remove(user);
});
}
}
@override
void initState() {
super.initState();
client = StreamChat.of(context).client;
_scrollController.addListener(() async {
if (!loading &&
_scrollController.offset >=
_scrollController.position.maxScrollExtent - 100) {
offset += 25;
await _queryUsers();
}
});
_queryUsers();
}
Future<void> _queryUsers() {
loading = true;
return client.queryUsers(
pagination: PaginationParams(
limit: 25,
offset: offset,
),
sort: [
SortOption(
'name',
direction: SortOption.ASC,
),
],
).then((value) {
setState(() {
users = [
...users,
...value.users,
];
});
}).whenComplete(() => loading = false);
}
}
+24
View File
@@ -0,0 +1,24 @@
name: example
description: A new Flutter project.
version: 1.0.27+28
environment:
sdk: ">=2.2.2 <3.0.0"
dependencies:
flutter:
sdk: flutter
stream_chat_flutter:
path: ../
flutter_apns: ^1.3.1
flutter_local_notifications: ^2.0.0
dev_dependencies:
flutter_test:
sdk: flutter
flutter_driver:
sdk: flutter
test: any
flutter:
uses-material-design: true