Skip to content

Commit

Permalink
Chat ok
Browse files Browse the repository at this point in the history
  • Loading branch information
LucaCoduriV committed Sep 5, 2022
1 parent 9fc19b6 commit 44a2840
Show file tree
Hide file tree
Showing 7 changed files with 150 additions and 98 deletions.
29 changes: 23 additions & 6 deletions lib/api/firebase_message.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:pdg_app/model/message.dart';
import 'package:cloud_firestore/cloud_firestore.dart';

import 'firebase_api.dart';
import 'package:async/async.dart' show StreamGroup;

class FirebaseMessage extends FirebaseAPI implements IMessage {
FirebaseMessage(FirebaseFirestore db) : super(db, 'message');
Expand Down Expand Up @@ -69,18 +70,34 @@ class FirebaseMessage extends FirebaseAPI implements IMessage {
return messages;
}

Stream<Message> followConversation(String firstId, String secondId) {
List<String> userIds = [firstId, secondId];
final Stream<QuerySnapshot> msgStream = collectionReference
.where('fromId', whereIn: userIds)
.where('toId', whereIn: userIds)
@override
Stream<Message?> followConversation(String firstId, String secondId) {
final Stream<QuerySnapshot<Message>> msgStream1 = collectionReference
.where('fromId', isEqualTo: firstId)
.where('toId', isEqualTo: secondId)
.orderBy('time', descending: false)
.limitToLast(1)
.withConverter(
fromFirestore: Message.fromFirestore,
toFirestore: (Message msg, _) => msg.toFirestore())
.snapshots();

final Stream<QuerySnapshot<Message>> msgStream2 = collectionReference
.where('fromId', isEqualTo: secondId)
.where('toId', isEqualTo: firstId)
.orderBy('time', descending: false)
.limitToLast(1)
.withConverter(
fromFirestore: Message.fromFirestore,
toFirestore: (Message msg, _) => msg.toFirestore())
.snapshots();

final msgStream =
StreamGroup.merge<QuerySnapshot<Message>>([msgStream1, msgStream2]);

return msgStream
.map((querySnapshot) => querySnapshot.docs.map((doc) => doc.data()))
.map((querySnapshot) => querySnapshot.docs)
.map((doc) => doc.isNotEmpty ? doc.first.data() : null)
.cast();
}

Expand Down
1 change: 1 addition & 0 deletions lib/api/imessage.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ abstract class IMessage {
Future<List<Message>?> readConversation(String firstId, String secondId);
void updateMessage(Message message);
void deleteMessage(String messageId);
Stream<Message?> followConversation(String firstId, String secondId);
}
35 changes: 33 additions & 2 deletions lib/provider/chat_provider.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:collection';
import 'dart:developer';

Expand All @@ -20,6 +21,7 @@ class ChatProvider extends ChangeNotifier {
final AuthProvider _auth;
final IMessage _messageApi = FirebaseMessage(FirebaseFirestore.instance);
final IUser _userApi = FirebaseUser(FirebaseFirestore.instance);
final List<StreamSubscription<Message?>> subcriptions = [];

/// The list of messages using a [LinkedHashMap] to keep the order of the messages.
final Map<User, SortedList<Message>> _messages = {};
Expand Down Expand Up @@ -69,13 +71,42 @@ class ChatProvider extends ChangeNotifier {
int index = 0;
for (final conv in futureResult) {
final sortedList =
SortedList<Message>((a, b) => a.time.compareTo(b.time));
SortedList<Message>((a, b) => b.time.compareTo(a.time));

sortedList.addAll(conv!);

_messages[users[index]] = sortedList;
index++;
}
log(_messages.toString());
notifyListeners();
}

Future<void> sendMessage(Message message) async {
_messageApi.createMessage(message);
}

startNewMessageListener() {
stopNewMessageListener();
for (final user in _messages.keys) {
final currentUserUid = _auth.userUid;

final subscription = _messageApi
.followConversation(currentUserUid, user.uid)
.listen((event) {
log('FOLLOW: $event');
if (event != null) {
_messages[user]!.add(event);
}

notifyListeners();
});
subcriptions.add(subscription);
}
}

stopNewMessageListener() {
for (final subscription in subcriptions) {
subscription.cancel();
}
}
}
6 changes: 5 additions & 1 deletion lib/router/chat_router_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ class ChatRouterPage extends StatelessWidget {
create: (context) => ChatProvider(GetIt.I.get<AuthProvider>()),
builder: (context, child) {
return FutureBuilder(
future: context.read<ChatProvider>().fetchAllMessages(),
future: () async {
final chatProvider = context.read<ChatProvider>();
await chatProvider.fetchAllMessages();
await chatProvider.startNewMessageListener();
}(),
builder: (context, snapshot) =>
snapshot.connectionState == ConnectionState.done
? const AutoRouter()
Expand Down
26 changes: 12 additions & 14 deletions lib/screens/chat.dart
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import 'dart:convert';
import 'dart:developer';
import 'dart:math' as math;

import 'package:auto_route/auto_route.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
// ignore: depend_on_referenced_packages
import 'package:flutter_chat_types/flutter_chat_types.dart' as types;
import 'package:flutter_chat_ui/flutter_chat_ui.dart';
import 'package:get_it/get_it.dart';
import 'package:pdg_app/api/firebase_message.dart';
import 'package:pdg_app/api/imessage.dart';
import 'package:pdg_app/router/router.gr.dart';
import 'package:provider/provider.dart';

import '../model/user.dart';
import '../model/message.dart' as model;
import '../provider/auth_provider.dart';
import '../provider/chat_provider.dart';

Expand Down Expand Up @@ -42,28 +45,23 @@ class _ChatScreenState extends State<ChatScreen> {
super.initState();
}

void _addMessage(types.Message message) {
setState(() {
//_messages.insert(0, message);
});
}

void _handleSendPressed(types.PartialText message) {
final textMessage = types.TextMessage(
author: _mainUser,
createdAt: DateTime.now().millisecondsSinceEpoch,
id: randomString(),
text: message.text,
IMessage messageApi = FirebaseMessage(FirebaseFirestore.instance);

final newMessage = model.Message(
toId: _otherUser.uid,
fromId: _mainUser.id,
content: message.text,
time: DateTime.now(),
);

_addMessage(textMessage);
messageApi.createMessage(newMessage);
}

@override
Widget build(BuildContext context) {
final ChatProvider chatProvider = context.watch<ChatProvider>();
_otherUser = widget._otherUser ?? chatProvider.messages.keys.first;
log(chatProvider.messages.toString());
return ChatInterface(
name: '${_otherUser.firstName} ${_otherUser.lastName}',
currentUser: _mainUser,
Expand Down
2 changes: 1 addition & 1 deletion pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ packages:
source: hosted
version: "2.3.1"
async:
dependency: transitive
dependency: "direct main"
description:
name: async
url: "https://pub.dartlang.org"
Expand Down
149 changes: 75 additions & 74 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1

environment:
sdk: ">=2.17.6 <3.0.0"
sdk: ">=2.17.6 <3.0.0"

# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
Expand All @@ -27,90 +27,91 @@ environment:
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies:
flutter:
sdk: flutter
flutter:
sdk: flutter

# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
firebase_core: ^1.21.0
auto_route: ^5.0.1
firebase_auth: ^3.6.4
firebase_storage: ^10.3.6
cloud_firestore: ^3.4.5
firebase_database: ^9.1.2
provider: ^6.0.3
flutter_chat_ui: ^1.6.4
table_calendar: ^3.0.6
intl: ^0.17.0
uuid: ^3.0.6
image_picker: ^0.8.5+3
cross_file_image: ^1.0.0
day_night_time_picker: ^1.1.2
google_nav_bar: ^5.0.6
path_provider: ^2.0.11
get_it: ^7.2.0
firebase_auth_mocks: ^0.8.5+1
firebase_storage_mocks: ^0.5.1
file_picker: ^3.0.4
file: ^6.1.4
awesome_snackbar_content: ^0.0.8
sorted_list: ^1.0.0
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
firebase_core: ^1.21.0
auto_route: ^5.0.1
firebase_auth: ^3.6.4
firebase_storage: ^10.3.6
cloud_firestore: ^3.4.5
firebase_database: ^9.1.2
provider: ^6.0.3
flutter_chat_ui: ^1.6.4
table_calendar: ^3.0.6
intl: ^0.17.0
uuid: ^3.0.6
image_picker: ^0.8.5+3
cross_file_image: ^1.0.0
day_night_time_picker: ^1.1.2
google_nav_bar: ^5.0.6
path_provider: ^2.0.11
get_it: ^7.2.0
firebase_auth_mocks: ^0.8.5+1
firebase_storage_mocks: ^0.5.1
file_picker: ^3.0.4
file: ^6.1.4
awesome_snackbar_content: ^0.0.8
sorted_list: ^1.0.0
async: ^2.9.0

dev_dependencies:
flutter_test:
sdk: flutter
flutter_test:
sdk: flutter

# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^2.0.0
widgetbook: ^2.4.1
auto_route_generator: ^5.0.1
build_runner:
fake_cloud_firestore: ^1.3.1
# The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is
# activated in the `analysis_options.yaml` file located at the root of your
# package. See that file for information about deactivating specific lint
# rules and activating additional ones.
flutter_lints: ^2.0.0
widgetbook: ^2.4.1
auto_route_generator: ^5.0.1
build_runner:
fake_cloud_firestore: ^1.3.1

# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec

# The following section is specific to Flutter packages.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
assets:
- assets/images/
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
assets:
- assets/images/

# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
# To add assets to your application, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg

# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware

# For details regarding adding assets from package dependencies, see
# https://flutter.dev/assets-and-images/#from-packages
# For details regarding adding assets from package dependencies, see
# https://flutter.dev/assets-and-images/#from-packages

# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages
# To add custom fonts to your application, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts from package dependencies,
# see https://flutter.dev/custom-fonts/#from-packages

0 comments on commit 44a2840

Please sign in to comment.