From b3dd5e2fee74449dfc0a653db3b1bb778dd45035 Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Wed, 9 Jun 2021 12:57:22 -0700 Subject: [PATCH] Persist rejection action --- LIBCWTCH-GO.version | 2 +- .../kotlin/im/cwtch/flwtch/MainActivity.kt | 7 +++++ assets/fonts/CwtchIcons.ttf | Bin 20140 -> 19920 bytes lib/cwtch/cwtch.dart | 4 +++ lib/cwtch/cwtchNotifier.dart | 9 +++--- lib/cwtch/ffi.dart | 13 ++++++++ lib/cwtch/gomobile.dart | 7 +++++ lib/cwtch_icons_icons.dart | 5 +-- lib/model.dart | 10 +++++- lib/views/addcontactview.dart | 6 +++- lib/views/addeditprofileview.dart | 7 ++++- lib/widgets/buttontextfield.dart | 1 + lib/widgets/invitationbubble.dart | 29 +++++++++--------- pubspec.yaml | 2 +- 14 files changed, 76 insertions(+), 26 deletions(-) diff --git a/LIBCWTCH-GO.version b/LIBCWTCH-GO.version index 8e40226..d12319f 100644 --- a/LIBCWTCH-GO.version +++ b/LIBCWTCH-GO.version @@ -1 +1 @@ -v0.0.2-49-g6a0e839-2021-06-02-19-40 \ No newline at end of file +v0.0.2-58-gfddfd41-2021-06-10-18-36 \ No newline at end of file diff --git a/android/app/src/main/kotlin/im/cwtch/flwtch/MainActivity.kt b/android/app/src/main/kotlin/im/cwtch/flwtch/MainActivity.kt index 5066757..dc34259 100644 --- a/android/app/src/main/kotlin/im/cwtch/flwtch/MainActivity.kt +++ b/android/app/src/main/kotlin/im/cwtch/flwtch/MainActivity.kt @@ -129,6 +129,13 @@ class MainActivity: FlutterActivity() { val end = (call.argument("end") as? Long) ?: 0; result.success(Cwtch.getMessages(profile, handle, start, end)) } + "UpdateMessageFlags" -> { + val profile = (call.argument("profile") as? String) ?: ""; + val handle = (call.argument("contact") as? String) ?: ""; + val midx = (call.argument("midx") as? Long) ?: 0; + val flags = (call.argument("flags") as? Long) ?: 0; + Cwtch.updateMessageFlags(profile, handle, midx, flags); + } "AcceptContact" -> { val profile = (call.argument("ProfileOnion") as? String) ?: ""; val handle = (call.argument("handle") as? String) ?: ""; diff --git a/assets/fonts/CwtchIcons.ttf b/assets/fonts/CwtchIcons.ttf index ef83f2ec4b529c35bf8df8aef5dd16aada8c0846..9a6e5cbd392d7e8f745d942b10720f3e9a054aaa 100644 GIT binary patch delta 1165 zcmX|BO>7%g5T5sTy&K2zx_0)*-q_o$y>^myvQ6yRN!!>-<+cP7g;Kx`6>TtyTenJL zlZ4VpNJfQ9ZQ4q0eWT(+g%nkx2Q0y*0wL532q?Xl0|x>|LWl$0NX%?pc&ktI^Ua%i zZ{}$?KOm3pkeh?m4}X3CZ2)ErfJ>iUSUdCCz?XS|b_3wROsQCy4?ccX2Y{at=@L5l z46}jy1B6jpT)p`GpUox!`57^@P@XGXr&Sifxr+S##lpo3St6sz`O)rPDl8T^?%WIk z9JXr?R>~{x)px(XaTVa1O+0{c>p>)!2ZFJPTb^=?9@6CNjNE+1e=6c|zOu+b3XlwSJWC08|4Oe#adhyBXNVvBvR6 zzHy~-&Av|qo?7d+_5UImz1jL|>&(ZFm$4{UJH-A|JI3;!4m*yuZ)&f6eai7YbMQDO zL%<6tv9UJ5_FZWKUPQUx0=$IsS_^=wYm?58TDWC>bnS<$FKEz*-hgax9}5sb6h;aHDF z_~CQ{ZI0(+ojTHzSJX&SPh?5TJ8Y3ok&Ecz80zVyUe$;c4RaX6?Ygpdpo|gJ=$q3O zRaH77{%LWg@5oz%XU`swG$Bh;;D{`Eh!7Av+zhewK%dv$laRf^(1=%3{Bq<>rrqtN zgfea7*3L{cYZ%!m+1Qm~Q`>n(i^nyx5i+;$YSp+;_1W}SZlBLho&?=dC37gFFy7v- z8Ts_k{>vUA))x~3R1rnLL+uC~Vb#ToUPiY_XmF^TbqCrwIUwyH8hIf~`!*lE{pi%WKJ@wPn*V*!~`p ze3-hrt#-41E1Mfvs=-iTJeQFbg$V|Hdu2aQo#LtUQ=Zi8C0*%0JZbbX#?E6;VxPag zSJmRQWSO2w)Yoenr;8``ozL%1yg^)2CO0t@BC5Yj#YCZia&Y2+=<~8+MfE4r?y2*q z%q}y~=AG=GDV*H-LlQ(QsmC=1ALTpaKh(E!k64ngeL8uMk`wjUo>d)VLScS>xwx`2 tJ6Eo(4J7!drfa3RG(T`|>B70yqHCd8xKJE8yIg*=(%#bNN(KB={0n&p^xpsg delta 1388 zcmYjNU1%It6h3F}oqKm@W_M&H&D^$AqBO`t7XluO(j1| z5^F2MR#0df3YC=#7T>fMX&)pn3dL6?f>uGqP^5?tsSouA#mf`T-OZu50oWk`VVzn!_rlCCuYC&;{}tfz#$vr%8~hyK0f4(CsK!i0X$iw zo)eAL^~A={#}AAF%)CVdq~E-idtx4tVoBD-aJl%y`4ozX&q*%X&!+9ZD5f#PFe#{IB@ue!UbsrW$)>|t#FM!*t-yF zI!L~2t!wNiC5l#+|K4iwxM_qg9=&ADZ@;L1#fldwkp!M0z1bCbmh{E0zzNb@U4gmQ zM*MwQ8hkLcHuUlKe(lm!t9bNw(+23Y*cJ8&%)&gp3a`T@xB~CNNAM}^z<2N?+=oBV z#!>VE4&=R{f_blm(wi!WTFB_}ljzD^UdSXmZg2Sbj$01gUO`p{%fUg%b%M#jub>y& zlT=2QgL2SxTNGmPXd2fiyzbSc@Dc`t)5^_#{dnlwZ(j6MZ> z)P|%?AsLi@Sfi4Z?Uv$#I>r%OHj5=}{$8dD7srO-IEMwBBw z;jz&qN}HsFp8Z();3&;Qd)xa&ZZw;pil9j+^hSZ?9j#!%hM81UAvJTn$2L?;8|XK< zo*vL_HEFYE&zPx&+pAKu`g(0EA?zqZGo)}#Q%Ts&>glsJd0)g6NjFs}6d6l9GNz66 zGq%rRF;yEJ!QxNFjy=Ef1q$q6;vuxX`i&yh-r&n zKZ{>j^l|U`xpq10PvmeX=g*O|y%`1B__FO{b2njdt#3fHRNC|*8C|+c|Irl&q!4wA z7*9rYDTt;uW?L~#X#>OzjYkxsi$#poxMol$5%N7TNQA{y zU45RI)(H*Ml?WcE19ex(R984uTOFlepWe_^ZnVbvu$+w+5YqB*Bs|tUmp8# z`<0n~by8oiuhfdCSI(T?s2dBbjdR6nt+rNQU)PuF)id?tskPOY8d}$0SgdXU{0;o> B;#B|u diff --git a/lib/cwtch/cwtch.dart b/lib/cwtch/cwtch.dart index cb2b0cd..4f96d6b 100644 --- a/lib/cwtch/cwtch.dart +++ b/lib/cwtch/cwtch.dart @@ -1,3 +1,5 @@ +import 'dart:ffi'; + abstract class Cwtch { // ignore: non_constant_identifier_names Future Start(); @@ -38,6 +40,8 @@ abstract class Cwtch { // ignore: non_constant_identifier_names Future GetMessage(String profile, String handle, int index); // ignore: non_constant_identifier_names + void UpdateMessageFlags(String profile, String handle, int index, int flags); + // ignore: non_constant_identifier_names Future GetMessages(String profile, String handle, int start, int end); // ignore: non_constant_identifier_names void SendMessage(String profile, String handle, String message); diff --git a/lib/cwtch/cwtchNotifier.dart b/lib/cwtch/cwtchNotifier.dart index 021f94c..950e21c 100644 --- a/lib/cwtch/cwtchNotifier.dart +++ b/lib/cwtch/cwtchNotifier.dart @@ -178,23 +178,24 @@ class CwtchNotifier { profileCN.getProfile(data["ProfileOnion"])?.replaceServers(data["ServerList"]); break; case "NewGroup": - print("new group invite: $data"); + print("new group: $data"); String invite = data["GroupInvite"].toString(); if (invite.startsWith("torv3")) { String inviteJson = new String.fromCharCodes(base64Decode(invite.substring(5))); dynamic groupInvite = jsonDecode(inviteJson); - print("new group invite: $groupInvite"); + print("group invite: $groupInvite"); // Retrieve Server Status from Cache... String status = ""; - ServerInfoState? serverInfoState = profileCN.getProfile(data["ProfileOnion"])?.serverList.getServer(groupInvite["ServerHost"]); + ServerInfoState? serverInfoState = profileCN.getProfile(data["ProfileOnion"])!.serverList.getServer(groupInvite["ServerHost"]); if (serverInfoState != null) { + print("Got server status: " + serverInfoState.status); status = serverInfoState.status; } if (profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(groupInvite["GroupID"]) == null) { profileCN.getProfile(data["ProfileOnion"])?.contactList.add(ContactInfoState(data["ProfileOnion"], groupInvite["GroupID"], - isInvitation: true, + isInvitation: false, imagePath: data["PicturePath"], nickname: groupInvite["GroupName"], server: groupInvite["ServerHost"], diff --git a/lib/cwtch/ffi.dart b/lib/cwtch/ffi.dart index 410ffba..df0e163 100644 --- a/lib/cwtch/ffi.dart +++ b/lib/cwtch/ffi.dart @@ -27,6 +27,9 @@ typedef VoidFromStringStringStringFn = void Function(Pointer, int, Pointer typedef void_from_string_string_string_string_function = Void Function(Pointer, Int32, Pointer, Int32, Pointer, Int32, Pointer, Int32); typedef VoidFromStringStringStringStringFn = void Function(Pointer, int, Pointer, int, Pointer, int, Pointer, int); +typedef void_from_string_string_int_int_function = Void Function(Pointer, Int32, Pointer, Int32, Int64, Int64); +typedef VoidFromStringStringIntIntFn = void Function(Pointer, int, Pointer, int, int, int); + typedef access_cwtch_eventbus_function = Void Function(); typedef NextEventFn = void Function(); @@ -384,4 +387,14 @@ class CwtchFfi implements Cwtch { final u2 = groupHandle.toNativeUtf8(); RejectInvite(u1, u1.length, u2, u2.length); } + + @override + void UpdateMessageFlags(String profile, String handle, int index, int flags) { + var updateMessageFlagsC = library.lookup>("c_UpdateMessageFlags"); + // ignore: non_constant_identifier_names + final updateMessageFlags = updateMessageFlagsC.asFunction(); + final utf8profile = profile.toNativeUtf8(); + final utf8handle = handle.toNativeUtf8(); + updateMessageFlags(utf8profile, utf8profile.length, utf8handle, utf8handle.length, index, flags); + } } diff --git a/lib/cwtch/gomobile.dart b/lib/cwtch/gomobile.dart index 210eb42..aba1f6e 100644 --- a/lib/cwtch/gomobile.dart +++ b/lib/cwtch/gomobile.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:ffi'; import 'dart:io'; import 'package:cwtch/config.dart'; @@ -187,4 +188,10 @@ class CwtchGomobile implements Cwtch { void LeaveGroup(String profileOnion, String groupHandle) { cwtchPlatform.invokeMethod("LeaveGroup", {"ProfileOnion": profileOnion, "handle": groupHandle}); } + + @override + void UpdateMessageFlags(String profile, String handle, int index, int flags) { + print("gomobile.dart UpdateMessageFlags " + index.toString()); + cwtchPlatform.invokeMethod("UpdateMessageFlags", {"profile": profile, "contact": handle, "index": index, "flags": flags}); + } } diff --git a/lib/cwtch_icons_icons.dart b/lib/cwtch_icons_icons.dart index 8552f4d..6c89b9a 100644 --- a/lib/cwtch_icons_icons.dart +++ b/lib/cwtch_icons_icons.dart @@ -1,4 +1,4 @@ -/// Flutter icons MyFlutterApp +/// Flutter icons CwtchIcons /// Copyright (C) 2021 by original authors @ fluttericon.com, fontello.com /// This font was generated by FlutterIcon.com, which is derived from Fontello. /// @@ -102,8 +102,9 @@ class CwtchIcons { static const IconData add_group = IconData(0xe84e, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData add_peer = IconData(0xe84f, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData add_24px = IconData(0xe850, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData address_copy_2 = IconData(0xe852, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData address = IconData(0xe856, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData send_invite = IconData(0xe888, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData copy_address = IconData(0xe889, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData leave_group = IconData(0xe88a, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData leave_chat = IconData(0xe88b, fontFamily: _kFontFam, fontPackage: _kFontPkg); } diff --git a/lib/model.dart b/lib/model.dart index a07fb07..7dec94b 100644 --- a/lib/model.dart +++ b/lib/model.dart @@ -183,7 +183,7 @@ class ProfileInfoState extends ChangeNotifier { // Parse out the server list json into our server info state struct... void replaceServers(String serversJson) { - if (serversJson != null && serversJson != "" && serversJson != "null") { + if (serversJson != "" && serversJson != "null") { print("got servers $serversJson"); List servers = jsonDecode(serversJson); this._servers.replace(servers.map((server) { @@ -382,6 +382,7 @@ class MessageState extends ChangeNotifier { late String _inviteNick; late DateTime _timestamp; late String _senderOnion; + late int _flags; String? _senderImage; late String _signature = ""; late bool _ackd = false; @@ -402,6 +403,12 @@ class MessageState extends ChangeNotifier { get message => this._message; get overlay => this._overlay; get timestamp => this._timestamp; + int get flags => this._flags; + set flags(int newVal) { + this._flags = newVal; + notifyListeners(); + } + bool get ackd => this._ackd; bool get error => this._error; bool get malformed => this._malformed; @@ -450,6 +457,7 @@ class MessageState extends ChangeNotifier { this._timestamp = DateTime.tryParse(messageWrapper['Timestamp'])!; this._senderOnion = messageWrapper['PeerID']; this._senderImage = messageWrapper['ContactImage']; + this._flags = int.parse(messageWrapper['Flags'].toString(), radix: 2); // If this is a group, store the signature if (contactHandle.length == 32) { diff --git a/lib/views/addcontactview.dart b/lib/views/addcontactview.dart index 3d9bc61..3c27c64 100644 --- a/lib/views/addcontactview.dart +++ b/lib/views/addcontactview.dart @@ -119,7 +119,11 @@ class _AddContactViewState extends State { CwtchButtonTextField( controller: ctrlrOnion, onPressed: _copyOnion, - icon: Icon(CwtchIcons.copy_address), + readonly: true, + icon: Icon( + CwtchIcons.address_copy_2, + size: 32, + ), tooltip: AppLocalizations.of(context)!.copyBtn, ), SizedBox( diff --git a/lib/views/addeditprofileview.dart b/lib/views/addeditprofileview.dart index c27308c..7fcc3b4 100644 --- a/lib/views/addeditprofileview.dart +++ b/lib/views/addeditprofileview.dart @@ -11,6 +11,7 @@ import 'package:cwtch/widgets/textfield.dart'; import 'package:provider/provider.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import '../cwtch_icons_icons.dart'; import '../main.dart'; import '../opaque.dart'; import '../settings.dart'; @@ -122,7 +123,11 @@ class _AddEditProfileViewState extends State { CwtchButtonTextField( controller: ctrlrOnion, onPressed: _copyOnion, - icon: Icon(Icons.copy), + readonly: true, + icon: Icon( + CwtchIcons.address_copy_2, + size: 32, + ), tooltip: AppLocalizations.of(context)!.copyBtn, ) ])), diff --git a/lib/widgets/buttontextfield.dart b/lib/widgets/buttontextfield.dart index 83083fb..65f8fa5 100644 --- a/lib/widgets/buttontextfield.dart +++ b/lib/widgets/buttontextfield.dart @@ -28,6 +28,7 @@ class _CwtchButtonTextFieldState extends State { suffixIcon: IconButton( onPressed: widget.onPressed, icon: widget.icon, + padding: EdgeInsets.fromLTRB(0.0, 4.0, 2.0, 2.0), tooltip: widget.tooltip, enableFeedback: true, color: theme.current().mainTextColor(), diff --git a/lib/widgets/invitationbubble.dart b/lib/widgets/invitationbubble.dart index 232fde3..7913f38 100644 --- a/lib/widgets/invitationbubble.dart +++ b/lib/widgets/invitationbubble.dart @@ -22,15 +22,17 @@ class InvitationBubble extends StatefulWidget { class InvitationBubbleState extends State { bool rejected = false; + bool isAccepted = false; FocusNode _focus = FocusNode(); @override Widget build(BuildContext context) { var fromMe = Provider.of(context).senderOnion == Provider.of(context).onion; var isGroup = Provider.of(context).overlay == 101; - var isAccepted = Provider.of(context).contactList.getContact(Provider.of(context).inviteTarget) != null; + isAccepted = Provider.of(context).contactList.getContact(Provider.of(context).inviteTarget) != null; var prettyDate = ""; var borderRadiousEh = 15.0; + rejected = Provider.of(context).flags & 0x01 == 0x01; var myKey = Provider.of(context).profileOnion + "::" + Provider.of(context).contactHandle + "::" + Provider.of(context).messageIndex.toString(); if (Provider.of(context).timestamp != null) { @@ -54,8 +56,6 @@ class InvitationBubbleState extends State { child: SelectableText(senderDisplayStr + '\u202F', style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of(context).theme.messageFromMeTextColor() : Provider.of(context).theme.messageFromOtherTextColor()))); - // todo: translations - // If we receive an invite for ourselves, treat it as a bug. The UI no longer allows this so it could have only come from // some kind of malfeasance. var selfInvite = Provider.of(context).inviteNick == Provider.of(context).onion; @@ -120,22 +120,21 @@ class InvitationBubbleState extends State { } void _btnReject() { - //todo: how should we track inline invite rejections? - setState(() => this.rejected = true); + setState(() { + var profileOnion = Provider.of(context, listen: false).onion; + var contact = Provider.of(context, listen: false).onion; + var idx = Provider.of(context, listen: false).messageIndex; + Provider.of(context, listen: false).cwtch.UpdateMessageFlags(profileOnion, contact, idx, Provider.of(context, listen: false).flags | 0x01); + Provider.of(context).flags |= 0x01; + }); } void _btnAccept() { - var profileOnion = Provider.of(context, listen: false).onion; - if (Provider.of(context, listen: false).overlay == 100) { - final setPeerAttribute = { - "EventType": "AddContact", - "Data": {"ImportString": Provider.of(context, listen: false).message}, - }; - final setPeerAttributeJson = jsonEncode(setPeerAttribute); - Provider.of(context, listen: false).cwtch.SendProfileEvent(profileOnion, setPeerAttributeJson); - } else { + setState(() { + var profileOnion = Provider.of(context, listen: false).onion; Provider.of(context, listen: false).cwtch.ImportBundle(profileOnion, Provider.of(context, listen: false).message); - } + isAccepted = true; + }); } // Construct an invite chrome for the sender diff --git a/pubspec.yaml b/pubspec.yaml index b232973..45e488b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -15,7 +15,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion. # Read more about iOS versioning at # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -version: 1.0.0+10 +version: 1.0.0+11 environment: sdk: ">=2.12.0 <3.0.0"