full gomobile cwtch compatibility
This commit is contained in:
parent
28a9ffa17f
commit
215e77fe63
|
@ -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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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});
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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(),
|
||||
));
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -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),
|
||||
));
|
||||
},
|
||||
),
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
|
Loading…
Reference in New Issue