diff --git a/android/app/src/main/kotlin/com/example/flutter_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/flutter_app/MainActivity.kt index 5c292d3..92d9a16 100644 --- a/android/app/src/main/kotlin/com/example/flutter_app/MainActivity.kt +++ b/android/app/src/main/kotlin/com/example/flutter_app/MainActivity.kt @@ -172,6 +172,11 @@ class MainActivity: FlutterActivity() { val value = (call.argument("value") as? String) ?: ""; Cwtch.setGroupAttribute(profile, groupHandle, key, value); } + "RejectInvite" -> { + val profile = (call.argument("ProfileOnion") as? String) ?: ""; + val groupHandle = (call.argument("groupHandle") as? String) ?: ""; + Cwtch.rejectInvite(profile, groupHandle); + } else -> result.notImplemented() } } diff --git a/android/cwtch/cwtch.aar b/android/cwtch/cwtch.aar index e5b4dfc..aff7045 100644 Binary files a/android/cwtch/cwtch.aar and b/android/cwtch/cwtch.aar differ diff --git a/lib/cwtch/cwtch.dart b/lib/cwtch/cwtch.dart index f103179..568e9a7 100644 --- a/lib/cwtch/cwtch.dart +++ b/lib/cwtch/cwtch.dart @@ -46,6 +46,8 @@ abstract class Cwtch { void ImportBundle(String profile, String bundle); // ignore: non_constant_identifier_names void SetGroupAttribute(String profile, String groupHandle, String key, String value); + // ignore: non_constant_identifier_names + void RejectInvite(String profileOnion, String groupHandle); void dispose(); } diff --git a/lib/cwtch/cwtchNotifier.dart b/lib/cwtch/cwtchNotifier.dart index dcb230c..c5be273 100644 --- a/lib/cwtch/cwtchNotifier.dart +++ b/lib/cwtch/cwtchNotifier.dart @@ -65,8 +65,7 @@ class CwtchNotifier { case "NewMessageFromGroup": profileCN.getProfile(data["ProfileOnion"]).contactList.getContact(data["GroupID"]).unreadMessages++; profileCN.getProfile(data["ProfileOnion"]).contactList.getContact(data["GroupID"]).totalMessages++; - // TODO exception is called in the case of groups. - profileCN.getProfile(data["ProfileOnion"]).contactList.updateLastMessageTime(data["RemotePeer"], DateTime.now()); + profileCN.getProfile(data["ProfileOnion"]).contactList.updateLastMessageTime(data["GroupID"], DateTime.now()); break; case "AppError": print("New App Error: $data"); @@ -95,16 +94,15 @@ class CwtchNotifier { break; case "NewGroupInvite": print("new group invite: $data"); - // TODO Add Group Dynamically dynamic groupInvite = jsonDecode(data["GroupInvite"]); - profileCN.getProfile(data["ProfileOnion"]).contactList.add(ContactInfoState( - "", - groupInvite["GroupID"], - isInvitation: true, - imagePath: data["PicturePath"], - nickname: groupInvite["GroupName"], - server: groupInvite["ServerHost"], - isGroup: true)); + profileCN.getProfile(data["ProfileOnion"]).contactList.add(ContactInfoState(data["ProfileOnion"], groupInvite["GroupID"], + isInvitation: true, imagePath: data["PicturePath"], nickname: groupInvite["GroupName"], server: groupInvite["ServerHost"], isGroup: true, lastMessageTime: DateTime.now())); + profileCN.getProfile(data["ProfileOnion"]).contactList.updateLastMessageTime(groupInvite["GroupID"], DateTime.now()); + break; + case "AcceptGroupInvite": + print("accept group invite: $data"); + profileCN.getProfile(data["ProfileOnion"]).contactList.getContact(data["GroupID"]).isInvitation = false; + profileCN.getProfile(data["ProfileOnion"]).contactList.updateLastMessageTime(data["GroupID"], DateTime.now()); break; case "ServerStateChange": print("server state change: $data"); diff --git a/lib/cwtch/ffi.dart b/lib/cwtch/ffi.dart index bc5ea28..2f747d2 100644 --- a/lib/cwtch/ffi.dart +++ b/lib/cwtch/ffi.dart @@ -332,4 +332,15 @@ class CwtchFfi implements Cwtch { final u4 = value.toNativeUtf8(); SetGroupAttribute(u1, u1.length, u2, u2.length, u3, u3.length, u4, u4.length); } + + @override + // ignore: non_constant_identifier_names + void RejectInvite(String profileOnion, String groupHandle) { + var rejectInvite = library.lookup>("c_RejectInvite"); + // ignore: non_constant_identifier_names + final RejectInvite = rejectInvite.asFunction(); + final u1 = profileOnion.toNativeUtf8(); + final u2 = groupHandle.toNativeUtf8(); + RejectInvite(u1, u1.length, u2, u2.length); + } } diff --git a/lib/cwtch/gomobile.dart b/lib/cwtch/gomobile.dart index 95690a4..ae329c3 100644 --- a/lib/cwtch/gomobile.dart +++ b/lib/cwtch/gomobile.dart @@ -159,4 +159,10 @@ class CwtchGomobile implements Cwtch { void SetGroupAttribute(String profileOnion, String groupHandle, String key, String value) { cwtchPlatform.invokeMethod("SetGroupAttribute", {"ProfileOnion": profileOnion, "groupHandle": groupHandle, "key": key, "value": value}); } + + @override + // ignore: non_constant_identifier_names + void RejectInvite(String profileOnion, String groupHandle) { + cwtchPlatform.invokeMethod("RejectInvite", {"ProfileOnion": profileOnion, "handle": groupHandle}); + } } diff --git a/lib/model.dart b/lib/model.dart index a64d830..b9c1111 100644 --- a/lib/model.dart +++ b/lib/model.dart @@ -141,9 +141,7 @@ class ProfileInfoState extends ChangeNotifier { if (contactsJson != null && contactsJson != "" && contactsJson != "null") { List contacts = jsonDecode(contactsJson); this._contacts.addAll(contacts.map((contact) { - return ContactInfoState( - this.onion, - contact["onion"], + return ContactInfoState(this.onion, contact["onion"], nickname: contact["name"], status: contact["status"], imagePath: contact["picture"], @@ -203,6 +201,14 @@ class ProfileInfoState extends ChangeNotifier { notifyListeners(); } + // Remove a contact from a list. Currently only used when rejecting a group invitation. + // Eventually will also be used for other removals. + void removeContact(String handle) { + int idx = this.contactList._contacts.indexWhere((element) => element.onion == handle); + this.contactList._contacts.removeAt(idx); + notifyListeners(); + } + ContactListState get contactList => this._contacts; ServerListState get serverList => this._servers; @@ -233,7 +239,7 @@ class ContactInfoState extends ChangeNotifier { ContactInfoState( this.profileOnion, - this.onion,{ + this.onion, { nickname = "", isGroup = false, isInvitation = false, diff --git a/lib/views/messageview.dart b/lib/views/messageview.dart index c357d0e..72c6031 100644 --- a/lib/views/messageview.dart +++ b/lib/views/messageview.dart @@ -105,20 +105,18 @@ class _MessageViewState extends State { onSubmitted: _sendMessage, )), SizedBox( - width: 100, - height: 90, - child: Padding( - padding: EdgeInsets.fromLTRB(2, 2, 2, 2), - child: ElevatedButton( - child: Icon(Icons.send, color: Provider.of(context).theme.mainTextColor()), - style: ButtonStyle( - fixedSize: MaterialStateProperty.all(Size(86, 40)), - backgroundColor: MaterialStateProperty.all(Provider.of(context).theme.defaultButtonColor()), - ), - onPressed: _sendMessage, - ) - ) - ), + width: 100, + height: 90, + child: Padding( + padding: EdgeInsets.fromLTRB(2, 2, 2, 2), + child: ElevatedButton( + child: Icon(Icons.send, color: Provider.of(context).theme.mainTextColor()), + style: ButtonStyle( + fixedSize: MaterialStateProperty.all(Size(86, 40)), + backgroundColor: MaterialStateProperty.all(Provider.of(context).theme.defaultButtonColor()), + ), + onPressed: _sendMessage, + ))), ], ), ); diff --git a/lib/widgets/contactrow.dart b/lib/widgets/contactrow.dart index c50c0d6..20560ff 100644 --- a/lib/widgets/contactrow.dart +++ b/lib/widgets/contactrow.dart @@ -109,9 +109,13 @@ class _ContactRowState extends State { } void _btnReject() { - Provider.of(context, listen: false) - .cwtch - .BlockContact(Provider.of(context, listen: false).profileOnion, Provider.of(context, listen: false).onion); + ContactInfoState contact = Provider.of(context, listen: false); + if (contact.isGroup == true) { + Provider.of(context, listen: false).cwtch.RejectInvite(Provider.of(context, listen: false).profileOnion, contact.onion); + Provider.of(context, listen: false).removeContact(contact.onion); + } else { + Provider.of(context, listen: false).cwtch.BlockContact(Provider.of(context, listen: false).profileOnion, contact.onion); + } } String dateToNiceString(DateTime date) { diff --git a/lib/widgets/messagebubble.dart b/lib/widgets/messagebubble.dart index d79fb57..2fbf4cb 100644 --- a/lib/widgets/messagebubble.dart +++ b/lib/widgets/messagebubble.dart @@ -26,52 +26,55 @@ class _MessageBubbleState extends State { } return LayoutBuilder(builder: (context, constraints) { //print(constraints.toString()+", "+constraints.maxWidth.toString()); - return Container(child:Container( - decoration: BoxDecoration( - color: fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor() : Provider.of(context).theme.messageFromOtherBackgroundColor(), - border: Border.all(color: fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor() : Provider.of(context).theme.messageFromOtherBackgroundColor(), width: 1), - borderRadius: BorderRadius.only( - topLeft: Radius.circular(borderRadiousEh), - topRight: Radius.circular(borderRadiousEh), - bottomLeft: fromMe ? Radius.circular(borderRadiousEh) : Radius.zero, - bottomRight: fromMe ? Radius.zero : Radius.circular(borderRadiousEh), - ), - ), - child: Padding( - padding: EdgeInsets.all(9.0), - child: Column( - crossAxisAlignment: fromMe ? CrossAxisAlignment.end : CrossAxisAlignment.start, - mainAxisAlignment: fromMe ? MainAxisAlignment.end : MainAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - //Flexible( - //fit: BoxFit.contain, - SelectableText( - (Provider.of(context).message ?? "") + '\u202F', - key: Key(myKey), - focusNode: _focus, - style: TextStyle( - color: fromMe ? Provider.of(context).theme.messageFromMeTextColor() : Provider.of(context).theme.messageFromOtherTextColor(), + return Container( + child: Container( + decoration: BoxDecoration( + color: fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor() : Provider.of(context).theme.messageFromOtherBackgroundColor(), + border: + Border.all(color: fromMe ? Provider.of(context).theme.messageFromMeBackgroundColor() : Provider.of(context).theme.messageFromOtherBackgroundColor(), width: 1), + borderRadius: BorderRadius.only( + topLeft: Radius.circular(borderRadiousEh), + topRight: Radius.circular(borderRadiousEh), + bottomLeft: fromMe ? Radius.circular(borderRadiousEh) : Radius.zero, + bottomRight: fromMe ? Radius.zero : Radius.circular(borderRadiousEh), ), - textAlign: TextAlign.left, - textWidthBasis: TextWidthBasis.longestLine, ), - Center(widthFactor: 1.0, child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text(prettyDate, - style: TextStyle( - fontSize: 9.0, - color: fromMe ? Provider.of(context).theme.messageFromMeTextColor() : Provider.of(context).theme.messageFromOtherTextColor(), - ), - textAlign: fromMe ? TextAlign.right : TextAlign.left), - Provider.of(context).ackd - ? Icon(Icons.check_circle_outline, color: Provider.of(context).theme.messageFromMeTextColor(), size: 12) - : Icon(Icons.hourglass_bottom_outlined, color: Provider.of(context).theme.messageFromMeTextColor(), size: 12) - ], - ) - )])), - )); + child: Padding( + padding: EdgeInsets.all(9.0), + child: Column( + crossAxisAlignment: fromMe ? CrossAxisAlignment.end : CrossAxisAlignment.start, + mainAxisAlignment: fromMe ? MainAxisAlignment.end : MainAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + //Flexible( + //fit: BoxFit.contain, + SelectableText( + (Provider.of(context).message ?? "") + '\u202F', + key: Key(myKey), + focusNode: _focus, + style: TextStyle( + color: fromMe ? Provider.of(context).theme.messageFromMeTextColor() : Provider.of(context).theme.messageFromOtherTextColor(), + ), + textAlign: TextAlign.left, + textWidthBasis: TextWidthBasis.longestLine, + ), + Center( + widthFactor: 1.0, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text(prettyDate, + style: TextStyle( + fontSize: 9.0, + color: fromMe ? Provider.of(context).theme.messageFromMeTextColor() : Provider.of(context).theme.messageFromOtherTextColor(), + ), + textAlign: fromMe ? TextAlign.right : TextAlign.left), + Provider.of(context).ackd + ? Icon(Icons.check_circle_outline, color: Provider.of(context).theme.messageFromMeTextColor(), size: 12) + : Icon(Icons.hourglass_bottom_outlined, color: Provider.of(context).theme.messageFromMeTextColor(), size: 12) + ], + )) + ])))); }); } }