From e08114881c21fb9ad8b56c2c1f42a4437ecb211a Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Fri, 1 Apr 2022 15:54:06 -0700 Subject: [PATCH] store last seen time in lcg and handle unread counts --- LIBCWTCH-GO-MACOS.version | 2 +- LIBCWTCH-GO.version | 2 +- lib/cwtch/cwtch.dart | 2 ++ lib/cwtch/cwtchNotifier.dart | 15 +++++++++++++++ lib/cwtch/ffi.dart | 1 + lib/cwtch/gomobile.dart | 1 + lib/models/profile.dart | 3 +++ lib/views/contactsview.dart | 3 +++ 8 files changed, 27 insertions(+), 2 deletions(-) diff --git a/LIBCWTCH-GO-MACOS.version b/LIBCWTCH-GO-MACOS.version index 6216cb9d..f0e5617e 100644 --- a/LIBCWTCH-GO-MACOS.version +++ b/LIBCWTCH-GO-MACOS.version @@ -1 +1 @@ -2022-03-23-19-06-v1.6.0-13-g1acae32 +2022-04-04-17-46-v1.6.0-15-g97defdf diff --git a/LIBCWTCH-GO.version b/LIBCWTCH-GO.version index 13244799..4b001196 100644 --- a/LIBCWTCH-GO.version +++ b/LIBCWTCH-GO.version @@ -1 +1 @@ -2022-03-23-23-06-v1.6.0-13-g1acae32 +2022-04-04-21-46-v1.6.0-15-g97defdf \ No newline at end of file diff --git a/lib/cwtch/cwtch.dart b/lib/cwtch/cwtch.dart index f675a884..d42be68b 100644 --- a/lib/cwtch/cwtch.dart +++ b/lib/cwtch/cwtch.dart @@ -2,6 +2,8 @@ // Details: https://docs.openprivacy.ca/cwtch-security-handbook/profile_encryption_and_storage.html const DefaultPassword = "be gay do crime"; +const LastMessageSeenTimeKey = "profile.lastMessageSeenTime"; + abstract class Cwtch { // ignore: non_constant_identifier_names Future Start(); diff --git a/lib/cwtch/cwtchNotifier.dart b/lib/cwtch/cwtchNotifier.dart index 3f3b4951..66abce25 100644 --- a/lib/cwtch/cwtchNotifier.dart +++ b/lib/cwtch/cwtchNotifier.dart @@ -18,6 +18,8 @@ import '../config.dart'; import '../errorHandler.dart'; import '../settings.dart'; +typedef SeenMessageCallback = Function(String, int, DateTime); + // Class that handles libcwtch-go events (received either via ffi with an isolate or gomobile over a method channel from kotlin) // Takes Notifiers and triggers them on appropriate events class CwtchNotifier { @@ -32,6 +34,8 @@ class CwtchNotifier { String? notificationSimple; String? notificationConversationInfo; + SeenMessageCallback? seenMessageCallback; + CwtchNotifier( ProfileListState pcn, Settings settingsCN, ErrorHandler errorCN, TorStatus torStatusCN, NotificationsManager notificationManagerP, AppState appStateCN, ServerListState serverListStateCN) { profileCN = pcn; @@ -48,6 +52,10 @@ class CwtchNotifier { this.notificationConversationInfo = notificationConversationInfo; } + void setMessageSeenCallback(SeenMessageCallback callback) { + seenMessageCallback = callback; + } + void handleMessage(String type, dynamic data) { //EnvironmentConfig.debugLog("NewEvent $type $data"); switch (type) { @@ -164,6 +172,10 @@ class CwtchNotifier { var selectedConversation = selectedProfile && appState.selectedConversation == identifier; var notification = data["notification"]; + if (selectedConversation && seenMessageCallback != null) { + seenMessageCallback!(data["ProfileOnion"]!, identifier, DateTime.now().toUtc()); + } + if (notification == "SimpleEvent") { notificationManager.notify(notificationSimple ?? "New Message", "", 0); } else if (notification == "ContactInfo") { @@ -229,6 +241,9 @@ class CwtchNotifier { // and ensure that malicious contacts in groups can only set this timestamp to a value within the range of `last seen message time` // and `local now`. profileCN.getProfile(data["ProfileOnion"])?.newMessage(identifier, idx, timestampSent, senderHandle, senderImage, isAuto, data["Data"], contenthash, selectedProfile, selectedConversation); + if (selectedConversation && seenMessageCallback != null) { + seenMessageCallback!(data["ProfileOnion"]!, identifier, DateTime.now().toUtc()); + } if (notification == "SimpleEvent") { notificationManager.notify(notificationSimple ?? "New Message", "", 0); diff --git a/lib/cwtch/ffi.dart b/lib/cwtch/ffi.dart index 02a02486..22de1638 100644 --- a/lib/cwtch/ffi.dart +++ b/lib/cwtch/ffi.dart @@ -133,6 +133,7 @@ class CwtchFfi implements Cwtch { } library = DynamicLibrary.open(libraryPath); cwtchNotifier = _cwtchNotifier; + cwtchNotifier.setMessageSeenCallback((String profile, int conversation, DateTime time) => {this.SetConversationAttribute(profile, conversation, LastMessageSeenTimeKey, time.toIso8601String())}); } // ignore: non_constant_identifier_names diff --git a/lib/cwtch/gomobile.dart b/lib/cwtch/gomobile.dart index ded0b36c..7bd4f888 100644 --- a/lib/cwtch/gomobile.dart +++ b/lib/cwtch/gomobile.dart @@ -35,6 +35,7 @@ class CwtchGomobile implements Cwtch { CwtchGomobile(CwtchNotifier _cwtchNotifier) { print("gomobile.dart: CwtchGomobile()"); cwtchNotifier = _cwtchNotifier; + cwtchNotifier.setMessageSeenCallback((String profile, int conversation, DateTime time) => {this.SetConversationAttribute(profile, conversation, LastMessageSeenTimeKey, time.toIso8601String())}); androidHomeDirectory = getApplicationDocumentsDirectory(); androidLibraryDir = appInfoPlatform.invokeMethod('getNativeLibDir'); diff --git a/lib/models/profile.dart b/lib/models/profile.dart index 174193c4..16dcdf0b 100644 --- a/lib/models/profile.dart +++ b/lib/models/profile.dart @@ -50,6 +50,7 @@ class ProfileInfoState extends ChangeNotifier { List contacts = jsonDecode(contactsJson); this._contacts.addAll(contacts.map((contact) { + this._unreadMessages += contact["numUnread"] as int; return ContactInfoState(this.onion, contact["identifier"], contact["onion"], nickname: contact["name"], status: contact["status"], @@ -164,12 +165,14 @@ class ProfileInfoState extends ChangeNotifier { this._nickname = name; this._imagePath = picture; this._online = online; + this._unreadMessages = 0; this.replaceServers(serverJson); if (contactsJson != null && contactsJson != "" && contactsJson != "null") { List contacts = jsonDecode(contactsJson); contacts.forEach((contact) { var profileContact = this._contacts.getContact(contact["identifier"]); + this._unreadMessages += contact["numUnread"] as int; if (profileContact != null) { profileContact.status = contact["status"]; profileContact.totalMessages = contact["numMessages"]; // Todo: trigger cache update (bulk upload) diff --git a/lib/views/contactsview.dart b/lib/views/contactsview.dart index 216e5e1f..14cbbd13 100644 --- a/lib/views/contactsview.dart +++ b/lib/views/contactsview.dart @@ -1,3 +1,4 @@ +import 'package:cwtch/cwtch/cwtch.dart'; import 'package:cwtch/cwtch_icons_icons.dart'; import 'package:cwtch/models/appstate.dart'; import 'package:cwtch/models/contact.dart'; @@ -38,6 +39,8 @@ void selectConversation(BuildContext context, int handle) { // if in singlepane mode, push to the stack var isLandscape = Provider.of(context, listen: false).isLandscape(context); if (Provider.of(context, listen: false).uiColumns(isLandscape).length == 1) _pushMessageView(context, handle); + // Set last message seen time in backend + Provider.of(context, listen: false).cwtch.SetConversationAttribute(Provider.of(context, listen: false).onion, handle, LastMessageSeenTimeKey, DateTime.now().toUtc().toIso8601String()); } void _pushMessageView(BuildContext context, int handle) {