Merge pull request 'Accept/Reject Group invites & other bug fixes' (#62) from groups into trunk
continuous-integration/drone/push Build is failing Details

Reviewed-on: #62
This commit is contained in:
erinn 2021-04-28 16:55:57 -07:00
commit 97b5709c75
10 changed files with 109 additions and 76 deletions

View File

@ -172,6 +172,11 @@ class MainActivity: FlutterActivity() {
val value = (call.argument("value") as? String) ?: ""; val value = (call.argument("value") as? String) ?: "";
Cwtch.setGroupAttribute(profile, groupHandle, key, value); 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() else -> result.notImplemented()
} }
} }

Binary file not shown.

View File

@ -46,6 +46,8 @@ abstract class Cwtch {
void ImportBundle(String profile, String bundle); void ImportBundle(String profile, String bundle);
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
void SetGroupAttribute(String profile, String groupHandle, String key, String value); void SetGroupAttribute(String profile, String groupHandle, String key, String value);
// ignore: non_constant_identifier_names
void RejectInvite(String profileOnion, String groupHandle);
void dispose(); void dispose();
} }

View File

@ -65,8 +65,7 @@ class CwtchNotifier {
case "NewMessageFromGroup": case "NewMessageFromGroup":
profileCN.getProfile(data["ProfileOnion"]).contactList.getContact(data["GroupID"]).unreadMessages++; profileCN.getProfile(data["ProfileOnion"]).contactList.getContact(data["GroupID"]).unreadMessages++;
profileCN.getProfile(data["ProfileOnion"]).contactList.getContact(data["GroupID"]).totalMessages++; 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["GroupID"], DateTime.now());
profileCN.getProfile(data["ProfileOnion"]).contactList.updateLastMessageTime(data["RemotePeer"], DateTime.now());
break; break;
case "AppError": case "AppError":
print("New App Error: $data"); print("New App Error: $data");
@ -95,16 +94,15 @@ class CwtchNotifier {
break; break;
case "NewGroupInvite": case "NewGroupInvite":
print("new group invite: $data"); print("new group invite: $data");
// TODO Add Group Dynamically
dynamic groupInvite = jsonDecode(data["GroupInvite"]); dynamic groupInvite = jsonDecode(data["GroupInvite"]);
profileCN.getProfile(data["ProfileOnion"]).contactList.add(ContactInfoState( 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()));
groupInvite["GroupID"], profileCN.getProfile(data["ProfileOnion"]).contactList.updateLastMessageTime(groupInvite["GroupID"], DateTime.now());
isInvitation: true, break;
imagePath: data["PicturePath"], case "AcceptGroupInvite":
nickname: groupInvite["GroupName"], print("accept group invite: $data");
server: groupInvite["ServerHost"], profileCN.getProfile(data["ProfileOnion"]).contactList.getContact(data["GroupID"]).isInvitation = false;
isGroup: true)); profileCN.getProfile(data["ProfileOnion"]).contactList.updateLastMessageTime(data["GroupID"], DateTime.now());
break; break;
case "ServerStateChange": case "ServerStateChange":
print("server state change: $data"); print("server state change: $data");

View File

@ -332,4 +332,15 @@ class CwtchFfi implements Cwtch {
final u4 = value.toNativeUtf8(); final u4 = value.toNativeUtf8();
SetGroupAttribute(u1, u1.length, u2, u2.length, u3, u3.length, u4, u4.length); 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<NativeFunction<string_string_to_void_function>>("c_RejectInvite");
// ignore: non_constant_identifier_names
final RejectInvite = rejectInvite.asFunction<VoidFromStringStringFn>();
final u1 = profileOnion.toNativeUtf8();
final u2 = groupHandle.toNativeUtf8();
RejectInvite(u1, u1.length, u2, u2.length);
}
} }

View File

@ -159,4 +159,10 @@ class CwtchGomobile implements Cwtch {
void SetGroupAttribute(String profileOnion, String groupHandle, String key, String value) { void SetGroupAttribute(String profileOnion, String groupHandle, String key, String value) {
cwtchPlatform.invokeMethod("SetGroupAttribute", {"ProfileOnion": profileOnion, "groupHandle": groupHandle, "key": key, "value": 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});
}
} }

View File

@ -141,9 +141,7 @@ class ProfileInfoState extends ChangeNotifier {
if (contactsJson != null && contactsJson != "" && contactsJson != "null") { if (contactsJson != null && contactsJson != "" && contactsJson != "null") {
List<dynamic> contacts = jsonDecode(contactsJson); List<dynamic> contacts = jsonDecode(contactsJson);
this._contacts.addAll(contacts.map((contact) { this._contacts.addAll(contacts.map((contact) {
return ContactInfoState( return ContactInfoState(this.onion, contact["onion"],
this.onion,
contact["onion"],
nickname: contact["name"], nickname: contact["name"],
status: contact["status"], status: contact["status"],
imagePath: contact["picture"], imagePath: contact["picture"],
@ -203,6 +201,14 @@ class ProfileInfoState extends ChangeNotifier {
notifyListeners(); 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; ContactListState get contactList => this._contacts;
ServerListState get serverList => this._servers; ServerListState get serverList => this._servers;
@ -233,7 +239,7 @@ class ContactInfoState extends ChangeNotifier {
ContactInfoState( ContactInfoState(
this.profileOnion, this.profileOnion,
this.onion,{ this.onion, {
nickname = "", nickname = "",
isGroup = false, isGroup = false,
isInvitation = false, isInvitation = false,

View File

@ -105,20 +105,18 @@ class _MessageViewState extends State<MessageView> {
onSubmitted: _sendMessage, onSubmitted: _sendMessage,
)), )),
SizedBox( SizedBox(
width: 100, width: 100,
height: 90, height: 90,
child: Padding( child: Padding(
padding: EdgeInsets.fromLTRB(2, 2, 2, 2), padding: EdgeInsets.fromLTRB(2, 2, 2, 2),
child: ElevatedButton( child: ElevatedButton(
child: Icon(Icons.send, color: Provider.of<Settings>(context).theme.mainTextColor()), child: Icon(Icons.send, color: Provider.of<Settings>(context).theme.mainTextColor()),
style: ButtonStyle( style: ButtonStyle(
fixedSize: MaterialStateProperty.all(Size(86, 40)), fixedSize: MaterialStateProperty.all(Size(86, 40)),
backgroundColor: MaterialStateProperty.all(Provider.of<Settings>(context).theme.defaultButtonColor()), backgroundColor: MaterialStateProperty.all(Provider.of<Settings>(context).theme.defaultButtonColor()),
), ),
onPressed: _sendMessage, onPressed: _sendMessage,
) ))),
)
),
], ],
), ),
); );

View File

@ -109,9 +109,13 @@ class _ContactRowState extends State<ContactRow> {
} }
void _btnReject() { void _btnReject() {
Provider.of<FlwtchState>(context, listen: false) ContactInfoState contact = Provider.of<ContactInfoState>(context, listen: false);
.cwtch if (contact.isGroup == true) {
.BlockContact(Provider.of<ContactInfoState>(context, listen: false).profileOnion, Provider.of<ContactInfoState>(context, listen: false).onion); Provider.of<FlwtchState>(context, listen: false).cwtch.RejectInvite(Provider.of<ContactInfoState>(context, listen: false).profileOnion, contact.onion);
Provider.of<ProfileInfoState>(context, listen: false).removeContact(contact.onion);
} else {
Provider.of<FlwtchState>(context, listen: false).cwtch.BlockContact(Provider.of<ContactInfoState>(context, listen: false).profileOnion, contact.onion);
}
} }
String dateToNiceString(DateTime date) { String dateToNiceString(DateTime date) {

View File

@ -26,52 +26,55 @@ class _MessageBubbleState extends State<MessageBubble> {
} }
return LayoutBuilder(builder: (context, constraints) { return LayoutBuilder(builder: (context, constraints) {
//print(constraints.toString()+", "+constraints.maxWidth.toString()); //print(constraints.toString()+", "+constraints.maxWidth.toString());
return Container(child:Container( return Container(
decoration: BoxDecoration( child: Container(
color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeBackgroundColor() : Provider.of<Settings>(context).theme.messageFromOtherBackgroundColor(), decoration: BoxDecoration(
border: Border.all(color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeBackgroundColor() : Provider.of<Settings>(context).theme.messageFromOtherBackgroundColor(), width: 1), color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeBackgroundColor() : Provider.of<Settings>(context).theme.messageFromOtherBackgroundColor(),
borderRadius: BorderRadius.only( border:
topLeft: Radius.circular(borderRadiousEh), Border.all(color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeBackgroundColor() : Provider.of<Settings>(context).theme.messageFromOtherBackgroundColor(), width: 1),
topRight: Radius.circular(borderRadiousEh), borderRadius: BorderRadius.only(
bottomLeft: fromMe ? Radius.circular(borderRadiousEh) : Radius.zero, topLeft: Radius.circular(borderRadiousEh),
bottomRight: fromMe ? Radius.zero : 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<MessageState>(context).message ?? "") + '\u202F',
key: Key(myKey),
focusNode: _focus,
style: TextStyle(
color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeTextColor() : Provider.of<Settings>(context).theme.messageFromOtherTextColor(),
), ),
textAlign: TextAlign.left,
textWidthBasis: TextWidthBasis.longestLine,
), ),
Center(widthFactor: 1.0, child: Row( child: Padding(
mainAxisSize: MainAxisSize.min, padding: EdgeInsets.all(9.0),
children: [ child: Column(
Text(prettyDate, crossAxisAlignment: fromMe ? CrossAxisAlignment.end : CrossAxisAlignment.start,
style: TextStyle( mainAxisAlignment: fromMe ? MainAxisAlignment.end : MainAxisAlignment.start,
fontSize: 9.0, mainAxisSize: MainAxisSize.min,
color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeTextColor() : Provider.of<Settings>(context).theme.messageFromOtherTextColor(), children: [
), //Flexible(
textAlign: fromMe ? TextAlign.right : TextAlign.left), //fit: BoxFit.contain,
Provider.of<MessageState>(context).ackd SelectableText(
? Icon(Icons.check_circle_outline, color: Provider.of<Settings>(context).theme.messageFromMeTextColor(), size: 12) (Provider.of<MessageState>(context).message ?? "") + '\u202F',
: Icon(Icons.hourglass_bottom_outlined, color: Provider.of<Settings>(context).theme.messageFromMeTextColor(), size: 12) key: Key(myKey),
], focusNode: _focus,
) style: TextStyle(
)])), color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeTextColor() : Provider.of<Settings>(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<Settings>(context).theme.messageFromMeTextColor() : Provider.of<Settings>(context).theme.messageFromOtherTextColor(),
),
textAlign: fromMe ? TextAlign.right : TextAlign.left),
Provider.of<MessageState>(context).ackd
? Icon(Icons.check_circle_outline, color: Provider.of<Settings>(context).theme.messageFromMeTextColor(), size: 12)
: Icon(Icons.hourglass_bottom_outlined, color: Provider.of<Settings>(context).theme.messageFromMeTextColor(), size: 12)
],
))
]))));
}); });
} }
} }