Persist rejection action
continuous-integration/drone/pr Build is passing Details

This commit is contained in:
Sarah Jamie Lewis 2021-06-09 12:57:22 -07:00
parent aa0a1d9a26
commit b3dd5e2fee
14 changed files with 76 additions and 26 deletions

View File

@ -1 +1 @@
v0.0.2-49-g6a0e839-2021-06-02-19-40 v0.0.2-58-gfddfd41-2021-06-10-18-36

View File

@ -129,6 +129,13 @@ class MainActivity: FlutterActivity() {
val end = (call.argument("end") as? Long) ?: 0; val end = (call.argument("end") as? Long) ?: 0;
result.success(Cwtch.getMessages(profile, handle, start, end)) 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" -> { "AcceptContact" -> {
val profile = (call.argument("ProfileOnion") as? String) ?: ""; val profile = (call.argument("ProfileOnion") as? String) ?: "";
val handle = (call.argument("handle") as? String) ?: ""; val handle = (call.argument("handle") as? String) ?: "";

Binary file not shown.

View File

@ -1,3 +1,5 @@
import 'dart:ffi';
abstract class Cwtch { abstract class Cwtch {
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
Future<void> Start(); Future<void> Start();
@ -38,6 +40,8 @@ abstract class Cwtch {
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
Future<dynamic> GetMessage(String profile, String handle, int index); Future<dynamic> GetMessage(String profile, String handle, int index);
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
void UpdateMessageFlags(String profile, String handle, int index, int flags);
// ignore: non_constant_identifier_names
Future<dynamic> GetMessages(String profile, String handle, int start, int end); Future<dynamic> GetMessages(String profile, String handle, int start, int end);
// ignore: non_constant_identifier_names // ignore: non_constant_identifier_names
void SendMessage(String profile, String handle, String message); void SendMessage(String profile, String handle, String message);

View File

@ -178,23 +178,24 @@ class CwtchNotifier {
profileCN.getProfile(data["ProfileOnion"])?.replaceServers(data["ServerList"]); profileCN.getProfile(data["ProfileOnion"])?.replaceServers(data["ServerList"]);
break; break;
case "NewGroup": case "NewGroup":
print("new group invite: $data"); print("new group: $data");
String invite = data["GroupInvite"].toString(); String invite = data["GroupInvite"].toString();
if (invite.startsWith("torv3")) { if (invite.startsWith("torv3")) {
String inviteJson = new String.fromCharCodes(base64Decode(invite.substring(5))); String inviteJson = new String.fromCharCodes(base64Decode(invite.substring(5)));
dynamic groupInvite = jsonDecode(inviteJson); dynamic groupInvite = jsonDecode(inviteJson);
print("new group invite: $groupInvite"); print("group invite: $groupInvite");
// Retrieve Server Status from Cache... // Retrieve Server Status from Cache...
String status = ""; 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) { if (serverInfoState != null) {
print("Got server status: " + serverInfoState.status);
status = serverInfoState.status; status = serverInfoState.status;
} }
if (profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(groupInvite["GroupID"]) == null) { if (profileCN.getProfile(data["ProfileOnion"])?.contactList.getContact(groupInvite["GroupID"]) == null) {
profileCN.getProfile(data["ProfileOnion"])?.contactList.add(ContactInfoState(data["ProfileOnion"], groupInvite["GroupID"], profileCN.getProfile(data["ProfileOnion"])?.contactList.add(ContactInfoState(data["ProfileOnion"], groupInvite["GroupID"],
isInvitation: true, isInvitation: false,
imagePath: data["PicturePath"], imagePath: data["PicturePath"],
nickname: groupInvite["GroupName"], nickname: groupInvite["GroupName"],
server: groupInvite["ServerHost"], server: groupInvite["ServerHost"],

View File

@ -27,6 +27,9 @@ typedef VoidFromStringStringStringFn = void Function(Pointer<Utf8>, int, Pointer
typedef void_from_string_string_string_string_function = Void Function(Pointer<Utf8>, Int32, Pointer<Utf8>, Int32, Pointer<Utf8>, Int32, Pointer<Utf8>, Int32); typedef void_from_string_string_string_string_function = Void Function(Pointer<Utf8>, Int32, Pointer<Utf8>, Int32, Pointer<Utf8>, Int32, Pointer<Utf8>, Int32);
typedef VoidFromStringStringStringStringFn = void Function(Pointer<Utf8>, int, Pointer<Utf8>, int, Pointer<Utf8>, int, Pointer<Utf8>, int); typedef VoidFromStringStringStringStringFn = void Function(Pointer<Utf8>, int, Pointer<Utf8>, int, Pointer<Utf8>, int, Pointer<Utf8>, int);
typedef void_from_string_string_int_int_function = Void Function(Pointer<Utf8>, Int32, Pointer<Utf8>, Int32, Int64, Int64);
typedef VoidFromStringStringIntIntFn = void Function(Pointer<Utf8>, int, Pointer<Utf8>, int, int, int);
typedef access_cwtch_eventbus_function = Void Function(); typedef access_cwtch_eventbus_function = Void Function();
typedef NextEventFn = void Function(); typedef NextEventFn = void Function();
@ -384,4 +387,14 @@ class CwtchFfi implements Cwtch {
final u2 = groupHandle.toNativeUtf8(); final u2 = groupHandle.toNativeUtf8();
RejectInvite(u1, u1.length, u2, u2.length); RejectInvite(u1, u1.length, u2, u2.length);
} }
@override
void UpdateMessageFlags(String profile, String handle, int index, int flags) {
var updateMessageFlagsC = library.lookup<NativeFunction<void_from_string_string_int_int_function>>("c_UpdateMessageFlags");
// ignore: non_constant_identifier_names
final updateMessageFlags = updateMessageFlagsC.asFunction<VoidFromStringStringIntIntFn>();
final utf8profile = profile.toNativeUtf8();
final utf8handle = handle.toNativeUtf8();
updateMessageFlags(utf8profile, utf8profile.length, utf8handle, utf8handle.length, index, flags);
}
} }

View File

@ -1,4 +1,5 @@
import 'dart:convert'; import 'dart:convert';
import 'dart:ffi';
import 'dart:io'; import 'dart:io';
import 'package:cwtch/config.dart'; import 'package:cwtch/config.dart';
@ -187,4 +188,10 @@ class CwtchGomobile implements Cwtch {
void LeaveGroup(String profileOnion, String groupHandle) { void LeaveGroup(String profileOnion, String groupHandle) {
cwtchPlatform.invokeMethod("LeaveGroup", {"ProfileOnion": profileOnion, "handle": 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});
}
} }

View File

@ -1,4 +1,4 @@
/// Flutter icons MyFlutterApp /// Flutter icons CwtchIcons
/// Copyright (C) 2021 by original authors @ fluttericon.com, fontello.com /// Copyright (C) 2021 by original authors @ fluttericon.com, fontello.com
/// This font was generated by FlutterIcon.com, which is derived from Fontello. /// 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_group = IconData(0xe84e, fontFamily: _kFontFam, fontPackage: _kFontPkg);
static const IconData add_peer = IconData(0xe84f, 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 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 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_group = IconData(0xe88a, fontFamily: _kFontFam, fontPackage: _kFontPkg);
static const IconData leave_chat = IconData(0xe88b, fontFamily: _kFontFam, fontPackage: _kFontPkg); static const IconData leave_chat = IconData(0xe88b, fontFamily: _kFontFam, fontPackage: _kFontPkg);
} }

View File

@ -183,7 +183,7 @@ class ProfileInfoState extends ChangeNotifier {
// Parse out the server list json into our server info state struct... // Parse out the server list json into our server info state struct...
void replaceServers(String serversJson) { void replaceServers(String serversJson) {
if (serversJson != null && serversJson != "" && serversJson != "null") { if (serversJson != "" && serversJson != "null") {
print("got servers $serversJson"); print("got servers $serversJson");
List<dynamic> servers = jsonDecode(serversJson); List<dynamic> servers = jsonDecode(serversJson);
this._servers.replace(servers.map((server) { this._servers.replace(servers.map((server) {
@ -382,6 +382,7 @@ class MessageState extends ChangeNotifier {
late String _inviteNick; late String _inviteNick;
late DateTime _timestamp; late DateTime _timestamp;
late String _senderOnion; late String _senderOnion;
late int _flags;
String? _senderImage; String? _senderImage;
late String _signature = ""; late String _signature = "";
late bool _ackd = false; late bool _ackd = false;
@ -402,6 +403,12 @@ class MessageState extends ChangeNotifier {
get message => this._message; get message => this._message;
get overlay => this._overlay; get overlay => this._overlay;
get timestamp => this._timestamp; get timestamp => this._timestamp;
int get flags => this._flags;
set flags(int newVal) {
this._flags = newVal;
notifyListeners();
}
bool get ackd => this._ackd; bool get ackd => this._ackd;
bool get error => this._error; bool get error => this._error;
bool get malformed => this._malformed; bool get malformed => this._malformed;
@ -450,6 +457,7 @@ class MessageState extends ChangeNotifier {
this._timestamp = DateTime.tryParse(messageWrapper['Timestamp'])!; this._timestamp = DateTime.tryParse(messageWrapper['Timestamp'])!;
this._senderOnion = messageWrapper['PeerID']; this._senderOnion = messageWrapper['PeerID'];
this._senderImage = messageWrapper['ContactImage']; this._senderImage = messageWrapper['ContactImage'];
this._flags = int.parse(messageWrapper['Flags'].toString(), radix: 2);
// If this is a group, store the signature // If this is a group, store the signature
if (contactHandle.length == 32) { if (contactHandle.length == 32) {

View File

@ -119,7 +119,11 @@ class _AddContactViewState extends State<AddContactView> {
CwtchButtonTextField( CwtchButtonTextField(
controller: ctrlrOnion, controller: ctrlrOnion,
onPressed: _copyOnion, onPressed: _copyOnion,
icon: Icon(CwtchIcons.copy_address), readonly: true,
icon: Icon(
CwtchIcons.address_copy_2,
size: 32,
),
tooltip: AppLocalizations.of(context)!.copyBtn, tooltip: AppLocalizations.of(context)!.copyBtn,
), ),
SizedBox( SizedBox(

View File

@ -11,6 +11,7 @@ import 'package:cwtch/widgets/textfield.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import '../cwtch_icons_icons.dart';
import '../main.dart'; import '../main.dart';
import '../opaque.dart'; import '../opaque.dart';
import '../settings.dart'; import '../settings.dart';
@ -122,7 +123,11 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
CwtchButtonTextField( CwtchButtonTextField(
controller: ctrlrOnion, controller: ctrlrOnion,
onPressed: _copyOnion, onPressed: _copyOnion,
icon: Icon(Icons.copy), readonly: true,
icon: Icon(
CwtchIcons.address_copy_2,
size: 32,
),
tooltip: AppLocalizations.of(context)!.copyBtn, tooltip: AppLocalizations.of(context)!.copyBtn,
) )
])), ])),

View File

@ -28,6 +28,7 @@ class _CwtchButtonTextFieldState extends State<CwtchButtonTextField> {
suffixIcon: IconButton( suffixIcon: IconButton(
onPressed: widget.onPressed, onPressed: widget.onPressed,
icon: widget.icon, icon: widget.icon,
padding: EdgeInsets.fromLTRB(0.0, 4.0, 2.0, 2.0),
tooltip: widget.tooltip, tooltip: widget.tooltip,
enableFeedback: true, enableFeedback: true,
color: theme.current().mainTextColor(), color: theme.current().mainTextColor(),

View File

@ -22,15 +22,17 @@ class InvitationBubble extends StatefulWidget {
class InvitationBubbleState extends State<InvitationBubble> { class InvitationBubbleState extends State<InvitationBubble> {
bool rejected = false; bool rejected = false;
bool isAccepted = false;
FocusNode _focus = FocusNode(); FocusNode _focus = FocusNode();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var fromMe = Provider.of<MessageState>(context).senderOnion == Provider.of<ProfileInfoState>(context).onion; var fromMe = Provider.of<MessageState>(context).senderOnion == Provider.of<ProfileInfoState>(context).onion;
var isGroup = Provider.of<MessageState>(context).overlay == 101; var isGroup = Provider.of<MessageState>(context).overlay == 101;
var isAccepted = Provider.of<ProfileInfoState>(context).contactList.getContact(Provider.of<MessageState>(context).inviteTarget) != null; isAccepted = Provider.of<ProfileInfoState>(context).contactList.getContact(Provider.of<MessageState>(context).inviteTarget) != null;
var prettyDate = ""; var prettyDate = "";
var borderRadiousEh = 15.0; var borderRadiousEh = 15.0;
rejected = Provider.of<MessageState>(context).flags & 0x01 == 0x01;
var myKey = Provider.of<MessageState>(context).profileOnion + "::" + Provider.of<MessageState>(context).contactHandle + "::" + Provider.of<MessageState>(context).messageIndex.toString(); var myKey = Provider.of<MessageState>(context).profileOnion + "::" + Provider.of<MessageState>(context).contactHandle + "::" + Provider.of<MessageState>(context).messageIndex.toString();
if (Provider.of<MessageState>(context).timestamp != null) { if (Provider.of<MessageState>(context).timestamp != null) {
@ -54,8 +56,6 @@ class InvitationBubbleState extends State<InvitationBubble> {
child: SelectableText(senderDisplayStr + '\u202F', child: SelectableText(senderDisplayStr + '\u202F',
style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeTextColor() : Provider.of<Settings>(context).theme.messageFromOtherTextColor()))); style: TextStyle(fontSize: 9.0, color: fromMe ? Provider.of<Settings>(context).theme.messageFromMeTextColor() : Provider.of<Settings>(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 // 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. // some kind of malfeasance.
var selfInvite = Provider.of<MessageState>(context).inviteNick == Provider.of<ProfileInfoState>(context).onion; var selfInvite = Provider.of<MessageState>(context).inviteNick == Provider.of<ProfileInfoState>(context).onion;
@ -120,22 +120,21 @@ class InvitationBubbleState extends State<InvitationBubble> {
} }
void _btnReject() { void _btnReject() {
//todo: how should we track inline invite rejections? setState(() {
setState(() => this.rejected = true); var profileOnion = Provider.of<ProfileInfoState>(context, listen: false).onion;
var contact = Provider.of<ContactInfoState>(context, listen: false).onion;
var idx = Provider.of<MessageState>(context, listen: false).messageIndex;
Provider.of<FlwtchState>(context, listen: false).cwtch.UpdateMessageFlags(profileOnion, contact, idx, Provider.of<MessageState>(context, listen: false).flags | 0x01);
Provider.of<MessageState>(context).flags |= 0x01;
});
} }
void _btnAccept() { void _btnAccept() {
var profileOnion = Provider.of<ProfileInfoState>(context, listen: false).onion; setState(() {
if (Provider.of<MessageState>(context, listen: false).overlay == 100) { var profileOnion = Provider.of<ProfileInfoState>(context, listen: false).onion;
final setPeerAttribute = {
"EventType": "AddContact",
"Data": {"ImportString": Provider.of<MessageState>(context, listen: false).message},
};
final setPeerAttributeJson = jsonEncode(setPeerAttribute);
Provider.of<FlwtchState>(context, listen: false).cwtch.SendProfileEvent(profileOnion, setPeerAttributeJson);
} else {
Provider.of<FlwtchState>(context, listen: false).cwtch.ImportBundle(profileOnion, Provider.of<MessageState>(context, listen: false).message); Provider.of<FlwtchState>(context, listen: false).cwtch.ImportBundle(profileOnion, Provider.of<MessageState>(context, listen: false).message);
} isAccepted = true;
});
} }
// Construct an invite chrome for the sender // Construct an invite chrome for the sender

View File

@ -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. # In iOS, build-name is used as CFBundleShortVersionString while build-number used as CFBundleVersion.
# Read more about iOS versioning at # Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
version: 1.0.0+10 version: 1.0.0+11
environment: environment:
sdk: ">=2.12.0 <3.0.0" sdk: ">=2.12.0 <3.0.0"