2022-01-18 21:26:52 +00:00
|
|
|
import 'package:cwtch/widgets/messagerow.dart';
|
|
|
|
import 'package:flutter/widgets.dart';
|
2022-02-08 21:54:17 +00:00
|
|
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
2022-06-10 19:10:17 +00:00
|
|
|
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
2022-02-08 21:54:17 +00:00
|
|
|
|
2022-01-18 21:26:52 +00:00
|
|
|
import 'message.dart';
|
|
|
|
import 'messagecache.dart';
|
|
|
|
|
2022-02-08 02:13:49 +00:00
|
|
|
enum ConversationNotificationPolicy {
|
|
|
|
Default,
|
|
|
|
OptIn,
|
|
|
|
Never,
|
|
|
|
}
|
|
|
|
|
|
|
|
extension Nameable on ConversationNotificationPolicy {
|
2022-02-08 21:54:17 +00:00
|
|
|
String toName(BuildContext context) {
|
2022-02-08 02:13:49 +00:00
|
|
|
switch (this) {
|
|
|
|
case ConversationNotificationPolicy.Default:
|
2022-02-08 21:54:17 +00:00
|
|
|
return AppLocalizations.of(context)!.conversationNotificationPolicyDefault;
|
2022-02-08 02:13:49 +00:00
|
|
|
case ConversationNotificationPolicy.OptIn:
|
2022-02-08 21:54:17 +00:00
|
|
|
return AppLocalizations.of(context)!.conversationNotificationPolicyOptIn;
|
2022-02-08 02:13:49 +00:00
|
|
|
case ConversationNotificationPolicy.Never:
|
2022-02-08 21:54:17 +00:00
|
|
|
return AppLocalizations.of(context)!.conversationNotificationPolicyNever;
|
2022-02-08 02:13:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-18 21:26:52 +00:00
|
|
|
class ContactInfoState extends ChangeNotifier {
|
|
|
|
final String profileOnion;
|
|
|
|
final int identifier;
|
|
|
|
final String onion;
|
|
|
|
late String _nickname;
|
|
|
|
|
2022-02-08 02:13:49 +00:00
|
|
|
late ConversationNotificationPolicy _notificationPolicy;
|
2022-02-04 22:19:02 +00:00
|
|
|
|
2022-01-18 21:26:52 +00:00
|
|
|
late bool _accepted;
|
|
|
|
late bool _blocked;
|
|
|
|
late String _status;
|
|
|
|
late String _imagePath;
|
2022-02-07 22:26:14 +00:00
|
|
|
late String _defaultImagePath;
|
2022-01-18 21:26:52 +00:00
|
|
|
late String _savePeerHistory;
|
|
|
|
late int _unreadMessages = 0;
|
|
|
|
late int _totalMessages = 0;
|
|
|
|
late DateTime _lastMessageTime;
|
|
|
|
late Map<String, GlobalKey<MessageRowState>> keys;
|
2022-04-29 23:00:52 +00:00
|
|
|
int _newMarkerMsgIndex = -1;
|
2022-01-20 14:13:54 +00:00
|
|
|
late MessageCache messageCache;
|
2022-06-10 19:10:17 +00:00
|
|
|
ItemScrollController messageScrollController = new ItemScrollController();
|
2022-01-18 21:26:52 +00:00
|
|
|
|
|
|
|
// todo: a nicer way to model contacts, groups and other "entities"
|
|
|
|
late bool _isGroup;
|
|
|
|
String? _server;
|
|
|
|
late bool _archived;
|
|
|
|
|
|
|
|
String? _acnCircuit;
|
|
|
|
|
|
|
|
ContactInfoState(this.profileOnion, this.identifier, this.onion,
|
|
|
|
{nickname = "",
|
2022-01-19 21:58:52 +00:00
|
|
|
isGroup = false,
|
|
|
|
accepted = false,
|
|
|
|
blocked = false,
|
|
|
|
status = "",
|
|
|
|
imagePath = "",
|
2022-02-07 22:26:14 +00:00
|
|
|
defaultImagePath = "",
|
2022-01-19 21:58:52 +00:00
|
|
|
savePeerHistory = "DeleteHistoryConfirmed",
|
|
|
|
numMessages = 0,
|
|
|
|
numUnread = 0,
|
|
|
|
lastMessageTime,
|
|
|
|
server,
|
2022-02-04 22:19:02 +00:00
|
|
|
archived = false,
|
2022-02-08 02:13:49 +00:00
|
|
|
notificationPolicy = "ConversationNotificationPolicy.Default"}) {
|
2022-01-18 21:26:52 +00:00
|
|
|
this._nickname = nickname;
|
|
|
|
this._isGroup = isGroup;
|
|
|
|
this._accepted = accepted;
|
|
|
|
this._blocked = blocked;
|
|
|
|
this._status = status;
|
|
|
|
this._imagePath = imagePath;
|
2022-02-07 22:26:14 +00:00
|
|
|
this._defaultImagePath = defaultImagePath;
|
2022-01-18 21:26:52 +00:00
|
|
|
this._totalMessages = numMessages;
|
|
|
|
this._unreadMessages = numUnread;
|
|
|
|
this._savePeerHistory = savePeerHistory;
|
|
|
|
this._lastMessageTime = lastMessageTime == null ? DateTime.fromMillisecondsSinceEpoch(0) : lastMessageTime;
|
|
|
|
this._server = server;
|
|
|
|
this._archived = archived;
|
2022-02-08 02:13:49 +00:00
|
|
|
this._notificationPolicy = notificationPolicyFromString(notificationPolicy);
|
2022-03-23 23:08:19 +00:00
|
|
|
this.messageCache = new MessageCache(_totalMessages);
|
2022-01-18 21:26:52 +00:00
|
|
|
keys = Map<String, GlobalKey<MessageRowState>>();
|
|
|
|
}
|
|
|
|
|
|
|
|
String get nickname => this._nickname;
|
|
|
|
|
|
|
|
String get savePeerHistory => this._savePeerHistory;
|
|
|
|
|
|
|
|
String? get acnCircuit => this._acnCircuit;
|
2022-01-20 18:05:11 +00:00
|
|
|
|
2022-01-18 21:26:52 +00:00
|
|
|
set acnCircuit(String? acnCircuit) {
|
|
|
|
this._acnCircuit = acnCircuit;
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Indicated whether the conversation is archived, in which case it will
|
|
|
|
// be moved to the very bottom of the active conversations list until
|
|
|
|
// new messages appear
|
|
|
|
set isArchived(bool archived) {
|
|
|
|
this._archived = archived;
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool get isArchived => this._archived;
|
|
|
|
|
|
|
|
set savePeerHistory(String newVal) {
|
|
|
|
this._savePeerHistory = newVal;
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
|
|
|
|
set nickname(String newVal) {
|
|
|
|
this._nickname = newVal;
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool get isGroup => this._isGroup;
|
2022-01-20 18:05:11 +00:00
|
|
|
|
2022-01-18 21:26:52 +00:00
|
|
|
set isGroup(bool newVal) {
|
|
|
|
this._isGroup = newVal;
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool get isBlocked => this._blocked;
|
|
|
|
|
|
|
|
bool get isInvitation => !this._blocked && !this._accepted;
|
|
|
|
|
|
|
|
set accepted(bool newVal) {
|
|
|
|
this._accepted = newVal;
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
|
|
|
|
set blocked(bool newVal) {
|
|
|
|
this._blocked = newVal;
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
|
|
|
|
String get status => this._status;
|
2022-01-20 18:05:11 +00:00
|
|
|
|
2022-01-18 21:26:52 +00:00
|
|
|
set status(String newVal) {
|
|
|
|
this._status = newVal;
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
|
2022-04-28 15:57:31 +00:00
|
|
|
void selected() {
|
2022-05-11 19:43:54 +00:00
|
|
|
this._newMarkerMsgIndex = this._unreadMessages - 1;
|
2022-04-28 15:57:31 +00:00
|
|
|
this._unreadMessages = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void unselected() {
|
2022-04-29 23:00:52 +00:00
|
|
|
this._newMarkerMsgIndex = -1;
|
2022-04-28 15:57:31 +00:00
|
|
|
}
|
|
|
|
|
2022-01-18 21:26:52 +00:00
|
|
|
int get unreadMessages => this._unreadMessages;
|
2022-01-20 18:05:11 +00:00
|
|
|
|
2022-01-18 21:26:52 +00:00
|
|
|
set unreadMessages(int newVal) {
|
|
|
|
this._unreadMessages = newVal;
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
|
2022-04-29 23:00:52 +00:00
|
|
|
int get newMarkerMsgIndex {
|
|
|
|
return this._newMarkerMsgIndex;
|
2022-01-18 21:26:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int get totalMessages => this._totalMessages;
|
2022-01-20 18:05:11 +00:00
|
|
|
|
2022-01-18 21:26:52 +00:00
|
|
|
set totalMessages(int newVal) {
|
|
|
|
this._totalMessages = newVal;
|
2022-03-23 23:08:19 +00:00
|
|
|
this.messageCache.storageMessageCount = newVal;
|
2022-01-18 21:26:52 +00:00
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
|
2022-02-08 21:59:24 +00:00
|
|
|
String get imagePath {
|
|
|
|
// don't show custom images for blocked contacts..
|
|
|
|
if (!this.isBlocked) {
|
|
|
|
return this._imagePath;
|
|
|
|
}
|
|
|
|
return this.defaultImagePath;
|
|
|
|
}
|
2022-01-20 18:05:11 +00:00
|
|
|
|
2022-01-18 21:26:52 +00:00
|
|
|
set imagePath(String newVal) {
|
|
|
|
this._imagePath = newVal;
|
2022-02-07 22:26:14 +00:00
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
|
|
|
|
String get defaultImagePath => this._defaultImagePath;
|
|
|
|
|
|
|
|
set defaultImagePath(String newVal) {
|
|
|
|
this._defaultImagePath = newVal;
|
2022-01-18 21:26:52 +00:00
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
|
|
|
|
DateTime get lastMessageTime => this._lastMessageTime;
|
2022-01-20 18:05:11 +00:00
|
|
|
|
2022-01-18 21:26:52 +00:00
|
|
|
set lastMessageTime(DateTime newVal) {
|
|
|
|
this._lastMessageTime = newVal;
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
|
|
|
|
// we only allow callers to fetch the server
|
2022-02-05 00:37:25 +00:00
|
|
|
String? get server => this._server;
|
2022-01-18 21:26:52 +00:00
|
|
|
|
|
|
|
bool isOnline() {
|
|
|
|
if (this.isGroup == true) {
|
|
|
|
// We now have an out of sync warning so we will mark these as online...
|
|
|
|
return this.status == "Authenticated" || this.status == "Synced";
|
|
|
|
} else {
|
|
|
|
return this.status == "Authenticated";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-08 02:13:49 +00:00
|
|
|
ConversationNotificationPolicy get notificationsPolicy => _notificationPolicy;
|
2022-02-04 22:19:02 +00:00
|
|
|
|
2022-02-08 02:13:49 +00:00
|
|
|
set notificationsPolicy(ConversationNotificationPolicy newVal) {
|
|
|
|
_notificationPolicy = newVal;
|
2022-02-04 22:19:02 +00:00
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
|
2022-01-18 21:26:52 +00:00
|
|
|
GlobalKey<MessageRowState> getMessageKey(int conversation, int message) {
|
|
|
|
String index = "c: " + conversation.toString() + " m:" + message.toString();
|
|
|
|
if (keys[index] == null) {
|
|
|
|
keys[index] = GlobalKey<MessageRowState>();
|
|
|
|
}
|
|
|
|
GlobalKey<MessageRowState> ret = keys[index]!;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
GlobalKey<MessageRowState>? getMessageKeyOrFail(int conversation, int message) {
|
|
|
|
String index = "c: " + conversation.toString() + " m:" + message.toString();
|
|
|
|
|
|
|
|
if (keys[index] == null) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
GlobalKey<MessageRowState> ret = keys[index]!;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2022-03-23 23:08:19 +00:00
|
|
|
void newMessage(int identifier, int messageID, DateTime timestamp, String senderHandle, String senderImage, bool isAuto, String data, String contenthash, bool selectedConversation) {
|
2022-01-20 14:13:54 +00:00
|
|
|
if (!selectedConversation) {
|
|
|
|
unreadMessages++;
|
2022-03-24 00:56:59 +00:00
|
|
|
}
|
2022-04-29 23:00:52 +00:00
|
|
|
if (_newMarkerMsgIndex == -1) {
|
2022-04-30 21:43:45 +00:00
|
|
|
if (!selectedConversation) {
|
|
|
|
_newMarkerMsgIndex = 0;
|
|
|
|
}
|
2022-04-29 23:00:52 +00:00
|
|
|
} else {
|
|
|
|
_newMarkerMsgIndex++;
|
2022-01-20 14:13:54 +00:00
|
|
|
}
|
|
|
|
|
2022-01-27 01:03:48 +00:00
|
|
|
this._lastMessageTime = timestamp;
|
2022-01-20 14:13:54 +00:00
|
|
|
this.messageCache.addNew(profileOnion, identifier, messageID, timestamp, senderHandle, senderImage, isAuto, data, contenthash);
|
2022-01-18 21:26:52 +00:00
|
|
|
this.totalMessages += 1;
|
2022-01-20 14:13:54 +00:00
|
|
|
|
|
|
|
// We only ever see messages from authenticated peers.
|
|
|
|
// If the contact is marked as offline then override this - can happen when the contact is removed from the front
|
|
|
|
// end during syncing.
|
|
|
|
if (isOnline() == false) {
|
|
|
|
status = "Authenticated";
|
|
|
|
}
|
2022-01-20 18:37:09 +00:00
|
|
|
notifyListeners();
|
2022-01-18 21:26:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ackCache(int messageID) {
|
2022-01-20 14:13:54 +00:00
|
|
|
this.messageCache.ackCache(messageID);
|
2022-01-18 21:26:52 +00:00
|
|
|
notifyListeners();
|
|
|
|
}
|
2022-02-08 02:13:49 +00:00
|
|
|
|
2022-03-04 19:30:19 +00:00
|
|
|
void errCache(int messageID) {
|
|
|
|
this.messageCache.errCache(messageID);
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
|
2022-02-08 02:13:49 +00:00
|
|
|
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;
|
|
|
|
}
|
2022-01-20 18:05:11 +00:00
|
|
|
}
|