Merge branch 'trunk' of git.openprivacy.ca:flutter/flutter_app into msgcounter

This commit is contained in:
erinn 2021-03-17 15:56:59 -07:00
commit 1bf033595e
16 changed files with 216 additions and 69 deletions

View File

@ -102,10 +102,6 @@ class MainActivity: FlutterActivity() {
"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) ?: "";

View File

@ -11,7 +11,6 @@ abstract class Cwtch {
Future<String> ContactEvents();
Future<String> GetProfiles();
Future<String> GetContacts(String onion);
Future<int> NumMessages(String profile, String handle);
Future<String> GetMessage(String profile, String handle, int index);

View File

@ -41,12 +41,8 @@ class CwtchNotifier {
if (contact == null) {
//todo: stopgap, as lc-g is supposed to handle this
print("PSC -> adding " + data["ProfileOnion"] + " :: " + data["RemotePeer"]);
profileCN.getProfile(data["ProfileOnion"]).contactList.add(ContactInfoState(
profileOnion: data["ProfileOnion"],
onion: data["RemotePeer"],
nickname: data["nick"],
status: data["ConnectionState"],
));
profileCN.getProfile(data["ProfileOnion"]).contactList.add(
ContactInfoState(profileOnion: data["ProfileOnion"], onion: data["RemotePeer"], nickname: data["name"], status: data["ConnectionState"], isBlocked: data["authorization"] == "blocked"));
} else {
contact.status = data["ConnectionState"];
}

View File

@ -175,16 +175,6 @@ class CwtchFfi implements Cwtch {
return jsonProfiles;
}
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>();
final utf8onion = onion.toNativeUtf8();
Pointer<Utf8> jsonContactBytes = GetContacts(utf8onion, utf8onion.length);
String jsonContacts = jsonContactBytes.toDartString();
return jsonContacts;
}
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

View File

@ -82,10 +82,6 @@ class CwtchGomobile implements Cwtch {
return cwtchPlatform.invokeMethod("GetProfiles");
}
Future<String> GetContacts(String onion) {
return cwtchPlatform.invokeMethod("GetContacts", {"profile": onion});
}
Future<int> NumMessages(String profile, String handle) {
return cwtchPlatform.invokeMethod("NumMessages", {"profile": profile, "contact": handle});
}

View File

@ -17,6 +17,7 @@
"builddate": "Aufgebaut auf: %2",
"bulletinsBtn": "Meldungen",
"chatBtn": "Chat",
"conversationSettings": "",
"copiedClipboardNotification": "in die Zwischenablage kopiert",
"copiedToClipboardNotification": "in die Zwischenablage kopiert",
"copyBtn": "Kopieren",

View File

@ -17,6 +17,7 @@
"builddate": "Built on: %2",
"bulletinsBtn": "Bulletins",
"chatBtn": "Chat",
"conversationSettings": "Conversation Settings",
"copiedClipboardNotification": "Copied to clipboard",
"copiedToClipboardNotification": "Copied to Clipboard",
"copyBtn": "Copy",
@ -28,12 +29,12 @@
"createProfileBtn": "Create Profile",
"currentPasswordLabel": "Current Password",
"cwtchSettingsTitle": "Cwtch Settings",
"cycleCatsAndroid": "Click to cycle category.\nLong-press to reset.",
"cycleCatsDesktop": "Click to cycle category.\nRight-click to reset.",
"cycleColoursAndroid": "Click to cycle colours.\nLong-press to reset.",
"cycleColoursDesktop": "Click to cycle colours.\nRight-click to reset.",
"cycleMorphsAndroid": "Click to cycle morphs.\nLong-press to reset.",
"cycleMorphsDesktop": "Click to cycle morphs.\nRight-click to reset.",
"cycleCatsAndroid": "Click to cycle category.\\nLong-press to reset.",
"cycleCatsDesktop": "Click to cycle category.\\nRight-click to reset.",
"cycleColoursAndroid": "Click to cycle colours.\\nLong-press to reset.",
"cycleColoursDesktop": "Click to cycle colours.\\nRight-click to reset.",
"cycleMorphsAndroid": "Click to cycle morphs.\\nLong-press to reset.",
"cycleMorphsDesktop": "Click to cycle morphs.\\nRight-click to reset.",
"defaultGroupName": "Awesome Group",
"defaultProfileName": "Alice",
"defaultScalingText": "Default size text (scale factor:",

View File

@ -17,6 +17,7 @@
"builddate": "Basado en: %2",
"bulletinsBtn": "Boletines",
"chatBtn": "Chat",
"conversationSettings": "",
"copiedClipboardNotification": "Copiado al portapapeles",
"copiedToClipboardNotification": "Copiado al portapapeles",
"copyBtn": "Copiar",

View File

@ -17,6 +17,7 @@
"builddate": "",
"bulletinsBtn": "Bulletins",
"chatBtn": "Discuter",
"conversationSettings": "",
"copiedClipboardNotification": "Copié dans le presse-papier",
"copiedToClipboardNotification": "Copié dans le presse-papier",
"copyBtn": "Copier",

View File

@ -17,6 +17,7 @@
"builddate": "Costruito il: %2",
"bulletinsBtn": "Bollettini",
"chatBtn": "Chat",
"conversationSettings": "",
"copiedClipboardNotification": "Copiato negli Appunti",
"copiedToClipboardNotification": "Copiato negli Appunti",
"copyBtn": "Copia",
@ -28,12 +29,12 @@
"createProfileBtn": "Crea un profilo",
"currentPasswordLabel": "Password corrente",
"cwtchSettingsTitle": "Impostazioni di Cwtch",
"cycleCatsAndroid": "Fare clic per scorrere le categorie.\nPressione lunga per resettare.",
"cycleCatsDesktop": "Fare clic per scorrere le categorie.\nCliccare con il tasto destro per resettare.",
"cycleColoursAndroid": "Fare clic per scorrere i colori.\nPressione lunga per resettare.",
"cycleColoursDesktop": "Fare clic per scorrere i colori.\nCliccare con il tasto destro per resettare.",
"cycleMorphsAndroid": "Fare clic per scorrere i morph.\nPressione lunga per resettare.",
"cycleMorphsDesktop": "Fare clic per scorrere i morph.\nCliccare con il tasto destro per resettare.",
"cycleCatsAndroid": "Fare clic per scorrere le categorie.\\nPressione lunga per resettare.",
"cycleCatsDesktop": "Fare clic per scorrere le categorie.\\nCliccare con il tasto destro per resettare.",
"cycleColoursAndroid": "Fare clic per scorrere i colori.\\nPressione lunga per resettare.",
"cycleColoursDesktop": "Fare clic per scorrere i colori.\\nCliccare con il tasto destro per resettare.",
"cycleMorphsAndroid": "Fare clic per scorrere i morph.\\nPressione lunga per resettare.",
"cycleMorphsDesktop": "Fare clic per scorrere i morph.\\nCliccare con il tasto destro per resettare.",
"defaultGroupName": "Gruppo fantastico",
"defaultProfileName": "Alice",
"defaultScalingText": "Testo di dimensioni predefinite (fattore di scala:",

View File

@ -17,6 +17,7 @@
"builddate": "",
"bulletinsBtn": "Boletins",
"chatBtn": "Chat",
"conversationSettings": "",
"copiedClipboardNotification": "Copiado",
"copiedToClipboardNotification": "Copiado",
"copyBtn": "Copiar",

View File

@ -139,14 +139,15 @@ class ProfileInfoState extends ChangeNotifier {
List<dynamic> contacts = jsonDecode(contactsJson);
this._contacts.addAll(contacts.map((contact) {
return ContactInfoState(
profileOnion: this.onion,
onion: contact["onion"],
nickname: contact["name"],
status: contact["status"],
imagePath: contact["picture"],
numMessages: contact["numMessages"],
numUnread: contact["numUnread"],
);
profileOnion: this.onion,
onion: contact["onion"],
nickname: contact["name"],
status: contact["status"],
imagePath: contact["picture"],
isBlocked: contact["authorization"] == "blocked",
savePeerHistory: contact["saveConversationHistory"],
numMessages: contact["numMessages"],
numUnread: contact["numUnread"]);
}));
}
}
@ -187,21 +188,11 @@ class ContactInfoState extends ChangeNotifier {
bool _isBlocked;
String _status;
String _imagePath;
int _totalMessages = 0;
String _savePeerHistory;
int _unreadMessages = 0;
int _totalMessages = 0;
ContactInfoState({
this.profileOnion,
this.onion,
nickname = "",
isGroup = false,
isInvitation = false,
isBlocked = false,
status = "",
imagePath = "",
numMessages = 0,
numUnread = 0,
}) {
ContactInfoState({this.profileOnion, this.onion, nickname = "", isGroup = false, isInvitation = false, isBlocked = false, status = "", imagePath = "", savePeerHistory = "DeleteHistoryConfirmed", numMessages = 0, numUnread = 0,}) {
this._nickname = nickname;
this._isGroup = isGroup;
this._isInvitation = isInvitation;
@ -210,14 +201,28 @@ class ContactInfoState extends ChangeNotifier {
this._imagePath = imagePath;
this._totalMessages = numMessages;
this._unreadMessages = numUnread;
this._savePeerHistory = savePeerHistory;
}
get nickname => this._nickname;
get savePeerHistory => this._savePeerHistory;
set savePeerHistory(String newVal) {
this._savePeerHistory = newVal;
notifyListeners();
}
set nickname(String newVal) {
this._nickname = newVal;
notifyListeners();
}
get isBlocked => this._isBlocked;
set isBlocked(bool newVal) {
this._isBlocked = newVal;
notifyListeners();
}
get isInvitation => this._isInvitation;
set isInvitation(bool newVal) {
this._isInvitation = newVal;

View File

@ -36,14 +36,14 @@ class _AddEditProfileViewState extends State<AddEditProfileView> {
void initState() {
super.initState();
usePassword = true;
final nickname = Provider.of<ProfileInfoState>(context, listen: false).nickname;
if (nickname.isNotEmpty) {
ctrlrNick.text = nickname;
}
}
@override
Widget build(BuildContext context) {
final nickname = Provider.of<ProfileInfoState>(context).nickname;
if (nickname.isNotEmpty) {
ctrlrNick.text = nickname;
}
ctrlrOnion.text = Provider.of<ProfileInfoState>(context).onion;
return Scaffold(
appBar: AppBar(

View File

@ -1,6 +1,9 @@
import 'dart:convert';
import 'dart:io';
import 'package:flutter/services.dart';
import 'package:flutter_app/model.dart';
import 'package:flutter_app/widgets/buttontextfield.dart';
import 'package:flutter_app/widgets/cwtchlabel.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:flutter/material.dart';
import 'package:flutter_app/opaque.dart';
@ -22,6 +25,17 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
super.dispose();
}
final ctrlrNick = TextEditingController(text: "");
@override
void initState() {
super.initState();
final nickname = Provider.of<ContactInfoState>(context, listen: false).nickname;
if (nickname.isNotEmpty) {
ctrlrNick.text = nickname;
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
@ -43,8 +57,144 @@ class _PeerSettingsViewState extends State<PeerSettingsView> {
constraints: BoxConstraints(
minHeight: viewportConstraints.maxHeight,
),
child: Column(children: []))));
child: Container(
margin: EdgeInsets.all(30),
padding: EdgeInsets.all(20),
child: Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.stretch, children: [
// Address Copy Button
Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [
SizedBox(
height: 20,
),
CwtchLabel(label: AppLocalizations.of(context).addressLabel),
SizedBox(
height: 20,
),
CwtchButtonTextField(
controller: TextEditingController(text: Provider.of<ContactInfoState>(context, listen: false).onion),
onPressed: _copyOnion,
icon: Icon(Icons.copy),
tooltip: AppLocalizations.of(context).copyBtn,
)
]),
// Nickname Save Button
Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [
SizedBox(
height: 20,
),
CwtchLabel(label: AppLocalizations.of(context).displayNameLabel),
SizedBox(
height: 20,
),
CwtchButtonTextField(
controller: ctrlrNick,
readonly: false,
onPressed: () {
var profileOnion = Provider.of<ContactInfoState>(context, listen: false).profileOnion;
var onion = Provider.of<ContactInfoState>(context, listen: false).onion;
Provider.of<ContactInfoState>(context, listen: false).nickname = ctrlrNick.text;
final setPeerAttribute = {
"EventType": "SetPeerAttribute",
"Data": {"RemotePeer": onion, "Key": "local.name", "Data": ctrlrNick.text},
};
final setPeerAttributeJson = jsonEncode(setPeerAttribute);
Provider.of<FlwtchState>(context, listen: false).cwtch.SendProfileEvent(profileOnion, setPeerAttributeJson);
},
icon: Icon(Icons.save),
tooltip: AppLocalizations.of(context).saveBtn,
)
]),
Column(mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [
SizedBox(
height: 20,
),
CwtchLabel(label: AppLocalizations.of(context).conversationSettings),
SizedBox(
height: 20,
),
SwitchListTile(
title: Text(AppLocalizations.of(context).blockBtn, style: TextStyle(color: settings.current().mainTextColor())),
value: Provider.of<ContactInfoState>(context).isBlocked,
onChanged: (bool blocked) {
// Save local blocked status
Provider.of<ContactInfoState>(context, listen: false).isBlocked = blocked;
// Save New peer authorization
var profileOnion = Provider.of<ContactInfoState>(context, listen: false).profileOnion;
var onion = Provider.of<ContactInfoState>(context, listen: false).onion;
Provider.of<ContactInfoState>(context, listen: false).nickname = ctrlrNick.text;
if (blocked) {
final setPeerAttribute = {
"EventType": "UpdatePeerAuthorization",
"Data": {"RemotePeer": onion, "Authorization": "blocked"},
};
final setPeerAttributeJson = jsonEncode(setPeerAttribute);
Provider.of<FlwtchState>(context, listen: false).cwtch.SendProfileEvent(profileOnion, setPeerAttributeJson);
} else {
final setPeerAttribute = {
"EventType": "UpdatePeerAuthorization",
"Data": {"RemotePeer": onion, "Authorization": "authorized"},
};
final setPeerAttributeJson = jsonEncode(setPeerAttribute);
Provider.of<FlwtchState>(context, listen: false).cwtch.SendProfileEvent(profileOnion, setPeerAttributeJson);
}
},
secondary: Icon(Icons.block, color: settings.current().mainTextColor()),
),
ListTile(
title: Text(AppLocalizations.of(context).savePeerHistory, style: TextStyle(color: settings.current().mainTextColor())),
subtitle: Text(AppLocalizations.of(context).savePeerHistoryDescription),
leading: Icon(Icons.history_sharp, color: settings.current().mainTextColor()),
trailing: DropdownButton(
value: Provider.of<ContactInfoState>(context).savePeerHistory == "DefaultDeleteHistory"
? AppLocalizations.of(context).dontSavePeerHistory
: (Provider.of<ContactInfoState>(context).savePeerHistory == "SaveHistory"
? AppLocalizations.of(context).savePeerHistory
: AppLocalizations.of(context).dontSavePeerHistory),
onChanged: (newValue) {
setState(() {
// Set whether or not to dave the Contact History...
var profileOnion = Provider.of<ContactInfoState>(context, listen: false).profileOnion;
var onion = Provider.of<ContactInfoState>(context, listen: false).onion;
const SaveHistoryKey = "SavePeerHistory";
if (newValue == AppLocalizations.of(context).savePeerHistory) {
Provider.of<ContactInfoState>(context, listen: false).savePeerHistory = "SaveHistory";
final setPeerAttribute = {
"EventType": "SetPeerAttribute",
"Data": {"RemotePeer": onion, "Key": SaveHistoryKey, "Data": "SaveHistory"},
};
final setPeerAttributeJson = jsonEncode(setPeerAttribute);
Provider.of<FlwtchState>(context, listen: false).cwtch.SendProfileEvent(profileOnion, setPeerAttributeJson);
} else {
Provider.of<ContactInfoState>(context, listen: false).savePeerHistory = "DeleteHistoryConfirmed";
final setPeerAttribute = {
"EventType": "SetPeerAttribute",
"Data": {"RemotePeer": onion, "Key": SaveHistoryKey, "Data": "DeleteHistoryConfirmed"},
};
final setPeerAttributeJson = jsonEncode(setPeerAttribute);
Provider.of<FlwtchState>(context, listen: false).cwtch.SendProfileEvent(profileOnion, setPeerAttributeJson);
}
});
},
items: [AppLocalizations.of(context).savePeerHistory, AppLocalizations.of(context).dontSavePeerHistory].map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList())),
]),
])))));
});
});
}
void _copyOnion() {
Clipboard.setData(new ClipboardData(text: Provider.of<ContactInfoState>(context, listen: false).onion));
final snackBar = SnackBar(content: Text(AppLocalizations.of(context).copiedClipboardNotification));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
}

View File

@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_app/widgets/profilerow.dart';
@ -29,7 +31,7 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
appBar: AppBar(
title: Text(AppLocalizations.of(context).profileName),
actions: [
IconButton(icon: Icon(Icons.bug_report_outlined), onPressed: _testChangingContactInfo),
IconButton(icon: Icon(Icons.bug_report_outlined), onPressed: _setLoggingLevelDebug),
IconButton(
icon: Icon(Icons.lock_open),
onPressed: _modalUnlockProfiles,
@ -46,8 +48,13 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
);
}
void _testChangingContactInfo() {
Provider.of<ProfileListState>(context, listen: false).profiles.first.nickname = "yay!";
void _setLoggingLevelDebug() {
final setLoggingLevel = {
"EventType": "SetLoggingLevel",
"Data": {"Debug": "true"},
};
final setLoggingLevelJson = jsonEncode(setLoggingLevel);
Provider.of<FlwtchState>(context, listen: false).cwtch.SendAppEvent(setLoggingLevelJson);
}
void _pushGlobalSettings() {

View File

@ -5,11 +5,12 @@ import 'package:provider/provider.dart';
// Provides a styled Text Field for use in Form Widgets.
// Callers must provide a text controller, label helper text and a validator.
class CwtchButtonTextField extends StatefulWidget {
CwtchButtonTextField({this.controller, this.onPressed, this.icon, this.tooltip});
CwtchButtonTextField({this.controller, this.onPressed, this.icon, this.tooltip, this.readonly = true});
final TextEditingController controller;
final Function onPressed;
final Icon icon;
final String tooltip;
final bool readonly;
@override
_CwtchButtonTextFieldState createState() => _CwtchButtonTextFieldState();
@ -19,9 +20,10 @@ class _CwtchButtonTextFieldState extends State<CwtchButtonTextField> {
@override
Widget build(BuildContext context) {
return Consumer<Settings>(builder: (context, theme, child) {
return TextField(
return TextFormField(
controller: widget.controller,
readOnly: true,
readOnly: widget.readonly,
showCursor: !widget.readonly,
decoration: InputDecoration(
suffixIcon: IconButton(
onPressed: widget.onPressed,