desktop support for notification settings

This commit is contained in:
Dan Ballard 2022-02-04 17:19:02 -05:00
parent c550437aa5
commit b382c3d349
6 changed files with 120 additions and 12 deletions

View File

@ -77,6 +77,7 @@ class CwtchNotifier {
server: null, server: null,
archived: false, archived: false,
lastMessageTime: DateTime.now(), //show at the top of the contact list even if no messages yet lastMessageTime: DateTime.now(), //show at the top of the contact list even if no messages yet
options: data["options"]
)); ));
break; break;
case "NewServer": case "NewServer":
@ -113,7 +114,8 @@ class CwtchNotifier {
status: status, status: status,
server: data["GroupServer"], server: data["GroupServer"],
isGroup: true, isGroup: true,
lastMessageTime: DateTime.now())); lastMessageTime: DateTime.now(),
options: data["options"]));
profileCN.getProfile(data["ProfileOnion"])?.contactList.updateLastMessageTime(int.parse(data["ConversationID"]), DateTime.now()); profileCN.getProfile(data["ProfileOnion"])?.contactList.updateLastMessageTime(int.parse(data["ConversationID"]), DateTime.now());
} }
break; break;
@ -144,7 +146,7 @@ class CwtchNotifier {
} }
break; break;
case "NewMessageFromPeer": case "NewMessageFromPeer":
notificationManager.notify("New Message From Peer!");
var identifier = int.parse(data["ConversationID"]); var identifier = int.parse(data["ConversationID"]);
var messageID = int.parse(data["Index"]); var messageID = int.parse(data["Index"]);
var timestamp = DateTime.tryParse(data['TimestampReceived'])!; var timestamp = DateTime.tryParse(data['TimestampReceived'])!;
@ -154,6 +156,14 @@ class CwtchNotifier {
String? contenthash = data['ContentHash']; String? contenthash = data['ContentHash'];
var selectedProfile = appState.selectedProfile == data["ProfileOnion"]; var selectedProfile = appState.selectedProfile == data["ProfileOnion"];
var selectedConversation = selectedProfile && appState.selectedConversation == identifier; 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( profileCN.getProfile(data["ProfileOnion"])?.newMessage(
identifier, identifier,
@ -209,6 +219,7 @@ class CwtchNotifier {
String? contenthash = data['ContentHash']; String? contenthash = data['ContentHash'];
var selectedProfile = appState.selectedProfile == data["ProfileOnion"]; var selectedProfile = appState.selectedProfile == data["ProfileOnion"];
var selectedConversation = selectedProfile && appState.selectedConversation == identifier; 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... // 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) { if (currentTotal != null && idx >= currentTotal) {
@ -224,7 +235,12 @@ class CwtchNotifier {
// and `local now`. // and `local now`.
profileCN.getProfile(data["ProfileOnion"])?.newMessage(identifier, idx, timestampSent, senderHandle, senderImage, isAuto, data["Data"], contenthash, selectedProfile, selectedConversation); 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(); appState.notifyProfileUnread();
} }
RemoteServerInfoState? server = profileCN.getProfile(data["ProfileOnion"])?.serverList.getServer(contact.server ?? ""); RemoteServerInfoState? server = profileCN.getProfile(data["ProfileOnion"])?.serverList.getServer(contact.server ?? "");

View File

@ -10,6 +10,9 @@ class ContactInfoState extends ChangeNotifier {
final String onion; final String onion;
late String _nickname; late String _nickname;
late bool _notificationsOptIn;
late bool _notificationsOptOut;
late bool _accepted; late bool _accepted;
late bool _blocked; late bool _blocked;
late String _status; late String _status;
@ -44,7 +47,8 @@ class ContactInfoState extends ChangeNotifier {
numUnread = 0, numUnread = 0,
lastMessageTime, lastMessageTime,
server, server,
archived = false}) { archived = false,
options = const {} }) {
this._nickname = nickname; this._nickname = nickname;
this._isGroup = isGroup; this._isGroup = isGroup;
this._accepted = accepted; this._accepted = accepted;
@ -58,6 +62,9 @@ class ContactInfoState extends ChangeNotifier {
this._lastMessageTime = lastMessageTime == null ? DateTime.fromMillisecondsSinceEpoch(0) : lastMessageTime; this._lastMessageTime = lastMessageTime == null ? DateTime.fromMillisecondsSinceEpoch(0) : lastMessageTime;
this._server = server; this._server = server;
this._archived = archived; 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(); this.messageCache = new MessageCache();
keys = Map<String, GlobalKey<MessageRowState>>(); keys = Map<String, GlobalKey<MessageRowState>>();
} }
@ -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<MessageRowState> getMessageKey(int conversation, int message) { GlobalKey<MessageRowState> getMessageKey(int conversation, int message) {
String index = "c: " + conversation.toString() + " m:" + message.toString(); String index = "c: " + conversation.toString() + " m:" + message.toString();
if (keys[index] == null) { if (keys[index] == null) {

View File

@ -63,7 +63,8 @@ class ProfileInfoState extends ChangeNotifier {
isGroup: contact["isGroup"], isGroup: contact["isGroup"],
server: contact["groupServer"], server: contact["groupServer"],
archived: contact["isArchived"] == true, 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 // dummy set to invoke sort-on-load
@ -183,6 +184,7 @@ class ProfileInfoState extends ChangeNotifier {
isGroup: contact["isGroup"], isGroup: contact["isGroup"],
server: contact["groupServer"], server: contact["groupServer"],
lastMessageTime: DateTime.fromMillisecondsSinceEpoch(1000 * int.parse(contact["lastMsgTime"])), lastMessageTime: DateTime.fromMillisecondsSinceEpoch(1000 * int.parse(contact["lastMsgTime"])),
options: contact["options"],
)); ));
} }
unreadMessages += int.parse(contact["numUnread"]); unreadMessages += int.parse(contact["numUnread"]);

View File

@ -274,11 +274,11 @@ class Settings extends ChangeNotifier {
static NotificationPolicy notificationPolicyFromString(String? np) { static NotificationPolicy notificationPolicyFromString(String? np) {
switch (np) { switch (np) {
case "None": case "NotificationPolicy.None":
return NotificationPolicy.None; return NotificationPolicy.None;
case "OptIn": case "NotificationPolicy.OptIn":
return NotificationPolicy.OptIn; return NotificationPolicy.OptIn;
case "OptOut": case "NotificationPolicy.OptOut":
return NotificationPolicy.OptOut; return NotificationPolicy.OptOut;
} }
return NotificationPolicy.OptOut; return NotificationPolicy.OptOut;
@ -286,9 +286,9 @@ class Settings extends ChangeNotifier {
static NotificationContent notificationContentFromString(String? nc) { static NotificationContent notificationContentFromString(String? nc) {
switch (nc) { switch (nc) {
case "SimpleEvent": case "NotificationContent.SimpleEvent":
return NotificationContent.SimpleEvent; return NotificationContent.SimpleEvent;
case "ContactInfo": case "NotificationContent.ContactInfo":
return NotificationContent.ContactInfo; return NotificationContent.ContactInfo;
} }
return NotificationContent.SimpleEvent; return NotificationContent.SimpleEvent;

View File

@ -130,7 +130,40 @@ class _GroupSettingsViewState extends State<GroupSettingsView> {
SizedBox( SizedBox(
height: 20, height: 20,
), ),
// TODO Visibility(
visible: Provider.of<Settings>(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<ContactInfoState>(context).notificationsOptOut,
onChanged: (bool optOut) {
Provider.of<ContactInfoState>(context, listen: false).notificationsOptOut = optOut;
var profileOnion = Provider.of<ContactInfoState>(context, listen: false).profileOnion;
var identifier = Provider.of<ContactInfoState>(context, listen: false).identifier;
const NotificationOptOutKey = "profile.notification-opt-out";
Provider.of<FlwtchState>(context, listen: false).cwtch.SetConversationAttribute(profileOnion, identifier, NotificationOptOutKey, optOut.toString());
},
activeTrackColor: settings.theme.defaultButtonColor,
inactiveTrackColor: settings.theme.defaultButtonDisabledColor,
)),
Visibility(
visible: Provider.of<Settings>(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<ContactInfoState>(context).notificationsOptIn,
onChanged: (bool optIn) {
Provider.of<ContactInfoState>(context, listen: false).notificationsOptIn = optIn;
var profileOnion = Provider.of<ContactInfoState>(context, listen: false).profileOnion;
var identifier = Provider.of<ContactInfoState>(context, listen: false).identifier;
const NotificationOptInKey = "profile.notification-opt-in";
Provider.of<FlwtchState>(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: [ Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.end, children: [

View File

@ -39,9 +39,13 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var handle = Provider.of<ContactInfoState>(context).nickname;
if (handle.isEmpty) {
handle = Provider.of<ContactInfoState>(context).onion;
}
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(Provider.of<ContactInfoState>(context).onion), title: Text(handle + " " + AppLocalizations.of(context)!.conversationSettings),
), ),
body: _buildSettingsList(), body: _buildSettingsList(),
); );
@ -197,6 +201,40 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
child: Text(value), child: Text(value),
); );
}).toList())), }).toList())),
Visibility(
visible: Provider.of<Settings>(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<ContactInfoState>(context).notificationsOptOut,
onChanged: (bool optOut) {
Provider.of<ContactInfoState>(context, listen: false).notificationsOptOut = optOut;
var profileOnion = Provider.of<ContactInfoState>(context, listen: false).profileOnion;
var identifier = Provider.of<ContactInfoState>(context, listen: false).identifier;
const NotificationOptOutKey = "profile.notification-opt-out";
Provider.of<FlwtchState>(context, listen: false).cwtch.SetConversationAttribute(profileOnion, identifier, NotificationOptOutKey, optOut.toString());
},
activeTrackColor: settings.theme.defaultButtonColor,
inactiveTrackColor: settings.theme.defaultButtonDisabledColor,
)),
Visibility(
visible: Provider.of<Settings>(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<ContactInfoState>(context).notificationsOptIn,
onChanged: (bool optIn) {
Provider.of<ContactInfoState>(context, listen: false).notificationsOptIn = optIn;
var profileOnion = Provider.of<ContactInfoState>(context, listen: false).profileOnion;
var identifier = Provider.of<ContactInfoState>(context, listen: false).identifier;
const NotificationOptInKey = "profile.notification-opt-in";
Provider.of<FlwtchState>(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: [ Column(mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end, children: [
SizedBox( SizedBox(