full gomobile cwtch compatibility

This commit is contained in:
Dan Ballard 2021-01-14 15:36:09 -08:00
parent 28a9ffa17f
commit 215e77fe63
13 changed files with 154 additions and 53 deletions

View File

@ -52,7 +52,35 @@ class MainActivity: FlutterActivity() {
Log.i("MainActivity.kt", " appDir: '" + appDir + "' torPath: '" + torPath + "'")
Cwtch.startCwtch(appDir, torPath)
}
"SelectProfile" -> {
val onion = (call.argument("profile") as? String) ?: "";
Cwtch.selectProfile(onion)
}
"GetProfiles" -> result.success(Cwtch.getProfiles())
"ACNEvents" -> result.success(Cwtch.acnEvents())
"ContactEvents" -> result.success(Cwtch.contactEvents())
"GetContacts" -> {
val onion = (call.argument("profile") as? String) ?: "";
result.success(Cwtch.getContacts(onion))
}
"NumMessages" -> {
val profile = (call.argument("profile") as? String) ?: "";
val handle = (call.argument("contact") as? String) ?: "";
result.success(Cwtch.numMessages(profile, handle))
}
"GetMessage" -> {
val profile = (call.argument("profile") as? String) ?: "";
val handle = (call.argument("contact") as? String) ?: "";
val index = (call.argument("index") as? Long) ?: 0;
result.success(Cwtch.getMessage(profile, handle, index))
}
"GetMessages" -> {
val profile = (call.argument("profile") as? String) ?: "";
val handle = (call.argument("contact") as? String) ?: "";
val start = (call.argument("start") as? Long) ?: 0;
val end = (call.argument("end") as? Long) ?: 0;
result.success(Cwtch.getMessages(profile, handle, start, end))
}
else -> result.notImplemented()
}
}

Binary file not shown.

View File

@ -3,12 +3,13 @@ abstract class Cwtch {
void SelectProfile(String onion);
String ACNEvents();
String ContactEvents();
Future<String> ACNEvents();
Future<String> ContactEvents();
Future<String> GetProfiles();
String GetContacts(String onion);
Future<String> GetContacts(String onion);
int NumMessages(String profile, String handle);
String GetMessage(String profile, String handle, int index);
Future<int> NumMessages(String profile, String handle);
Future<String> GetMessage(String profile, String handle, int index);
Future<String> GetMessages(String profile, String handle, int start, int end);
}

View File

@ -29,6 +29,10 @@ typedef GetIntFromStrStrFn = int Function(Pointer<Utf8>, int, Pointer<Utf8>, int
typedef get_json_blob_from_str_str_int_function = Pointer<Utf8> Function(Pointer<Utf8>, Int32, Pointer<Utf8>, Int32, Int32);
typedef GetJsonBlobFromStrStrIntFn = Pointer<Utf8> Function(Pointer<Utf8>, int, Pointer<Utf8>, int, int);
//func GetMessages(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int, start C.int, end C.int) *C.char {
typedef get_json_blob_from_str_str_int_int_function = Pointer<Utf8> Function(Pointer<Utf8>, Int32, Pointer<Utf8>, Int32, Int32, Int32);
typedef GetJsonBlobFromStrStrIntIntFn = Pointer<Utf8> Function(Pointer<Utf8>, int, Pointer<Utf8>, int, int, int);
typedef acn_events_function = Pointer<Utf8> Function();
typedef ACNEventsFn = Pointer<Utf8> Function();
@ -39,7 +43,7 @@ class CwtchFfi implements Cwtch {
library = DynamicLibrary.open("libCwtch.so");
}
Future<void> Start() {
Future<void> Start() async {
String home = "";
Map<String, String> envVars = Platform.environment;
if (Platform.isLinux) {
@ -56,7 +60,7 @@ class CwtchFfi implements Cwtch {
StartCwtch(Utf8.toUtf8(cwtchDir), cwtchDir.length, Utf8.toUtf8(""), 0);
}
void SelectProfile(String onion) {
void SelectProfile(String onion) async {
var selectProfileC = library.lookup<NativeFunction<get_json_blob_string_function>>("c_SelectProfile");
// ignore: non_constant_identifier_names
final SelectProfile = selectProfileC.asFunction<GetJsonBlobStringFn>();
@ -64,7 +68,7 @@ class CwtchFfi implements Cwtch {
SelectProfile(Utf8.toUtf8(onion), onion.length);
}
String ACNEvents() {
Future<String> ACNEvents() async {
var acnEventsC = library.lookup<NativeFunction<acn_events_function>>(
"c_ACNEvents");
// ignore: non_constant_identifier_names
@ -76,7 +80,7 @@ class CwtchFfi implements Cwtch {
}
String ContactEvents() {
Future<String> ContactEvents() async {
var acnEventsC = library.lookup<NativeFunction<acn_events_function>>(
"c_ContactEvents");
// ignore: non_constant_identifier_names
@ -97,7 +101,7 @@ class CwtchFfi implements Cwtch {
return jsonProfiles;
}
String GetContacts(String onion) {
Future<String> GetContacts(String onion) async {
var getContactsC = library.lookup<NativeFunction<get_json_blob_string_function>>("c_GetContacts");
// ignore: non_constant_identifier_names
final GetContacts = getContactsC.asFunction<GetJsonBlobStringFn>();
@ -106,7 +110,7 @@ class CwtchFfi implements Cwtch {
return jsonContacts;
}
int NumMessages(String profile, String handle) {
Future<int> NumMessages(String profile, String handle) async {
var numMessagesC = library.lookup<NativeFunction<get_int_from_str_str_function>>("c_NumMessages");
// ignore: non_constant_identifier_names
final NumMessages = numMessagesC.asFunction<GetIntFromStrStrFn>();
@ -115,7 +119,7 @@ class CwtchFfi implements Cwtch {
return num;
}
String GetMessage(String profile, String handle, int index) {
Future<String> GetMessage(String profile, String handle, int index) async {
var getMessageC = library.lookup<NativeFunction<get_json_blob_from_str_str_int_function>>("c_GetMessage");
// ignore: non_constant_identifier_names
final GetMessage = getMessageC.asFunction<GetJsonBlobFromStrStrIntFn>();
@ -124,4 +128,14 @@ class CwtchFfi implements Cwtch {
String jsonMessage = Utf8.fromUtf8(jsonMessageBytes);
return jsonMessage;
}
Future<String> GetMessages(String profile, String handle, int start, int end) async {
var getMessagesC = library.lookup<NativeFunction<get_json_blob_from_str_str_int_int_function>>("c_GetMessages");
// ignore: non_constant_identifier_names
final GetMessages = getMessagesC.asFunction<GetJsonBlobFromStrStrIntIntFn>();
Pointer<Utf8> jsonMessagesBytes = GetMessages(Utf8.toUtf8(profile), profile.length, Utf8.toUtf8(handle), handle.length, start, end);
String jsonMessages = Utf8.fromUtf8(jsonMessagesBytes);
return jsonMessages;
}
}

View File

@ -8,6 +8,8 @@ import 'package:path/path.dart' as path;
import 'cwtch.dart';
/*
TODO: make a reusable plugin for other flutter apps
import 'package:federated_plugin_platform_interface/federated_plugin_platform_interface.dart';
/// It uses [FederatedPluginInterface]
@ -38,14 +40,15 @@ class CwtchGomobile implements Cwtch {
}
void SelectProfile(String onion) {
cwtchPlatform.invokeMethod("SelectProfile", {"profile" : onion});
}
String ACNEvents() {
return "{}";
Future<String> ACNEvents() {
return cwtchPlatform.invokeMethod("ACNEvents");
}
String ContactEvents() {
return "{}";
Future<String> ContactEvents() {
return cwtchPlatform.invokeMethod("ContactEvents");
}
Future<String> GetProfiles() {
@ -53,16 +56,20 @@ class CwtchGomobile implements Cwtch {
return cwtchPlatform.invokeMethod("GetProfiles");
}
String GetContacts(String onion) {
return "{}";
Future<String> GetContacts(String onion) {
return cwtchPlatform.invokeMethod("GetContacts", {"profile" : onion});
}
int NumMessages(String profile, String handle) {
return 0;
Future<int> NumMessages(String profile, String handle) {
return cwtchPlatform.invokeMethod("NumMessages", {"profile" : profile, "contact": handle});
}
String GetMessage(String profile, String handle, int index) {
return "{}";
Future<String> GetMessage(String profile, String handle, int index) {
return cwtchPlatform.invokeMethod("GetMessage", {"profile" : profile, "contact": handle, "index": index});
}
Future<String> GetMessages(String profile, String handle, int start, int end) {
return cwtchPlatform.invokeMethod("GetMessage", {"profile" : profile, "contact": handle, "start": start, "end": end});
}

View File

@ -101,7 +101,7 @@ class FlwtchState extends State<Flwtch> {
canvasColor: Color(0xFFB09CBC),
accentColor: Color(0xFFD01972),
),
home: cwtchInit == true ? ProfileMgrView() : SplashView(),
home: cwtchInit == true ? ProfileMgrView(cwtch) : SplashView(),
));
}
}

View File

@ -26,6 +26,12 @@ class ContactModel {
ContactModel({this.onion, this.nickname, this.status});
}
class MessageModel {
String Timestamp;
bool Acknowledged;
String Message;
}
/////////////
/// ACN ///
/////////////
@ -38,7 +44,7 @@ class AppModel {
Stream<String> contactEvents() async* {
while (true) {
String event = cwtch.ContactEvents();
String event = await cwtch.ContactEvents();
if (event != "") {
print(event);
yield event;
@ -50,7 +56,7 @@ class AppModel {
Stream<String> torStatus() async* {
while (true) {
String event = cwtch.ACNEvents();
String event = await cwtch.ACNEvents();
if (event != "") {
yield event;
} else {

View File

@ -4,21 +4,40 @@ import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/cwtch/cwtch.dart';
import 'package:provider/provider.dart';
import '../main.dart';
import 'messageview.dart';
import '../model.dart';
class ContactsView extends StatefulWidget {
const ContactsView({Key key, this.flwtch, this.profileOnion}) : super(key: key);
final GlobalKey<FlwtchState> flwtch;
const ContactsView({Key key, this.cwtch, this.profileOnion}) : super(key: key);
final Cwtch cwtch;
final String profileOnion;
@override
_ContactsViewState createState() => _ContactsViewState();
_ContactsViewState createState() => _ContactsViewState(cwtch);
}
class _ContactsViewState extends State<ContactsView> {
final Cwtch cwtch;
Map<String, ContactModel> _contacts = new HashMap<String, ContactModel>();
_ContactsViewState(this.cwtch);
@override
initState() {
cwtch.GetContacts(widget.profileOnion).then((jsonContacts) {
print("got contact: $jsonContacts");
setState(() {
List<dynamic> contacts = jsonDecode(jsonContacts);
contacts.forEach((onion) {
_contacts.putIfAbsent(onion['onion'], () => ContactModel(onion: onion['onion'], nickname: onion['name'], status: onion['status']));
});
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
@ -34,16 +53,6 @@ class _ContactsViewState extends State<ContactsView> {
return StreamBuilder<String>(
stream: Provider.of<FlwtchState>(context).appStatus.contactEvents(),
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
String jsonContacts = Provider.of<FlwtchState>(context).cwtch.GetContacts(widget.profileOnion);
print(jsonContacts);
List<dynamic> contacts = jsonDecode(jsonContacts);
Map<String, ContactModel> _contacts = new HashMap<String, ContactModel>();
contacts.forEach((onion) {
_contacts.putIfAbsent(onion['onion'], () => ContactModel(onion: onion['onion'], nickname: onion['name'], status: onion['status']));
});
// Map<String, ContactModel> _contacts = _profiles[currentlySelectedProfile].contacts;
final tiles = _contacts.values.map(
(ContactModel contact) {
return ListTile(
@ -81,7 +90,7 @@ class _ContactsViewState extends State<ContactsView> {
appBar: AppBar(
title: Text('Convo: ' + widget.profileOnion),
),
body: MessageView(profileOnion: widget.profileOnion, conversationHandle: handle),
body: MessageView(profileOnion: widget.profileOnion, conversationHandle: handle, cwtch: cwtch),
));
},
),

View File

@ -4,24 +4,36 @@ import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/cwtch/cwtch.dart';
import 'package:provider/provider.dart';
import '../main.dart';
import '../model.dart';
class MessageView extends StatefulWidget {
const MessageView({Key key, this.flwtch, this.profileOnion, this.conversationHandle}) : super(key: key);
const MessageView({Key key, this.flwtch, this.profileOnion, this.conversationHandle, this.cwtch}) : super(key: key);
final GlobalKey<FlwtchState> flwtch;
final String profileOnion;
final String conversationHandle;
final Cwtch cwtch;
@override
_MessageViewState createState() => _MessageViewState();
_MessageViewState createState() => _MessageViewState(cwtch);
}
class _MessageViewState extends State<MessageView> {
_MessageViewState(this.cwtch);
final Cwtch cwtch;
int conversationNumMessages = 0;
Timer timer;
List<MessageModel> messages;
@override
initState() {
messages = [];
}
@override
Widget build(BuildContext context) {
@ -42,15 +54,10 @@ class _MessageViewState extends State<MessageView> {
child: ListView.builder(
itemCount: conversationNumMessages,
itemBuilder: (context, index) {
String jsonMessage = Provider.of<FlwtchState>(context).cwtch.GetMessage(widget.profileOnion, widget.conversationHandle, index);
//print(jsonMessage);
dynamic messageWrapper = jsonDecode(jsonMessage);
dynamic message = jsonDecode(messageWrapper['Message']);
return ListTile(
title: Text(message['d']),
title: Text(messages[index].Message),
subtitle: Row(
children: [Text(messageWrapper['Timestamp']), messageWrapper['Acknowledged'] ? Icon(Icons.check_circle_outline) : Icon(Icons.hourglass_bottom_outlined)],
children: [Text(messages[index].Timestamp), messages[index].Acknowledged ? Icon(Icons.check_circle_outline) : Icon(Icons.hourglass_bottom_outlined)],
));
},
));
@ -61,8 +68,29 @@ class _MessageViewState extends State<MessageView> {
if (timer != null && timer.isActive) timer.cancel();
return;
}
setState(() {
conversationNumMessages = Provider.of<FlwtchState>(context).cwtch.NumMessages(widget.profileOnion, widget.conversationHandle);
cwtch.NumMessages(widget.profileOnion, widget.conversationHandle).then((numMessages) {
// don't update/setState -> force redraw if no need to
if (conversationNumMessages != numMessages) {
setState(() {
conversationNumMessages = numMessages;
});
cwtch.GetMessages(widget.profileOnion, widget.conversationHandle, 0, numMessages-1).then((messagesJson) {
List<dynamic> messages = jsonDecode(messagesJson);
List<MessageModel> newMessages = [];
messages.forEach((messageWrapper) {
dynamic message = jsonDecode(messageWrapper['Message']);
MessageModel messageModel = new MessageModel();
messageModel.Acknowledged = messageWrapper['Acknowledged'];
messageModel.Timestamp = messageWrapper['Timestamp'];
messageModel.Message = message['d'];
newMessages.add(messageModel);
});
setState(() {
messages = newMessages;
});
});
}
});
}
}

View File

@ -2,6 +2,7 @@ import 'dart:convert';
import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/cwtch/cwtch.dart';
import 'package:provider/provider.dart';
import '../main.dart';
import '../model.dart';
@ -10,15 +11,22 @@ import 'dart:collection';
import 'contactsview.dart';
class ProfileMgrView extends StatefulWidget {
final Cwtch cwtch;
ProfileMgrView(this.cwtch);
@override
_ProfileMgrViewState createState() => _ProfileMgrViewState();
_ProfileMgrViewState createState() => _ProfileMgrViewState(cwtch);
}
class _ProfileMgrViewState extends State<ProfileMgrView> {
final Cwtch cwtch;
_ProfileMgrViewState(this.cwtch);
@override
Widget build(BuildContext context) {
print("ProfileMgrViewState.build()");
//HashMap<String, ProfileModel> _profiles = Provider.of<FlwtchState>(context).profiles;
return Scaffold (
appBar: AppBar(
@ -37,7 +45,7 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
builder: (BuildContext context) {
return Provider(
create: (_) => Provider.of<FlwtchState>(context),
child: ContactsView(profileOnion: profile),
child: ContactsView(profileOnion: profile, cwtch: cwtch),
);
},
),