rejig notification policy globally and conversationally

This commit is contained in:
Dan Ballard 2022-02-07 21:13:49 -05:00
parent b382c3d349
commit ddefcb8ff2
6 changed files with 114 additions and 110 deletions

View File

@ -60,25 +60,24 @@ class CwtchNotifier {
case "ContactCreated":
EnvironmentConfig.debugLog("ContactCreated $data");
profileCN.getProfile(data["ProfileOnion"])?.contactList.add(ContactInfoState(
data["ProfileOnion"],
int.parse(data["ConversationID"]),
data["RemotePeer"],
nickname: data["nick"],
status: data["status"],
imagePath: data["picture"],
defaultImagePath: data["defaultPicture"],
blocked: data["blocked"] == "true",
accepted: data["accepted"] == "true",
savePeerHistory: data["saveConversationHistory"] == null ? "DeleteHistoryConfirmed" : data["saveConversationHistory"],
numMessages: int.parse(data["numMessages"]),
numUnread: int.parse(data["unread"]),
isGroup: false, // by definition
server: null,
archived: false,
lastMessageTime: DateTime.now(), //show at the top of the contact list even if no messages yet
options: data["options"]
));
profileCN.getProfile(data["ProfileOnion"])?.contactList.add(ContactInfoState(data["ProfileOnion"], int.parse(data["ConversationID"]), data["RemotePeer"],
nickname: data["nick"],
status: data["status"],
imagePath: data["picture"],
defaultImagePath: data["defaultPicture"],
blocked: data["blocked"] == "true",
accepted: data["accepted"] == "true",
savePeerHistory: data["saveConversationHistory"] == null ? "DeleteHistoryConfirmed" : data["saveConversationHistory"],
numMessages: int.parse(data["numMessages"]),
numUnread: int.parse(data["unread"]),
isGroup: false,
// by definition
server: null,
archived: false,
lastMessageTime: DateTime.now(),
//show at the top of the contact list even if no messages yet
notificationPolicy: data["notificationPolicy"] ?? "ConversationNotificationPolicy.Default"));
break;
case "NewServer":
EnvironmentConfig.debugLog("NewServer $data");
@ -106,8 +105,10 @@ class CwtchNotifier {
}
if (profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(int.parse(data["ConversationID"])) == null) {
profileCN.getProfile(data["ProfileOnion"])?.contactList.add(ContactInfoState(data["ProfileOnion"], int.parse(data["ConversationID"]), data["GroupID"],
blocked: false, // we created
accepted: true, // we created
blocked: false,
// we created
accepted: true,
// we created
imagePath: data["picture"],
defaultImagePath: data["picture"],
nickname: data["GroupName"],
@ -115,7 +116,8 @@ class CwtchNotifier {
server: data["GroupServer"],
isGroup: true,
lastMessageTime: DateTime.now(),
options: data["options"]));
notificationPolicy: data["notificationPolicy"] ?? "ConversationNotificationPolicy.Default"));
profileCN.getProfile(data["ProfileOnion"])?.contactList.updateLastMessageTime(int.parse(data["ConversationID"]), DateTime.now());
}
break;
@ -146,7 +148,6 @@ class CwtchNotifier {
}
break;
case "NewMessageFromPeer":
var identifier = int.parse(data["ConversationID"]);
var messageID = int.parse(data["Index"]);
var timestamp = DateTime.tryParse(data['TimestampReceived'])!;
@ -319,8 +320,10 @@ class CwtchNotifier {
if (profileCN.getProfile(data["ProfileOnion"])?.contactList.findContact(groupInvite["GroupID"]) == null) {
var identifier = int.parse(data["ConversationID"]);
profileCN.getProfile(data["ProfileOnion"])?.contactList.add(ContactInfoState(data["ProfileOnion"], identifier, groupInvite["GroupID"],
blocked: false, // NewGroup only issued on accepting invite
accepted: true, // NewGroup only issued on accepting invite
blocked: false,
// NewGroup only issued on accepting invite
accepted: true,
// NewGroup only issued on accepting invite
imagePath: data["picture"],
nickname: groupInvite["GroupName"],
server: groupInvite["ServerHost"],

View File

@ -4,14 +4,32 @@ import 'package:flutter/widgets.dart';
import 'message.dart';
import 'messagecache.dart';
enum ConversationNotificationPolicy {
Default,
OptIn,
Never,
}
extension Nameable on ConversationNotificationPolicy {
String get toName {
switch (this) {
case ConversationNotificationPolicy.Default:
return "Default";
case ConversationNotificationPolicy.OptIn:
return "Opt In";
case ConversationNotificationPolicy.Never:
return "Never";
}
}
}
class ContactInfoState extends ChangeNotifier {
final String profileOnion;
final int identifier;
final String onion;
late String _nickname;
late bool _notificationsOptIn;
late bool _notificationsOptOut;
late ConversationNotificationPolicy _notificationPolicy;
late bool _accepted;
late bool _blocked;
@ -48,7 +66,7 @@ class ContactInfoState extends ChangeNotifier {
lastMessageTime,
server,
archived = false,
options = const {} }) {
notificationPolicy = "ConversationNotificationPolicy.Default"}) {
this._nickname = nickname;
this._isGroup = isGroup;
this._accepted = accepted;
@ -62,9 +80,7 @@ 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._notificationPolicy = notificationPolicyFromString(notificationPolicy);
this.messageCache = new MessageCache();
keys = Map<String, GlobalKey<MessageRowState>>();
}
@ -202,15 +218,10 @@ class ContactInfoState extends ChangeNotifier {
}
}
bool get notificationsOptIn => _notificationsOptIn;
set notificationsOptIn(bool newVal) {
_notificationsOptIn = newVal;
notifyListeners();
}
ConversationNotificationPolicy get notificationsPolicy => _notificationPolicy;
bool get notificationsOptOut => _notificationsOptOut;
set notificationsOptOut(bool newVal) {
_notificationsOptOut = newVal;
set notificationsPolicy(ConversationNotificationPolicy newVal) {
_notificationPolicy = newVal;
notifyListeners();
}
@ -257,4 +268,16 @@ class ContactInfoState extends ChangeNotifier {
this.messageCache.ackCache(messageID);
notifyListeners();
}
static ConversationNotificationPolicy notificationPolicyFromString(String val) {
switch (val) {
case "ConversationNotificationPolicy.Default":
return ConversationNotificationPolicy.Default;
case "ConversationNotificationPolicy.OptIn":
return ConversationNotificationPolicy.OptIn;
case "ConversationNotificationPolicy.Never":
return ConversationNotificationPolicy.Never;
}
return ConversationNotificationPolicy.Never;
}
}

View File

@ -64,7 +64,7 @@ class ProfileInfoState extends ChangeNotifier {
server: contact["groupServer"],
archived: contact["isArchived"] == true,
lastMessageTime: DateTime.fromMillisecondsSinceEpoch(1000 * int.parse(contact["lastMsgTime"])),
options: contact["options"]);
notificationPolicy: contact["notificationPolicy"] ?? "ConversationNotificationPolicy.Default");
}));
// dummy set to invoke sort-on-load
@ -101,6 +101,7 @@ class ProfileInfoState extends ChangeNotifier {
// Getters and Setters for Online Status
bool get isOnline => this._online;
set isOnline(bool newValue) {
this._online = newValue;
notifyListeners();
@ -110,24 +111,28 @@ class ProfileInfoState extends ChangeNotifier {
bool get isEncrypted => this._encrypted;
String get nickname => this._nickname;
set nickname(String newValue) {
this._nickname = newValue;
notifyListeners();
}
String get imagePath => this._imagePath;
set imagePath(String newVal) {
this._imagePath = newVal;
notifyListeners();
}
String get defaultImagePath => this._defaultImagePath;
set defaultImagePath(String newVal) {
this._defaultImagePath = newVal;
notifyListeners();
}
int get unreadMessages => this._unreadMessages;
set unreadMessages(int newVal) {
this._unreadMessages = newVal;
notifyListeners();
@ -145,6 +150,7 @@ class ProfileInfoState extends ChangeNotifier {
}
ContactListState get contactList => this._contacts;
ProfileServerListState get serverList => this._servers;
@override
@ -184,7 +190,7 @@ class ProfileInfoState extends ChangeNotifier {
isGroup: contact["isGroup"],
server: contact["groupServer"],
lastMessageTime: DateTime.fromMillisecondsSinceEpoch(1000 * int.parse(contact["lastMsgTime"])),
options: contact["options"],
notificationPolicy: contact["notificationPolicy"] ?? "ConversationNotificationPolicy.Default",
));
}
unreadMessages += int.parse(contact["numUnread"]);

View File

@ -23,9 +23,9 @@ enum DualpaneMode {
}
enum NotificationPolicy {
None,
Mute,
OptIn,
OptOut,
DefaultAll,
}
enum NotificationContent {
@ -47,7 +47,7 @@ class Settings extends ChangeNotifier {
DualpaneMode _uiColumnModePortrait = DualpaneMode.Single;
DualpaneMode _uiColumnModeLandscape = DualpaneMode.CopyPortrait;
NotificationPolicy _notificationPolicy = NotificationPolicy.OptOut;
NotificationPolicy _notificationPolicy = NotificationPolicy.DefaultAll;
NotificationContent _notificationContent = NotificationContent.SimpleEvent;
bool blockUnknownConnections = false;
@ -275,13 +275,13 @@ class Settings extends ChangeNotifier {
static NotificationPolicy notificationPolicyFromString(String? np) {
switch (np) {
case "NotificationPolicy.None":
return NotificationPolicy.None;
return NotificationPolicy.Mute;
case "NotificationPolicy.OptIn":
return NotificationPolicy.OptIn;
case "NotificationPolicy.OptOut":
return NotificationPolicy.OptOut;
return NotificationPolicy.DefaultAll;
}
return NotificationPolicy.OptOut;
return NotificationPolicy.DefaultAll;
}
static NotificationContent notificationContentFromString(String? nc) {
@ -296,9 +296,9 @@ class Settings extends ChangeNotifier {
static String notificationPolicyToString(NotificationPolicy np, BuildContext context) {
switch (np) {
case NotificationPolicy.None: return "None";
case NotificationPolicy.Mute: return "Mute";
case NotificationPolicy.OptIn: return "OptIn";
case NotificationPolicy.OptOut: return "OptOut";
case NotificationPolicy.DefaultAll: return "DefaultAll";
}
}

View File

@ -130,40 +130,26 @@ class _GroupSettingsViewState extends State<GroupSettingsView> {
SizedBox(
height: 20,
),
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;
ListTile(
title: Text(/*AppLocalizations.of(context)!.savePeerHistory*/ "Conversation Notification Policy", style: TextStyle(color: settings.current().mainTextColor)),
subtitle: Text(/*AppLocalizations.of(context)!.savePeerHistoryDescription*/ "The system blah blah..."),
leading: Icon(CwtchIcons.chat_bubble_empty_24px, color: settings.current().mainTextColor),
trailing: DropdownButton(
value: Provider.of<ContactInfoState>(context).notificationsPolicy,
items: ConversationNotificationPolicy.values.map<DropdownMenuItem<ConversationNotificationPolicy>>((ConversationNotificationPolicy value) {
return DropdownMenuItem<ConversationNotificationPolicy>(
value: value,
child: Text(value.toName),
);
}).toList(),
onChanged: (ConversationNotificationPolicy? newVal) {
Provider.of<ContactInfoState>(context, listen: false).notificationsPolicy = newVal!;
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());
const NotificationPolicyKey = "profile.notification-policy";
Provider.of<FlwtchState>(context, listen: false).cwtch.SetConversationAttribute(profileOnion, identifier, NotificationPolicyKey, newVal.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: [

View File

@ -201,40 +201,26 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
child: Text(value),
);
}).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;
ListTile(
title: Text(/*AppLocalizations.of(context)!.savePeerHistory*/ "Conversation Notification Policy", style: TextStyle(color: settings.current().mainTextColor)),
subtitle: Text(/*AppLocalizations.of(context)!.savePeerHistoryDescription*/ "The system blah blah..."),
leading: Icon(CwtchIcons.chat_bubble_empty_24px, color: settings.current().mainTextColor),
trailing: DropdownButton(
value: Provider.of<ContactInfoState>(context).notificationsPolicy,
items: ConversationNotificationPolicy.values.map<DropdownMenuItem<ConversationNotificationPolicy>>((ConversationNotificationPolicy value) {
return DropdownMenuItem<ConversationNotificationPolicy>(
value: value,
child: Text(value.toName),
);
}).toList(),
onChanged: (ConversationNotificationPolicy? newVal) {
Provider.of<ContactInfoState>(context, listen: false).notificationsPolicy = newVal!;
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());
const NotificationPolicyKey = "profile.notification-policy";
Provider.of<FlwtchState>(context, listen: false).cwtch.SetConversationAttribute(profileOnion, identifier, NotificationPolicyKey, newVal.toString());
},
activeTrackColor: settings.theme.defaultButtonColor,
inactiveTrackColor: settings.theme.defaultButtonDisabledColor,
))
)),
]),
Column(mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end, children: [
SizedBox(