diff --git a/lib/client_holder.dart b/lib/client_holder.dart new file mode 100644 index 0000000..7f0e469 --- /dev/null +++ b/lib/client_holder.dart @@ -0,0 +1,39 @@ + +import 'package:contacts_plus_plus/clients/api_client.dart'; +import 'package:contacts_plus_plus/clients/messaging_client.dart'; +import 'package:contacts_plus_plus/clients/notification_client.dart'; +import 'package:contacts_plus_plus/clients/settings_client.dart'; +import 'package:contacts_plus_plus/models/authentication_data.dart'; +import 'package:flutter/material.dart'; + +class ClientHolder extends InheritedWidget { + final ApiClient apiClient; + final SettingsClient settingsClient; + late final MessagingClient messagingClient; + final NotificationClient notificationClient = NotificationClient(); + + ClientHolder({ + super.key, + required AuthenticationData authenticationData, + required this.settingsClient, + required super.child + }) : apiClient = ApiClient(authenticationData: authenticationData) { + messagingClient = MessagingClient(apiClient: apiClient, notificationClient: notificationClient); + } + + static ClientHolder? maybeOf(BuildContext context) { + return context.dependOnInheritedWidgetOfExactType(); + } + + static ClientHolder of(BuildContext context) { + final ClientHolder? result = maybeOf(context); + assert(result != null, 'No AuthenticatedClient found in context'); + return result!; + } + + @override + bool updateShouldNotify(covariant ClientHolder oldWidget) => + oldWidget.apiClient != apiClient + || oldWidget.settingsClient != settingsClient + || oldWidget.messagingClient != messagingClient; +} diff --git a/lib/clients/api_client.dart b/lib/clients/api_client.dart index e41ddd4..c1240f0 100644 --- a/lib/clients/api_client.dart +++ b/lib/clients/api_client.dart @@ -1,6 +1,7 @@ import 'dart:async'; import 'dart:convert'; import 'package:contacts_plus_plus/clients/messaging_client.dart'; +import 'package:contacts_plus_plus/clients/notification_client.dart'; import 'package:contacts_plus_plus/clients/settings_client.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -145,35 +146,3 @@ class ApiClient { return http.delete(buildFullUri(path), headers: headers); } } - -class ClientHolder extends InheritedWidget { - final ApiClient apiClient; - final SettingsClient settingsClient; - late final MessagingClient messagingClient; - final NotificationClient notificationClient = NotificationClient(); - - ClientHolder({ - super.key, - required AuthenticationData authenticationData, - required this.settingsClient, - required super.child - }) : apiClient = ApiClient(authenticationData: authenticationData) { - messagingClient = MessagingClient(apiClient: apiClient, notificationClient: notificationClient); - } - - static ClientHolder? maybeOf(BuildContext context) { - return context.dependOnInheritedWidgetOfExactType(); - } - - static ClientHolder of(BuildContext context) { - final ClientHolder? result = maybeOf(context); - assert(result != null, 'No AuthenticatedClient found in context'); - return result!; - } - - @override - bool updateShouldNotify(covariant ClientHolder oldWidget) => - oldWidget.apiClient != apiClient - || oldWidget.settingsClient != settingsClient - || oldWidget.messagingClient != messagingClient; -} diff --git a/lib/clients/messaging_client.dart b/lib/clients/messaging_client.dart index 607bbdc..2770d68 100644 --- a/lib/clients/messaging_client.dart +++ b/lib/clients/messaging_client.dart @@ -1,13 +1,10 @@ import 'dart:convert'; import 'dart:io'; import 'package:contacts_plus_plus/apis/message_api.dart'; -import 'package:contacts_plus_plus/auxiliary.dart'; +import 'package:contacts_plus_plus/clients/notification_client.dart'; import 'package:contacts_plus_plus/models/authentication_data.dart'; import 'package:contacts_plus_plus/models/friend.dart'; -import 'package:contacts_plus_plus/models/session.dart'; -import 'package:flutter_local_notifications/flutter_local_notifications.dart' as fln; import 'package:http/http.dart' as http; -import 'package:collection/collection.dart'; import 'package:contacts_plus_plus/clients/api_client.dart'; import 'package:contacts_plus_plus/config.dart'; @@ -283,89 +280,3 @@ class MessagingClient { _sendData(data); } } - -class NotificationChannel { - final String id; - final String name; - final String description; - - const NotificationChannel({required this.name, required this.id, required this.description}); -} - -class NotificationClient { - static const NotificationChannel _messageChannel = NotificationChannel( - id: "messages", - name: "Messages", - description: "Messages received from your friends", - ); - - final fln.FlutterLocalNotificationsPlugin _notifier = fln.FlutterLocalNotificationsPlugin() - ..initialize( - const fln.InitializationSettings( - android: fln.AndroidInitializationSettings("ic_notification"), - ) - ); - - Future showUnreadMessagesNotification(Iterable messages) async { - if (messages.isEmpty) return; - - final bySender = groupBy(messages, (p0) => p0.senderId); - - for (final entry in bySender.entries) { - final uname = entry.key.stripUid(); - await _notifier.show( - uname.hashCode, - null, - null, - fln.NotificationDetails(android: fln.AndroidNotificationDetails( - _messageChannel.id, - _messageChannel.name, - channelDescription: _messageChannel.description, - importance: fln.Importance.high, - priority: fln.Priority.max, - styleInformation: fln.MessagingStyleInformation( - fln.Person( - name: uname, - bot: false, - ), - groupConversation: false, - messages: entry.value.map((message) { - String content; - switch (message.type) { - case MessageType.unknown: - content = "Unknown Message Type"; - break; - case MessageType.text: - content = message.content; - break; - case MessageType.sound: - content = "Audio Message"; - break; - case MessageType.sessionInvite: - try { - final session = Session.fromMap(jsonDecode(message.content)); - content = "Session Invite to ${session.name}"; - } catch (e) { - content = "Session Invite"; - } - break; - case MessageType.object: - content = "Asset"; - break; - } - return fln.Message( - content, - message.sendTime, - fln.Person( - name: uname, - bot: false, - ), - ); - }).toList(), - ), - ), - ), - ); - } - } -} \ No newline at end of file diff --git a/lib/clients/notification_client.dart b/lib/clients/notification_client.dart new file mode 100644 index 0000000..c8a9dab --- /dev/null +++ b/lib/clients/notification_client.dart @@ -0,0 +1,93 @@ +import 'dart:convert'; + +import 'package:contacts_plus_plus/auxiliary.dart'; +import 'package:contacts_plus_plus/models/message.dart'; +import 'package:contacts_plus_plus/models/session.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart' as fln; +import 'package:collection/collection.dart'; + +class NotificationChannel { + final String id; + final String name; + final String description; + + const NotificationChannel({required this.name, required this.id, required this.description}); +} + +class NotificationClient { + static const NotificationChannel _messageChannel = NotificationChannel( + id: "messages", + name: "Messages", + description: "Messages received from your friends", + ); + + final fln.FlutterLocalNotificationsPlugin _notifier = fln.FlutterLocalNotificationsPlugin() + ..initialize( + const fln.InitializationSettings( + android: fln.AndroidInitializationSettings("ic_notification"), + ) + ); + + Future showUnreadMessagesNotification(Iterable messages) async { + if (messages.isEmpty) return; + + final bySender = groupBy(messages, (p0) => p0.senderId); + + for (final entry in bySender.entries) { + final uname = entry.key.stripUid(); + await _notifier.show( + uname.hashCode, + null, + null, + fln.NotificationDetails(android: fln.AndroidNotificationDetails( + _messageChannel.id, + _messageChannel.name, + channelDescription: _messageChannel.description, + importance: fln.Importance.high, + priority: fln.Priority.max, + styleInformation: fln.MessagingStyleInformation( + fln.Person( + name: uname, + bot: false, + ), + groupConversation: false, + messages: entry.value.map((message) { + String content; + switch (message.type) { + case MessageType.unknown: + content = "Unknown Message Type"; + break; + case MessageType.text: + content = message.content; + break; + case MessageType.sound: + content = "Audio Message"; + break; + case MessageType.sessionInvite: + try { + final session = Session.fromMap(jsonDecode(message.content)); + content = "Session Invite to ${session.name}"; + } catch (e) { + content = "Session Invite"; + } + break; + case MessageType.object: + content = "Asset"; + break; + } + return fln.Message( + content, + message.sendTime, + fln.Person( + name: uname, + bot: false, + ), + ); + }).toList(), + ), + ), + ), + ); + } + } +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 9708fc4..0dc85fc 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,7 @@ import 'dart:developer'; import 'dart:io' show Platform; +import 'package:contacts_plus_plus/client_holder.dart'; import 'package:contacts_plus_plus/clients/messaging_client.dart'; import 'package:contacts_plus_plus/clients/settings_client.dart'; import 'package:contacts_plus_plus/widgets/friends_list.dart'; diff --git a/lib/widgets/friends_list.dart b/lib/widgets/friends_list.dart index 1afc683..426b2d4 100644 --- a/lib/widgets/friends_list.dart +++ b/lib/widgets/friends_list.dart @@ -1,6 +1,6 @@ import 'dart:async'; -import 'package:contacts_plus_plus/clients/api_client.dart'; +import 'package:contacts_plus_plus/client_holder.dart'; import 'package:contacts_plus_plus/apis/friend_api.dart'; import 'package:contacts_plus_plus/apis/message_api.dart'; import 'package:contacts_plus_plus/models/friend.dart'; diff --git a/lib/widgets/login_screen.dart b/lib/widgets/login_screen.dart index 8c0348f..6fda6d2 100644 --- a/lib/widgets/login_screen.dart +++ b/lib/widgets/login_screen.dart @@ -2,6 +2,7 @@ import 'package:contacts_plus_plus/clients/api_client.dart'; import 'package:contacts_plus_plus/models/authentication_data.dart'; import 'package:flutter/material.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +import 'package:contacts_plus_plus/client_holder.dart'; class LoginScreen extends StatefulWidget { const LoginScreen({this.onLoginSuccessful, this.cachedUsername, super.key}); diff --git a/lib/widgets/message_audio_player.dart b/lib/widgets/message_audio_player.dart index 08042cf..3c98b3c 100644 --- a/lib/widgets/message_audio_player.dart +++ b/lib/widgets/message_audio_player.dart @@ -1,7 +1,7 @@ import 'dart:convert'; import 'dart:io' show Platform; -import 'package:contacts_plus_plus/clients/api_client.dart'; +import 'package:contacts_plus_plus/client_holder.dart'; import 'package:contacts_plus_plus/auxiliary.dart'; import 'package:contacts_plus_plus/models/message.dart'; import 'package:contacts_plus_plus/widgets/messages_list.dart'; diff --git a/lib/widgets/message_session_invite.dart b/lib/widgets/message_session_invite.dart index a86152b..d6e9e0e 100644 --- a/lib/widgets/message_session_invite.dart +++ b/lib/widgets/message_session_invite.dart @@ -1,6 +1,6 @@ import 'dart:convert'; -import 'package:contacts_plus_plus/clients/api_client.dart'; +import 'package:contacts_plus_plus/client_holder.dart'; import 'package:contacts_plus_plus/auxiliary.dart'; import 'package:contacts_plus_plus/models/message.dart'; import 'package:contacts_plus_plus/models/session.dart'; diff --git a/lib/widgets/messages_list.dart b/lib/widgets/messages_list.dart index 2d452ed..046eb46 100644 --- a/lib/widgets/messages_list.dart +++ b/lib/widgets/messages_list.dart @@ -1,7 +1,7 @@ import 'dart:async'; import 'package:cached_network_image/cached_network_image.dart'; -import 'package:contacts_plus_plus/clients/api_client.dart'; +import 'package:contacts_plus_plus/client_holder.dart'; import 'package:contacts_plus_plus/auxiliary.dart'; import 'package:contacts_plus_plus/models/friend.dart'; import 'package:contacts_plus_plus/models/message.dart'; diff --git a/lib/widgets/settings_page.dart b/lib/widgets/settings_page.dart index 2b958f4..ed91bad 100644 --- a/lib/widgets/settings_page.dart +++ b/lib/widgets/settings_page.dart @@ -1,4 +1,4 @@ -import 'package:contacts_plus_plus/clients/api_client.dart'; +import 'package:contacts_plus_plus/client_holder.dart'; import 'package:flutter/material.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:workmanager/workmanager.dart'; diff --git a/lib/widgets/user_list_tile.dart b/lib/widgets/user_list_tile.dart index 9477dd5..6b80eaa 100644 --- a/lib/widgets/user_list_tile.dart +++ b/lib/widgets/user_list_tile.dart @@ -1,6 +1,6 @@ import 'package:contacts_plus_plus/apis/user_api.dart'; import 'package:contacts_plus_plus/auxiliary.dart'; -import 'package:contacts_plus_plus/clients/api_client.dart'; +import 'package:contacts_plus_plus/client_holder.dart'; import 'package:contacts_plus_plus/models/user.dart'; import 'package:contacts_plus_plus/widgets/generic_avatar.dart'; import 'package:flutter/material.dart'; diff --git a/lib/widgets/user_search.dart b/lib/widgets/user_search.dart index 280079b..25ba988 100644 --- a/lib/widgets/user_search.dart +++ b/lib/widgets/user_search.dart @@ -1,8 +1,7 @@ - import 'dart:async'; import 'package:contacts_plus_plus/apis/user_api.dart'; -import 'package:contacts_plus_plus/clients/api_client.dart'; +import 'package:contacts_plus_plus/client_holder.dart'; import 'package:contacts_plus_plus/models/user.dart'; import 'package:contacts_plus_plus/widgets/default_error_widget.dart'; import 'package:contacts_plus_plus/widgets/user_list_tile.dart';