From 3eaf6ea9c6b11cf3f1be7d199000497cb39a113f Mon Sep 17 00:00:00 2001 From: Nutcake Date: Fri, 5 May 2023 11:29:54 +0200 Subject: [PATCH] Add basic new message notifications --- .../res/drawable-hdpi/ic_notification.png | Bin 0 -> 677 bytes .../res/drawable-mdpi/ic_notification.png | Bin 0 -> 461 bytes .../res/drawable-xhdpi/ic_notification.png | Bin 0 -> 895 bytes .../res/drawable-xxhdpi/ic_notification.png | Bin 0 -> 1359 bytes .../res/drawable-xxxhdpi/ic_notification.png | Bin 0 -> 1798 bytes assets/images/logo-white.png | Bin 0 -> 35948 bytes lib/apis/user_api.dart | 7 ++ lib/auxiliary.dart | 4 +- lib/clients/api_client.dart | 3 +- lib/clients/messaging_client.dart | 103 +++++++++++++++++- lib/widgets/friends_list.dart | 3 +- lib/widgets/messages_list.dart | 11 +- pubspec.lock | 2 +- pubspec.yaml | 1 + 14 files changed, 123 insertions(+), 11 deletions(-) create mode 100644 android/app/src/main/res/drawable-hdpi/ic_notification.png create mode 100644 android/app/src/main/res/drawable-mdpi/ic_notification.png create mode 100644 android/app/src/main/res/drawable-xhdpi/ic_notification.png create mode 100644 android/app/src/main/res/drawable-xxhdpi/ic_notification.png create mode 100644 android/app/src/main/res/drawable-xxxhdpi/ic_notification.png create mode 100644 assets/images/logo-white.png diff --git a/android/app/src/main/res/drawable-hdpi/ic_notification.png b/android/app/src/main/res/drawable-hdpi/ic_notification.png new file mode 100644 index 0000000000000000000000000000000000000000..11f355c8c2ec7e7fc6e926489ddc27920be35fa1 GIT binary patch literal 677 zcmV;W0$TlvP)Ebg({{a!H!ByCe zeRu{><6+!^%dy&DS8-Tm2_DA}@@L-TA#C(HxgoR;PvQ5HCClRr9>lpmH;NF1?@HH* z;*rmehOl0r9zmDSjfSvl9QG?@;Hb~c1OW?i6kE+$Ej}}ge8jV&Z`FF-DEii2z%f&I z18Yotc9PJ*H|#d!O`^}!KAdN-u`pMU$M7ZA`T0zU?k^KbLn%WzCz&sMf5}oiEreVw z?PZF~zBa&k3qDWm@$7O}OPP&i3^IDY&5{Cfsts z*QQ9p4Q;?d(dXy^zQNB@`ueZLEyn$mttfZh+$Kq0hQeThC#HdNSmrY-iu}!nxOfHb z61@%K*ZnF!#uihv8&4WTP0A}b7mh0N8zUDFm~hKpUz;KYKh&Kj+%oEGQ>5UA7U8&A zz|!IC15#u|0YYz?1uS=bZGiDMQ*+MG=SK7x;kk_qd~HDVtki&w@|zPtE(pG7nmHlK z&xYvP`X;vfYb?yq5D=4lDHX$05!oQfm5=WG|<60YGx(eu+4(XWkdSnsc!;h*FO^v6c)ADRJl00000 LNkvXXu0mjfIJ-+_ literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-mdpi/ic_notification.png b/android/app/src/main/res/drawable-mdpi/ic_notification.png new file mode 100644 index 0000000000000000000000000000000000000000..f76a3d82c59c82b58961de44da37c64816d70977 GIT binary patch literal 461 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 R@I3$k002ovPDHLkV1jF)plAR9 literal 0 HcmV?d00001 diff --git a/android/app/src/main/res/drawable-xxxhdpi/ic_notification.png b/android/app/src/main/res/drawable-xxxhdpi/ic_notification.png new file mode 100644 index 0000000000000000000000000000000000000000..b5067cf378aa1d46a696e02d1dc54e36991ec0d4 GIT binary patch literal 1798 zcmV+h2l@DkP)?paoG@R5oV=&C}bvSogy5{qA&z@4IK%54=CTcb|3l+S_x^-fOSDzX1aRfj}S- z2m}IwKp+sP17IjMgF1=2l6shWnfieGn)-?Qnfj61Ol_o|rPfdvQb$ugYB$gVHrSrj zxzy9tFUW?^sC%drsqOSPD-Ro`hq{P*FWPE-#9!1?)M9Fc)}>Og0S=}frT&h#P(Si5 zbpsD&$@Imlrbzb<5x`x_b>sl({kD7<5|F&{JKiJFs9BQc6z0lC1LDU)W5lazx zo0_G56cRcziF!sHECTkjwt>N5^{Fth^24bww)U%VT&I2&2Kb}LCQe0WsrpqY=)gqy zM5u_YReuTz9hn6m>J6p=NeXccj``Rs(#l9mK#I88}&LN7C*9?>v!;|X%>&SRa)O%!wQe2-l^(i~Zk6Eum&p6Ce{L{(A)6?vd2R@L1Cywd*^QE$X7+yCPzL@hu#BL+(jvS-c=NfoK^IvhKjy;mv4&hkl zOudl&3V&H=8kwZM1K{fbirtA*w0y2%g$Gk_i6hF3)Q)T}cpi`saSpsRWpxr>Vodi^{18n-9mXp&5 z!taMrw^7f>kgcjU!*YGJd@J3IyeA8=f^VRA!*Eo z)YF*QXlSz9O#&*~0XM3r3CLt=5*6)$IqGQwEKB+@wH+5!v;%Bc%;)ND0yZIKhBT_! z0R}wBKP`3_Ojp}+K!rQNf^4mJHnzhW?l`p@7x7TZGt^#E z;Oo)7q~%Hno!krY19KL2+(B&x5(0k&bjq#NFtrf{zQcVR{k$*X@9j*D)6WY5d|ja3 z`9GFTy+p57;OQ*(Ua{kd57Frwh=|!Azuf69z!$i0F60%jlwd!*2>ng z5z<=p(PnMhod;hyic-8YA`JL}e2q5C*=KE+_~56e*#E#r*l5NcU3=?wae-&Q*$SRz z^EG3oURMZM@tN=#Po0jop~BA%dOUJnD_*BAfdAGIwbcmtAsu#V%1zW)5nIi$J1^4& z;(i0ZcP!RMY?fOY^*#nRk9ZY62)LTMgj!BrM%@7KR7-PgwPxH5%X7^vWZti^;^XzR zX0Yt>$mVdRzQE3kEAK(x@W)6e8P(mST&E@0fuC|!l=DL~TRh4I@DbBX>SfMZrhXI_ zc=A@!u*uN%96WLro*4$+0`~T oH62xbo(BSfKp+qZ1OlD$KLy(6@-7Lb5dZ)H07*qoM6N<$f;8=Qx&QzG literal 0 HcmV?d00001 diff --git a/assets/images/logo-white.png b/assets/images/logo-white.png new file mode 100644 index 0000000000000000000000000000000000000000..8d04f2beed36bce373a58f52c3a999d7a63f3b29 GIT binary patch literal 35948 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

#{ zRf*bNnXLUlsfgtn`vv2hZ3trB)7EzrGu|$4`~~s&Cz1C{#T7Fos}!aN-1t7)K+)TK z7gRVAdPI}`w{UF8cP>c3VfP*Gjum3!K5B^-uSdN(V2~+6`9&;&Q^(4Lg6W-W=La1a zeNpckPH|4VDi-LsCyOH0W4M+JFtw8&gwV+XNB6le880i99^NJcp|J5+?8XBTf^Ak_ z$FcP;sc0Y2hN-Q3$iHEsSar{^FpMaC&|NWN|zo@Tw X?PKorKi~1;7E$(@?#=y!dh!1N$#7p% literal 0 HcmV?d00001 diff --git a/lib/apis/user_api.dart b/lib/apis/user_api.dart index 1bd78d8..8dec605 100644 --- a/lib/apis/user_api.dart +++ b/lib/apis/user_api.dart @@ -12,6 +12,13 @@ class UserApi { final data = jsonDecode(response.body) as List; return data.map((e) => User.fromMap(e)); } + + static Future getUser(ApiClient client, {required String userId}) async { + final response = await client.get("/users/$userId/"); + ApiClient.checkResponse(response); + final data = jsonDecode(response.body); + return User.fromMap(data); + } static Future addUserAsFriend(ApiClient client, {required User user}) async { final friend = Friend( diff --git a/lib/auxiliary.dart b/lib/auxiliary.dart index 7955fe5..03e5c2e 100644 --- a/lib/auxiliary.dart +++ b/lib/auxiliary.dart @@ -66,11 +66,13 @@ extension Unique on List { } } -extension StripHTLM on String { +extension Strip on String { String stripHtml() { final document = htmlparser.parse(this); return htmlparser.parse(document.body?.text).documentElement?.text ?? ""; } + + String stripUid() => startsWith("U-") ? substring(2) : this; } extension Format on Duration { diff --git a/lib/clients/api_client.dart b/lib/clients/api_client.dart index be646b9..e41ddd4 100644 --- a/lib/clients/api_client.dart +++ b/lib/clients/api_client.dart @@ -150,6 +150,7 @@ class ClientHolder extends InheritedWidget { final ApiClient apiClient; final SettingsClient settingsClient; late final MessagingClient messagingClient; + final NotificationClient notificationClient = NotificationClient(); ClientHolder({ super.key, @@ -157,7 +158,7 @@ class ClientHolder extends InheritedWidget { required this.settingsClient, required super.child }) : apiClient = ApiClient(authenticationData: authenticationData) { - messagingClient = MessagingClient(apiClient: apiClient); + messagingClient = MessagingClient(apiClient: apiClient, notificationClient: notificationClient); } static ClientHolder? maybeOf(BuildContext context) { diff --git a/lib/clients/messaging_client.dart b/lib/clients/messaging_client.dart index 23db9f5..d7ba827 100644 --- a/lib/clients/messaging_client.dart +++ b/lib/clients/messaging_client.dart @@ -1,9 +1,13 @@ 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/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'; @@ -19,7 +23,7 @@ enum EventType { enum EventTarget { unknown, messageSent, - messageReceived, + receiveMessage, messagesRead; factory EventTarget.parse(String? text) { @@ -41,11 +45,12 @@ class MessagingClient { final Map _updateListeners = {}; final Logger _logger = Logger("NeosHub"); final Workmanager _workmanager = Workmanager(); + final NotificationClient _notificationClient; WebSocket? _wsChannel; bool _isConnecting = false; - MessagingClient({required ApiClient apiClient}) - : _apiClient = apiClient { + MessagingClient({required ApiClient apiClient, required NotificationClient notificationClient}) + : _apiClient = apiClient, _notificationClient = notificationClient { start(); } @@ -183,11 +188,14 @@ class MessagingClient { cache.addMessage(message); notifyListener(message.recipientId); break; - case EventTarget.messageReceived: + case EventTarget.receiveMessage: final msg = args[0]; final message = Message.fromMap(msg); final cache = await getMessageCache(message.senderId); cache.addMessage(message); + if (!_updateListeners.containsKey(message.senderId)) { + _notificationClient.showUnreadMessagesNotification([message]); + } notifyListener(message.senderId); break; case EventTarget.messagesRead: @@ -229,3 +237,90 @@ 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(List 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/widgets/friends_list.dart b/lib/widgets/friends_list.dart index 725edab..ab47e10 100644 --- a/lib/widgets/friends_list.dart +++ b/lib/widgets/friends_list.dart @@ -60,7 +60,6 @@ class _FriendsListState extends State { _friendsFuture = FriendApi.getFriendsList(_clientHolder!.apiClient).then((Iterable value) async { final unreadMessages = await MessageApi.getUserMessages(_clientHolder!.apiClient, unreadOnly: true); _unreads.clear(); - for (final msg in unreadMessages) { if (msg.senderId != _clientHolder!.apiClient.userId) { final value = _unreads[msg.senderId]; @@ -128,7 +127,7 @@ class _FriendsListState extends State { } else { _autoRefresh = Timer(_autoRefreshDuration, () => setState(() => _refreshFriendsList())); } - }) + }), ].map((item) => PopupMenuItem( value: item, diff --git a/lib/widgets/messages_list.dart b/lib/widgets/messages_list.dart index baa501f..8338278 100644 --- a/lib/widgets/messages_list.dart +++ b/lib/widgets/messages_list.dart @@ -49,8 +49,15 @@ class _MessagesListState extends State { _messageCacheFutureComplete = false; _messageCacheFuture = _clientHolder?.messagingClient.getMessageCache(widget.friend.id) .whenComplete(() => _messageCacheFutureComplete = true); - _clientHolder?.messagingClient.registerListener( - widget.friend.id, () => setState(() {})); + final mClient = _clientHolder?.messagingClient; + final id = widget.friend.id; + mClient?.registerListener(id, () { + if (context.mounted) { + setState(() {}); + } else { + mClient.unregisterListener(id); + } + }); } @override diff --git a/pubspec.lock b/pubspec.lock index dac875f..fbeecd8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -74,7 +74,7 @@ packages: source: hosted version: "1.1.1" collection: - dependency: transitive + dependency: "direct main" description: name: collection sha256: cfc915e6923fe5ce6e153b0723c753045de46de1b4d63771530504004a45fae0 diff --git a/pubspec.yaml b/pubspec.yaml index c258a6a..3650ada 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -50,6 +50,7 @@ dependencies: url_launcher: ^6.1.10 workmanager: ^0.5.1 flutter_local_notifications: ^14.0.0+1 + collection: any dev_dependencies: flutter_test: