forked from cwtch.im/cwtch-ui
Move Attribute Updates / File Downloading / Contact Requests / Invites to new API
This commit is contained in:
parent
b0f74ffb6d
commit
d6839c62e3
|
@ -73,8 +73,9 @@ abstract class Cwtch {
|
|||
// ignore: non_constant_identifier_names
|
||||
void SetProfileAttribute(String profile, String key, String val);
|
||||
// ignore: non_constant_identifier_names
|
||||
void SetConversationAttribute(String profile, int contact, String key, String val);
|
||||
|
||||
void SetConversationAttribute(String profile, int conversation, String key, String val);
|
||||
// ignore: non_constant_identifier_names
|
||||
void SetMessageAttribute(String profile, int conversation, int channel, int message, String key, String val);
|
||||
// ignore: non_constant_identifier_names
|
||||
void LoadServers(String password);
|
||||
// ignore: non_constant_identifier_names
|
||||
|
|
|
@ -79,7 +79,6 @@ class CwtchNotifier {
|
|||
}
|
||||
break;
|
||||
case "GroupCreated":
|
||||
|
||||
// Retrieve Server Status from Cache...
|
||||
String status = "";
|
||||
RemoteServerInfoState? serverInfoState = profileCN.getProfile(data["ProfileOnion"])?.serverList.getServer(data["GroupServer"]);
|
||||
|
@ -131,6 +130,10 @@ class CwtchNotifier {
|
|||
case "NewMessageFromPeer":
|
||||
notificationManager.notify("New Message From Peer!");
|
||||
var identifier = int.parse(data["ConversationID"]);
|
||||
|
||||
// We might not have received a contact created for this contact yet...
|
||||
// In that case the **next** event we receive will actually update these values...
|
||||
if (profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(identifier) != null) {
|
||||
if (appState.selectedProfile != data["ProfileOnion"] || appState.selectedConversation != identifier) {
|
||||
profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(identifier)!.unreadMessages++;
|
||||
} else {
|
||||
|
@ -145,6 +148,7 @@ class CwtchNotifier {
|
|||
if (profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(identifier)!.isOnline() == false) {
|
||||
profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(identifier)!.status = "Authenticated";
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case "PeerAcknowledgement":
|
||||
|
@ -206,17 +210,7 @@ class CwtchNotifier {
|
|||
notificationManager.notify("New Message From Group!");
|
||||
}
|
||||
} else {
|
||||
// from me (already displayed - do not update counter)
|
||||
var idx = data["Signature"];
|
||||
var key = profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(identifier)?.getMessageKey(idx);
|
||||
if (key == null) break;
|
||||
try {
|
||||
var message = Provider.of<MessageMetadata>(key.currentContext!, listen: false);
|
||||
if (message == null) break;
|
||||
message.ackd = true;
|
||||
} catch (e) {
|
||||
// ignore, we likely have an old key that has been replaced with an actual signature
|
||||
}
|
||||
// This is not dealt with by IndexedAcknowledgment
|
||||
}
|
||||
break;
|
||||
case "MessageCounterResync":
|
||||
|
@ -242,7 +236,7 @@ class CwtchNotifier {
|
|||
break;
|
||||
case "SendMessageToGroupError":
|
||||
// from me (already displayed - do not update counter)
|
||||
EnvironmentConfig.debugLog("SendMessageToGroupError");
|
||||
EnvironmentConfig.debugLog("SendMessageToGroupError: $data");
|
||||
var idx = data["Signature"];
|
||||
var key = profileCN.getProfile(data["ProfileOnion"])?.contactList.findContact(data["GroupID"])!.getMessageKey(idx);
|
||||
if (key == null) break;
|
||||
|
@ -289,7 +283,6 @@ class CwtchNotifier {
|
|||
profileCN.getProfile(data["ProfileOnion"])?.replaceServers(data["ServerList"]);
|
||||
break;
|
||||
case "NewGroup":
|
||||
EnvironmentConfig.debugLog("new group");
|
||||
String invite = data["GroupInvite"].toString();
|
||||
if (invite.startsWith("torv3")) {
|
||||
String inviteJson = new String.fromCharCodes(base64Decode(invite.substring(5)));
|
||||
|
@ -303,7 +296,8 @@ class CwtchNotifier {
|
|||
}
|
||||
|
||||
if (profileCN.getProfile(data["ProfileOnion"])?.contactList.findContact(groupInvite["GroupID"]) == null) {
|
||||
profileCN.getProfile(data["ProfileOnion"])?.contactList.add(ContactInfoState(data["ProfileOnion"], data["ConversationID"], groupInvite["GroupID"],
|
||||
var identifier = int.parse(data["ConversationID"]);
|
||||
profileCN.getProfile(data["ProfileOnion"])?.contactList.add(ContactInfoState(data["ProfileOnion"], identifier, groupInvite["GroupID"],
|
||||
authorization: ContactAuthorization.approved,
|
||||
imagePath: data["PicturePath"],
|
||||
nickname: groupInvite["GroupName"],
|
||||
|
@ -311,7 +305,7 @@ class CwtchNotifier {
|
|||
status: status,
|
||||
isGroup: true,
|
||||
lastMessageTime: DateTime.fromMillisecondsSinceEpoch(0)));
|
||||
profileCN.getProfile(data["ProfileOnion"])?.contactList.updateLastMessageTime(groupInvite["GroupID"], DateTime.fromMillisecondsSinceEpoch(0));
|
||||
profileCN.getProfile(data["ProfileOnion"])?.contactList.updateLastMessageTime(identifier, DateTime.fromMillisecondsSinceEpoch(0));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -323,7 +317,7 @@ class CwtchNotifier {
|
|||
break;
|
||||
case "ServerStateChange":
|
||||
// Update the Server Cache
|
||||
EnvironmentConfig.debugLog("server state changes $data");
|
||||
//EnvironmentConfig.debugLog("server state changes $data");
|
||||
profileCN.getProfile(data["ProfileOnion"])?.updateServerStatusCache(data["GroupServer"], data["ConnectionState"]);
|
||||
profileCN.getProfile(data["ProfileOnion"])?.contactList.contacts.forEach((contact) {
|
||||
if (contact.isGroup == true && contact.server == data["GroupServer"]) {
|
||||
|
@ -361,13 +355,17 @@ class CwtchNotifier {
|
|||
}
|
||||
break;
|
||||
case "NewRetValMessageFromPeer":
|
||||
if (data["Path"] == "name" && data["Data"].toString().trim().length > 0) {
|
||||
if (data["Path"] == "profile.name") {
|
||||
if (data["Data"].toString().trim().length > 0) {
|
||||
// Update locally on the UI...
|
||||
if (profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(data["RemotePeer"]) != null) {
|
||||
profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(data["RemotePeer"])!.nickname = data["Data"];
|
||||
if (profileCN.getProfile(data["ProfileOnion"])?.contactList.findContact(data["RemotePeer"]) != null) {
|
||||
profileCN.getProfile(data["ProfileOnion"])?.contactList.findContact(data["RemotePeer"])!.nickname = data["Data"];
|
||||
}
|
||||
}
|
||||
} else if (data['Path'] == "profile.picture") {
|
||||
// Not yet..
|
||||
} else {
|
||||
EnvironmentConfig.debugLog("unhandled peer attribute event: ${data['Path']}");
|
||||
EnvironmentConfig.debugLog("unhandled ret val event: ${data['Path']}");
|
||||
}
|
||||
break;
|
||||
case "ManifestSaved":
|
||||
|
|
|
@ -84,6 +84,9 @@ typedef VoidFromStringIntStringFn = void Function(Pointer<Utf8>, int, int, Point
|
|||
typedef void_from_string_int_string_string_function = Void Function(Pointer<Utf8>, Int32, Int32, Pointer<Utf8>, Int32, Pointer<Utf8>, Int32);
|
||||
typedef VoidFromStringIntStringStringFn = void Function(Pointer<Utf8>, int, int, Pointer<Utf8>, int, Pointer<Utf8>, int);
|
||||
|
||||
typedef void_from_string_int_int_int_string_string_function = Void Function(Pointer<Utf8>, Int32, Int32, Int32, Int32, Pointer<Utf8>, Int32, Pointer<Utf8>, Int32);
|
||||
typedef VoidFromStringIntIntIntStringStringFn = void Function(Pointer<Utf8>, int, int, int, int, Pointer<Utf8>, int, Pointer<Utf8>, int);
|
||||
|
||||
typedef void_from_string_int_int_function = Void Function(Pointer<Utf8>, Int32, Int32, Int32);
|
||||
typedef VoidFromStringIntIntFn = void Function(Pointer<Utf8>, int, int, int);
|
||||
|
||||
|
@ -549,6 +552,21 @@ class CwtchFfi implements Cwtch {
|
|||
malloc.free(u4);
|
||||
}
|
||||
|
||||
@override
|
||||
// ignore: non_constant_identifier_names
|
||||
void SetMessageAttribute(String profile, int conversation, int channel, int message, String key, String val) {
|
||||
var setMessageAttribute = library.lookup<NativeFunction<void_from_string_int_int_int_string_string_function>>("c_SetMessageAttribute");
|
||||
// ignore: non_constant_identifier_names
|
||||
final SetMessageAttribute = setMessageAttribute.asFunction<VoidFromStringIntIntIntStringStringFn>();
|
||||
final u1 = profile.toNativeUtf8();
|
||||
final u3 = key.toNativeUtf8();
|
||||
final u4 = val.toNativeUtf8();
|
||||
SetMessageAttribute(u1, u1.length, conversation, channel, message, u3, u3.length, u4, u4.length);
|
||||
malloc.free(u1);
|
||||
malloc.free(u3);
|
||||
malloc.free(u4);
|
||||
}
|
||||
|
||||
@override
|
||||
// ignore: non_constant_identifier_names
|
||||
void LoadServers(String password) {
|
||||
|
|
|
@ -281,4 +281,9 @@ class CwtchGomobile implements Cwtch {
|
|||
Future GetMessageByContentHash(String profile, int handle, String contentHash) {
|
||||
return cwtchPlatform.invokeMethod("GetMessageByContentHash", {"profile": profile, "contact": handle, "contentHash": contentHash});
|
||||
}
|
||||
|
||||
@override
|
||||
void SetMessageAttribute(String profile, int conversation, int channel, int message, String key, String val) {
|
||||
cwtchPlatform.invokeMethod("SetMessageAttribute", {"ProfileOnion": profile, "Conversation": conversation, "Channel": channel, "Message": message, "Key": key, "Val": val});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ Future<Message> messageHandler(BuildContext context, String profileOnion, int co
|
|||
}
|
||||
|
||||
return rawMessageEnvelopeFuture.then((dynamic rawMessageEnvelope) {
|
||||
var metadata = MessageMetadata(profileOnion, conversationIdentifier, index, -1, DateTime.now(), "", "", null, 0, false, true);
|
||||
var metadata = MessageMetadata(profileOnion, conversationIdentifier, index, -1, DateTime.now(), "", "", "", <String, String>{}, false, true);
|
||||
try {
|
||||
dynamic messageWrapper = jsonDecode(rawMessageEnvelope);
|
||||
// There are 2 conditions in which this error condition can be met:
|
||||
|
@ -67,11 +67,11 @@ Future<Message> messageHandler(BuildContext context, String profileOnion, int co
|
|||
var timestamp = DateTime.tryParse(messageWrapper['Timestamp'])!;
|
||||
var senderHandle = messageWrapper['PeerID'];
|
||||
var senderImage = messageWrapper['ContactImage'];
|
||||
var flags = int.parse(messageWrapper['Flags'].toString());
|
||||
var attributes = messageWrapper['Attributes'];
|
||||
var ackd = messageWrapper['Acknowledged'];
|
||||
var error = messageWrapper['Error'] != null;
|
||||
var signature = messageWrapper['Signature'];
|
||||
metadata = MessageMetadata(profileOnion, conversationIdentifier, index, messageID, timestamp, senderHandle, senderImage, signature, flags, ackd, error);
|
||||
metadata = MessageMetadata(profileOnion, conversationIdentifier, index, messageID, timestamp, senderHandle, senderImage, signature, attributes, ackd, error);
|
||||
|
||||
dynamic message = jsonDecode(messageWrapper['Message']);
|
||||
var content = message['d'] as dynamic;
|
||||
|
@ -97,7 +97,7 @@ Future<Message> messageHandler(BuildContext context, String profileOnion, int co
|
|||
}
|
||||
});
|
||||
} catch (e) {
|
||||
return Future.value(MalformedMessage(MessageMetadata(profileOnion, conversationIdentifier, index, -1, DateTime.now(), "", "", null, 0, false, true)));
|
||||
return Future.value(MalformedMessage(MessageMetadata(profileOnion, conversationIdentifier, index, -1, DateTime.now(), "", "", "", <String, String>{}, false, true)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,17 +111,13 @@ class MessageMetadata extends ChangeNotifier {
|
|||
final DateTime timestamp;
|
||||
final String senderHandle;
|
||||
final String? senderImage;
|
||||
int _flags;
|
||||
final dynamic _attributes;
|
||||
bool _ackd;
|
||||
bool _error;
|
||||
|
||||
final String? signature;
|
||||
|
||||
int get flags => this._flags;
|
||||
set flags(int newVal) {
|
||||
this._flags = newVal;
|
||||
notifyListeners();
|
||||
}
|
||||
dynamic get attributes => this._attributes;
|
||||
|
||||
bool get ackd => this._ackd;
|
||||
set ackd(bool newVal) {
|
||||
|
@ -135,6 +131,6 @@ class MessageMetadata extends ChangeNotifier {
|
|||
notifyListeners();
|
||||
}
|
||||
|
||||
MessageMetadata(
|
||||
this.profileOnion, this.conversationIdentifier, this.messageIndex, this.messageID, this.timestamp, this.senderHandle, this.senderImage, this.signature, this._flags, this._ackd, this._error);
|
||||
MessageMetadata(this.profileOnion, this.conversationIdentifier, this.messageIndex, this.messageID, this.timestamp, this.senderHandle, this.senderImage, this.signature, this._attributes, this._ackd,
|
||||
this._error);
|
||||
}
|
||||
|
|
|
@ -195,10 +195,11 @@ class _GroupSettingsViewState extends State<GroupSettingsView> {
|
|||
child: Text(AppLocalizations.of(context)!.yesLeave),
|
||||
onPressed: () {
|
||||
var profileOnion = Provider.of<ContactInfoState>(context, listen: false).profileOnion;
|
||||
var handle = Provider.of<ContactInfoState>(context, listen: false).identifier;
|
||||
var identifier = Provider.of<ContactInfoState>(context, listen: false).identifier;
|
||||
// locally update cache...
|
||||
Provider.of<ContactInfoState>(context, listen: false).isArchived = true;
|
||||
Provider.of<FlwtchState>(context, listen: false).cwtch.DeleteContact(profileOnion, handle);
|
||||
Provider.of<ProfileInfoState>(context, listen: false).contactList.removeContact(identifier);
|
||||
Provider.of<FlwtchState>(context, listen: false).cwtch.DeleteContact(profileOnion, identifier);
|
||||
Future.delayed(Duration(milliseconds: 500), () {
|
||||
Provider.of<AppState>(context, listen: false).selectedConversation = null;
|
||||
Navigator.of(context).popUntil((route) => route.settings.name == "conversations"); // dismiss dialog
|
||||
|
|
|
@ -353,7 +353,7 @@ class _MessageViewState extends State<MessageView> {
|
|||
return contact.onion != Provider.of<ContactInfoState>(context).onion;
|
||||
}, onChanged: (newVal) {
|
||||
setState(() {
|
||||
this.selectedContact = newVal;
|
||||
this.selectedContact = Provider.of<ProfileInfoState>(context).contactList.findContact(newVal)!.identifier;
|
||||
});
|
||||
})),
|
||||
SizedBox(
|
||||
|
@ -362,7 +362,7 @@ class _MessageViewState extends State<MessageView> {
|
|||
ElevatedButton(
|
||||
child: Text(AppLocalizations.of(bcontext)!.inviteBtn, semanticsLabel: AppLocalizations.of(bcontext)!.inviteBtn),
|
||||
onPressed: () {
|
||||
if (this.selectedContact != "") {
|
||||
if (this.selectedContact != -1) {
|
||||
this._sendInvitation();
|
||||
}
|
||||
Navigator.pop(bcontext);
|
||||
|
|
|
@ -111,6 +111,8 @@ class _ContactRowState extends State<ContactRow> {
|
|||
}
|
||||
|
||||
void _btnApprove() {
|
||||
// Update the UI
|
||||
Provider.of<ContactInfoState>(context, listen: false).authorization = ContactAuthorization.approved;
|
||||
Provider.of<FlwtchState>(context, listen: false)
|
||||
.cwtch
|
||||
.AcceptContact(Provider.of<ContactInfoState>(context, listen: false).profileOnion, Provider.of<ContactInfoState>(context, listen: false).identifier);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:cwtch/config.dart';
|
||||
import 'package:cwtch/models/message.dart';
|
||||
import 'package:file_picker_desktop/file_picker_desktop.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
@ -41,7 +42,7 @@ class FileBubbleState extends State<FileBubble> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var fromMe = Provider.of<MessageMetadata>(context).senderHandle == Provider.of<ProfileInfoState>(context).onion;
|
||||
var flagStarted = Provider.of<MessageMetadata>(context).flags & 0x02 > 0;
|
||||
var flagStarted = Provider.of<MessageMetadata>(context).attributes["file-downloaded"] == "true";
|
||||
var borderRadiousEh = 15.0;
|
||||
var showFileSharing = Provider.of<Settings>(context).isExperimentEnabled(FileSharingExperiment);
|
||||
var prettyDate = DateFormat.yMd(Platform.localeName).add_jm().format(Provider.of<MessageMetadata>(context).timestamp);
|
||||
|
@ -146,14 +147,13 @@ class FileBubbleState extends State<FileBubble> {
|
|||
String? selectedFileName;
|
||||
File? file;
|
||||
var profileOnion = Provider.of<ProfileInfoState>(context, listen: false).onion;
|
||||
var handle = Provider.of<MessageMetadata>(context, listen: false).senderHandle;
|
||||
var contact = Provider.of<ContactInfoState>(context, listen: false).onion;
|
||||
var idx = Provider.of<MessageMetadata>(context, listen: false).messageIndex;
|
||||
var conversation = Provider.of<ContactInfoState>(context, listen: false).identifier;
|
||||
var idx = Provider.of<MessageMetadata>(context, listen: false).messageID;
|
||||
|
||||
if (Platform.isAndroid) {
|
||||
Provider.of<ProfileInfoState>(context, listen: false).downloadInit(widget.fileKey(), (widget.fileSize / 4096).ceil());
|
||||
//Provider.of<FlwtchState>(context, listen: false).cwtch.UpdateMessageFlags(profileOnion, contact, idx, Provider.of<MessageMetadata>(context, listen: false).flags | 0x02);
|
||||
Provider.of<MessageMetadata>(context, listen: false).flags |= 0x02;
|
||||
Provider.of<FlwtchState>(context, listen: false).cwtch.SetMessageAttribute(profileOnion, conversation, 0, idx, "file-downloaded", "true");
|
||||
//Provider.of<MessageMetadata>(context, listen: false).attributes |= 0x02;
|
||||
ContactInfoState? contact = Provider.of<ProfileInfoState>(context).contactList.findContact(Provider.of<MessageMetadata>(context).senderHandle);
|
||||
if (contact != null) {
|
||||
Provider.of<FlwtchState>(context, listen: false).cwtch.CreateDownloadableFile(profileOnion, contact.identifier, widget.nameSuggestion, widget.fileKey());
|
||||
|
@ -165,11 +165,11 @@ class FileBubbleState extends State<FileBubble> {
|
|||
);
|
||||
if (selectedFileName != null) {
|
||||
file = File(selectedFileName);
|
||||
print("saving to " + file.path);
|
||||
EnvironmentConfig.debugLog("saving to " + file.path);
|
||||
var manifestPath = file.path + ".manifest";
|
||||
Provider.of<ProfileInfoState>(context, listen: false).downloadInit(widget.fileKey(), (widget.fileSize / 4096).ceil());
|
||||
//Provider.of<FlwtchState>(context, listen: false).cwtch.UpdateMessageFlags(profileOnion, contact, idx, Provider.of<MessageMetadata>(context, listen: false).flags | 0x02);
|
||||
Provider.of<MessageMetadata>(context, listen: false).flags |= 0x02;
|
||||
Provider.of<FlwtchState>(context, listen: false).cwtch.SetMessageAttribute(profileOnion, conversation, 0, idx, "file-downloaded", "true");
|
||||
//Provider.of<MessageMetadata>(context, listen: false).flags |= 0x02;
|
||||
ContactInfoState? contact = Provider.of<ProfileInfoState>(context).contactList.findContact(Provider.of<MessageMetadata>(context).senderHandle);
|
||||
if (contact != null) {
|
||||
Provider.of<FlwtchState>(context, listen: false).cwtch.DownloadFile(profileOnion, contact.identifier, file.path, manifestPath, widget.fileKey());
|
||||
|
|
|
@ -39,7 +39,7 @@ class InvitationBubbleState extends State<InvitationBubble> {
|
|||
isAccepted = Provider.of<ProfileInfoState>(context).contactList.findContact(widget.inviteTarget) != null;
|
||||
var borderRadiousEh = 15.0;
|
||||
var showGroupInvite = Provider.of<Settings>(context).isExperimentEnabled(TapirGroupsExperiment);
|
||||
rejected = Provider.of<MessageMetadata>(context).flags & 0x01 == 0x01;
|
||||
rejected = Provider.of<MessageMetadata>(context).attributes["rejected-invite"] == "true";
|
||||
var prettyDate = DateFormat.yMd(Platform.localeName).add_jm().format(Provider.of<MessageMetadata>(context).timestamp);
|
||||
|
||||
// If the sender is not us, then we want to give them a nickname...
|
||||
|
@ -128,10 +128,10 @@ class InvitationBubbleState extends State<InvitationBubble> {
|
|||
void _btnReject() {
|
||||
setState(() {
|
||||
var profileOnion = Provider.of<ProfileInfoState>(context, listen: false).onion;
|
||||
var contact = Provider.of<ContactInfoState>(context, listen: false).onion;
|
||||
var idx = Provider.of<MessageMetadata>(context, listen: false).messageIndex;
|
||||
//Provider.of<FlwtchState>(context, listen: false).cwtch.UpdateMessageFlags(profileOnion, contact, idx, Provider.of<MessageMetadata>(context, listen: false).flags | 0x01);
|
||||
Provider.of<MessageMetadata>(context, listen: false).flags |= 0x01;
|
||||
var conversation = Provider.of<ContactInfoState>(context, listen: false).identifier;
|
||||
var idx = Provider.of<MessageMetadata>(context, listen: false).messageID;
|
||||
Provider.of<FlwtchState>(context, listen: false).cwtch.SetMessageAttribute(profileOnion, conversation, 0, idx, "rejected-invite", "true");
|
||||
//Provider.of<MessageMetadata>(context, listen: false).flags |= 0x01;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue