From b382c3d349c17fd691134631b4739b37ab02f078 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Fri, 4 Feb 2022 17:19:02 -0500 Subject: [PATCH] desktop support for notification settings --- lib/cwtch/cwtchNotifier.dart | 22 +++++++++++++++--- lib/models/contact.dart | 21 ++++++++++++++++- lib/models/profile.dart | 4 +++- lib/settings.dart | 10 ++++---- lib/views/groupsettingsview.dart | 35 +++++++++++++++++++++++++++- lib/views/peersettingsview.dart | 40 +++++++++++++++++++++++++++++++- 6 files changed, 120 insertions(+), 12 deletions(-) diff --git a/lib/cwtch/cwtchNotifier.dart b/lib/cwtch/cwtchNotifier.dart index d3b74765..4136644d 100644 --- a/lib/cwtch/cwtchNotifier.dart +++ b/lib/cwtch/cwtchNotifier.dart @@ -77,6 +77,7 @@ class CwtchNotifier { server: null, archived: false, lastMessageTime: DateTime.now(), //show at the top of the contact list even if no messages yet + options: data["options"] )); break; case "NewServer": @@ -113,7 +114,8 @@ class CwtchNotifier { status: status, server: data["GroupServer"], isGroup: true, - lastMessageTime: DateTime.now())); + lastMessageTime: DateTime.now(), + options: data["options"])); profileCN.getProfile(data["ProfileOnion"])?.contactList.updateLastMessageTime(int.parse(data["ConversationID"]), DateTime.now()); } break; @@ -144,7 +146,7 @@ class CwtchNotifier { } break; case "NewMessageFromPeer": - notificationManager.notify("New Message From Peer!"); + var identifier = int.parse(data["ConversationID"]); var messageID = int.parse(data["Index"]); var timestamp = DateTime.tryParse(data['TimestampReceived'])!; @@ -154,6 +156,14 @@ class CwtchNotifier { String? contenthash = data['ContentHash']; var selectedProfile = appState.selectedProfile == data["ProfileOnion"]; var selectedConversation = selectedProfile && appState.selectedConversation == identifier; + var notification = data["notification"]; + + if (notification == "SimpleEvent") { + notificationManager.notify(/*TODO l10n */ "New Message"); + } else if (notification == "ContactInfo") { + var contact = profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(identifier); + notificationManager.notify(/*TODO l10n */ "New Message from " + (contact?.nickname ?? senderHandle.toString())); + } profileCN.getProfile(data["ProfileOnion"])?.newMessage( identifier, @@ -209,6 +219,7 @@ class CwtchNotifier { String? contenthash = data['ContentHash']; var selectedProfile = appState.selectedProfile == data["ProfileOnion"]; var selectedConversation = selectedProfile && appState.selectedConversation == identifier; + var notification = data["notification"]; // Only bother to do anything if we know about the group and the provided index is greater than our current total... if (currentTotal != null && idx >= currentTotal) { @@ -224,7 +235,12 @@ class CwtchNotifier { // and `local now`. profileCN.getProfile(data["ProfileOnion"])?.newMessage(identifier, idx, timestampSent, senderHandle, senderImage, isAuto, data["Data"], contenthash, selectedProfile, selectedConversation); - notificationManager.notify("New Message From Group!"); + if (notification == "SimpleEvent") { + notificationManager.notify(/*TODO l10n */ "New Message"); + } else if (notification == "ContactInfo") { + var contact = profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(identifier); + notificationManager.notify(/*TODO l10n */ "New Message from " + (contact?.nickname ?? senderHandle.toString())); + } appState.notifyProfileUnread(); } RemoteServerInfoState? server = profileCN.getProfile(data["ProfileOnion"])?.serverList.getServer(contact.server ?? ""); diff --git a/lib/models/contact.dart b/lib/models/contact.dart index 38cd31cd..3cfd604d 100644 --- a/lib/models/contact.dart +++ b/lib/models/contact.dart @@ -10,6 +10,9 @@ class ContactInfoState extends ChangeNotifier { final String onion; late String _nickname; + late bool _notificationsOptIn; + late bool _notificationsOptOut; + late bool _accepted; late bool _blocked; late String _status; @@ -44,7 +47,8 @@ class ContactInfoState extends ChangeNotifier { numUnread = 0, lastMessageTime, server, - archived = false}) { + archived = false, + options = const {} }) { this._nickname = nickname; this._isGroup = isGroup; this._accepted = accepted; @@ -58,6 +62,9 @@ class ContactInfoState extends ChangeNotifier { this._lastMessageTime = lastMessageTime == null ? DateTime.fromMillisecondsSinceEpoch(0) : lastMessageTime; this._server = server; this._archived = archived; + print("Contact: $_nickname, Options: $options opt-in: ${options["notification-opt-in"]} opt-out: ${options["notification-opt-out"]} "); + this._notificationsOptIn = (options["notification-opt-in"] ?? "false") == "true"; + this._notificationsOptOut = (options["notification-opt-out"] ?? "false") == "true"; this.messageCache = new MessageCache(); keys = Map>(); } @@ -195,6 +202,18 @@ class ContactInfoState extends ChangeNotifier { } } + bool get notificationsOptIn => _notificationsOptIn; + set notificationsOptIn(bool newVal) { + _notificationsOptIn = newVal; + notifyListeners(); + } + + bool get notificationsOptOut => _notificationsOptOut; + set notificationsOptOut(bool newVal) { + _notificationsOptOut = newVal; + notifyListeners(); + } + GlobalKey getMessageKey(int conversation, int message) { String index = "c: " + conversation.toString() + " m:" + message.toString(); if (keys[index] == null) { diff --git a/lib/models/profile.dart b/lib/models/profile.dart index 070a25cc..a50c9922 100644 --- a/lib/models/profile.dart +++ b/lib/models/profile.dart @@ -63,7 +63,8 @@ class ProfileInfoState extends ChangeNotifier { isGroup: contact["isGroup"], server: contact["groupServer"], archived: contact["isArchived"] == true, - lastMessageTime: DateTime.fromMillisecondsSinceEpoch(1000 * int.parse(contact["lastMsgTime"]))); + lastMessageTime: DateTime.fromMillisecondsSinceEpoch(1000 * int.parse(contact["lastMsgTime"])), + options: contact["options"]); })); // dummy set to invoke sort-on-load @@ -183,6 +184,7 @@ class ProfileInfoState extends ChangeNotifier { isGroup: contact["isGroup"], server: contact["groupServer"], lastMessageTime: DateTime.fromMillisecondsSinceEpoch(1000 * int.parse(contact["lastMsgTime"])), + options: contact["options"], )); } unreadMessages += int.parse(contact["numUnread"]); diff --git a/lib/settings.dart b/lib/settings.dart index ab1cca53..b13eaea6 100644 --- a/lib/settings.dart +++ b/lib/settings.dart @@ -274,11 +274,11 @@ class Settings extends ChangeNotifier { static NotificationPolicy notificationPolicyFromString(String? np) { switch (np) { - case "None": + case "NotificationPolicy.None": return NotificationPolicy.None; - case "OptIn": + case "NotificationPolicy.OptIn": return NotificationPolicy.OptIn; - case "OptOut": + case "NotificationPolicy.OptOut": return NotificationPolicy.OptOut; } return NotificationPolicy.OptOut; @@ -286,9 +286,9 @@ class Settings extends ChangeNotifier { static NotificationContent notificationContentFromString(String? nc) { switch (nc) { - case "SimpleEvent": + case "NotificationContent.SimpleEvent": return NotificationContent.SimpleEvent; - case "ContactInfo": + case "NotificationContent.ContactInfo": return NotificationContent.ContactInfo; } return NotificationContent.SimpleEvent; diff --git a/lib/views/groupsettingsview.dart b/lib/views/groupsettingsview.dart index 1026bf05..9d7f2bf9 100644 --- a/lib/views/groupsettingsview.dart +++ b/lib/views/groupsettingsview.dart @@ -130,7 +130,40 @@ class _GroupSettingsViewState extends State { SizedBox( height: 20, ), - // TODO + Visibility( + visible: Provider.of(context, listen: false).notificationPolicy == NotificationPolicy.OptOut, + child: SwitchListTile( + title: Text(/*AppLocalizations.of(context)!.savePeerHistory*/"Notifications Opt Out", style: TextStyle(color: settings.current().mainTextColor)), + subtitle: Text(/*AppLocalizations.of(context)!.savePeerHistoryDescription*/"The system blah blah..."), + secondary: Icon(CwtchIcons.chat_bubble_empty_24px, color: settings.current().mainTextColor), + value: Provider.of(context).notificationsOptOut, + onChanged: (bool optOut) { + Provider.of(context, listen: false).notificationsOptOut = optOut; + var profileOnion = Provider.of(context, listen: false).profileOnion; + var identifier = Provider.of(context, listen: false).identifier; + const NotificationOptOutKey = "profile.notification-opt-out"; + Provider.of(context, listen: false).cwtch.SetConversationAttribute(profileOnion, identifier, NotificationOptOutKey, optOut.toString()); + }, + activeTrackColor: settings.theme.defaultButtonColor, + inactiveTrackColor: settings.theme.defaultButtonDisabledColor, + )), + Visibility( + visible: Provider.of(context, listen: false).notificationPolicy == NotificationPolicy.OptIn, + child: SwitchListTile( + title: Text(/*AppLocalizations.of(context)!.savePeerHistory*/"Notifications Opt In", style: TextStyle(color: settings.current().mainTextColor)), + subtitle: Text(/*AppLocalizations.of(context)!.savePeerHistoryDescription*/"The system blah blah..."), + secondary: Icon(CwtchIcons.chat_bubble_empty_24px, color: settings.current().mainTextColor), + value: Provider.of(context).notificationsOptIn, + onChanged: (bool optIn) { + Provider.of(context, listen: false).notificationsOptIn = optIn; + var profileOnion = Provider.of(context, listen: false).profileOnion; + var identifier = Provider.of(context, listen: false).identifier; + const NotificationOptInKey = "profile.notification-opt-in"; + Provider.of(context, listen: false).cwtch.SetConversationAttribute(profileOnion, identifier, NotificationOptInKey, optIn.toString()); + }, + activeTrackColor: settings.theme.defaultButtonColor, + inactiveTrackColor: settings.theme.defaultButtonDisabledColor, + )) ]), Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.end, children: [ diff --git a/lib/views/peersettingsview.dart b/lib/views/peersettingsview.dart index 0206c175..b45954c8 100644 --- a/lib/views/peersettingsview.dart +++ b/lib/views/peersettingsview.dart @@ -39,9 +39,13 @@ class _PeerSettingsViewState extends State { @override Widget build(BuildContext context) { + var handle = Provider.of(context).nickname; + if (handle.isEmpty) { + handle = Provider.of(context).onion; + } return Scaffold( appBar: AppBar( - title: Text(Provider.of(context).onion), + title: Text(handle + " " + AppLocalizations.of(context)!.conversationSettings), ), body: _buildSettingsList(), ); @@ -197,6 +201,40 @@ class _PeerSettingsViewState extends State { child: Text(value), ); }).toList())), + Visibility( + visible: Provider.of(context, listen: false).notificationPolicy == NotificationPolicy.OptOut, + child: SwitchListTile( + title: Text(/*AppLocalizations.of(context)!.savePeerHistory*/"Notifications Opt Out", style: TextStyle(color: settings.current().mainTextColor)), + subtitle: Text(/*AppLocalizations.of(context)!.savePeerHistoryDescription*/"The system blah blah..."), + secondary: Icon(CwtchIcons.chat_bubble_empty_24px, color: settings.current().mainTextColor), + value: Provider.of(context).notificationsOptOut, + onChanged: (bool optOut) { + Provider.of(context, listen: false).notificationsOptOut = optOut; + var profileOnion = Provider.of(context, listen: false).profileOnion; + var identifier = Provider.of(context, listen: false).identifier; + const NotificationOptOutKey = "profile.notification-opt-out"; + Provider.of(context, listen: false).cwtch.SetConversationAttribute(profileOnion, identifier, NotificationOptOutKey, optOut.toString()); + }, + activeTrackColor: settings.theme.defaultButtonColor, + inactiveTrackColor: settings.theme.defaultButtonDisabledColor, + )), + Visibility( + visible: Provider.of(context, listen: false).notificationPolicy == NotificationPolicy.OptIn, + child: SwitchListTile( + title: Text(/*AppLocalizations.of(context)!.savePeerHistory*/"Notifications Opt In", style: TextStyle(color: settings.current().mainTextColor)), + subtitle: Text(/*AppLocalizations.of(context)!.savePeerHistoryDescription*/"The system blah blah..."), + secondary: Icon(CwtchIcons.chat_bubble_empty_24px, color: settings.current().mainTextColor), + value: Provider.of(context).notificationsOptIn, + onChanged: (bool optIn) { + Provider.of(context, listen: false).notificationsOptIn = optIn; + var profileOnion = Provider.of(context, listen: false).profileOnion; + var identifier = Provider.of(context, listen: false).identifier; + const NotificationOptInKey = "profile.notification-opt-in"; + Provider.of(context, listen: false).cwtch.SetConversationAttribute(profileOnion, identifier, NotificationOptInKey, optIn.toString()); + }, + activeTrackColor: settings.theme.defaultButtonColor, + inactiveTrackColor: settings.theme.defaultButtonDisabledColor, + )) ]), Column(mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end, children: [ SizedBox(