diff --git a/android/app/src/main/kotlin/com/example/flutter_app/MainActivity.kt b/android/app/src/main/kotlin/com/example/flutter_app/MainActivity.kt index 3c1cdca..a7c0719 100644 --- a/android/app/src/main/kotlin/com/example/flutter_app/MainActivity.kt +++ b/android/app/src/main/kotlin/com/example/flutter_app/MainActivity.kt @@ -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) ?: ""; diff --git a/lib/cwtch/cwtch.dart b/lib/cwtch/cwtch.dart index 9430bc0..d5ab130 100644 --- a/lib/cwtch/cwtch.dart +++ b/lib/cwtch/cwtch.dart @@ -11,7 +11,6 @@ abstract class Cwtch { Future ContactEvents(); Future GetProfiles(); - Future GetContacts(String onion); Future NumMessages(String profile, String handle); Future GetMessage(String profile, String handle, int index); diff --git a/lib/cwtch/cwtchNotifier.dart b/lib/cwtch/cwtchNotifier.dart index f075b11..9291733 100644 --- a/lib/cwtch/cwtchNotifier.dart +++ b/lib/cwtch/cwtchNotifier.dart @@ -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"]; } diff --git a/lib/cwtch/ffi.dart b/lib/cwtch/ffi.dart index a79a88d..374499f 100644 --- a/lib/cwtch/ffi.dart +++ b/lib/cwtch/ffi.dart @@ -175,16 +175,6 @@ class CwtchFfi implements Cwtch { return jsonProfiles; } - Future GetContacts(String onion) async { - var getContactsC = library.lookup>("c_GetContacts"); - // ignore: non_constant_identifier_names - final GetContacts = getContactsC.asFunction(); - final utf8onion = onion.toNativeUtf8(); - Pointer jsonContactBytes = GetContacts(utf8onion, utf8onion.length); - String jsonContacts = jsonContactBytes.toDartString(); - return jsonContacts; - } - Future NumMessages(String profile, String handle) async { var numMessagesC = library.lookup>("c_NumMessages"); // ignore: non_constant_identifier_names diff --git a/lib/cwtch/gomobile.dart b/lib/cwtch/gomobile.dart index 04a470a..5403a47 100644 --- a/lib/cwtch/gomobile.dart +++ b/lib/cwtch/gomobile.dart @@ -82,10 +82,6 @@ class CwtchGomobile implements Cwtch { return cwtchPlatform.invokeMethod("GetProfiles"); } - Future GetContacts(String onion) { - return cwtchPlatform.invokeMethod("GetContacts", {"profile": onion}); - } - Future NumMessages(String profile, String handle) { return cwtchPlatform.invokeMethod("NumMessages", {"profile": profile, "contact": handle}); } diff --git a/lib/l10n/intl_de.arb b/lib/l10n/intl_de.arb index 340e162..765901d 100644 --- a/lib/l10n/intl_de.arb +++ b/lib/l10n/intl_de.arb @@ -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", diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 15e3f20..9c4d3f3 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -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:", diff --git a/lib/l10n/intl_es.arb b/lib/l10n/intl_es.arb index 661e351..dd9ff31 100644 --- a/lib/l10n/intl_es.arb +++ b/lib/l10n/intl_es.arb @@ -17,6 +17,7 @@ "builddate": "Basado en: %2", "bulletinsBtn": "Boletines", "chatBtn": "Chat", + "conversationSettings": "", "copiedClipboardNotification": "Copiado al portapapeles", "copiedToClipboardNotification": "Copiado al portapapeles", "copyBtn": "Copiar", diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index 56bf040..ad310c1 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -17,6 +17,7 @@ "builddate": "", "bulletinsBtn": "Bulletins", "chatBtn": "Discuter", + "conversationSettings": "", "copiedClipboardNotification": "CopiƩ dans le presse-papier", "copiedToClipboardNotification": "CopiƩ dans le presse-papier", "copyBtn": "Copier", diff --git a/lib/l10n/intl_it.arb b/lib/l10n/intl_it.arb index 6fd0a19..551c391 100644 --- a/lib/l10n/intl_it.arb +++ b/lib/l10n/intl_it.arb @@ -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:", diff --git a/lib/l10n/intl_pt.arb b/lib/l10n/intl_pt.arb index f1ccc09..a83d1ac 100644 --- a/lib/l10n/intl_pt.arb +++ b/lib/l10n/intl_pt.arb @@ -17,6 +17,7 @@ "builddate": "", "bulletinsBtn": "Boletins", "chatBtn": "Chat", + "conversationSettings": "", "copiedClipboardNotification": "Copiado", "copiedToClipboardNotification": "Copiado", "copyBtn": "Copiar", diff --git a/lib/model.dart b/lib/model.dart index df09914..aba5462 100644 --- a/lib/model.dart +++ b/lib/model.dart @@ -139,12 +139,7 @@ class ProfileInfoState extends ChangeNotifier { List 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"], - ); + profileOnion: this.onion, onion: contact["onion"], nickname: contact["name"], status: contact["status"], imagePath: contact["picture"], isBlocked: contact["authorization"] == "blocked"); })); } } @@ -211,6 +206,12 @@ class ContactInfoState extends ChangeNotifier { notifyListeners(); } + get isBlocked => this._isBlocked; + set isBlocked(bool newVal) { + this._isBlocked = newVal; + notifyListeners(); + } + get isInvitation => this._isInvitation; set isInvitation(bool newVal) { this._isInvitation = newVal; diff --git a/lib/views/addeditprofileview.dart b/lib/views/addeditprofileview.dart index a684552..c48d047 100644 --- a/lib/views/addeditprofileview.dart +++ b/lib/views/addeditprofileview.dart @@ -36,14 +36,14 @@ class _AddEditProfileViewState extends State { void initState() { super.initState(); usePassword = true; + final nickname = Provider.of(context, listen: false).nickname; + if (nickname.isNotEmpty) { + ctrlrNick.text = nickname; + } } @override Widget build(BuildContext context) { - final nickname = Provider.of(context).nickname; - if (nickname.isNotEmpty) { - ctrlrNick.text = nickname; - } ctrlrOnion.text = Provider.of(context).onion; return Scaffold( appBar: AppBar( diff --git a/lib/views/peersettingsview.dart b/lib/views/peersettingsview.dart index f875f2d..ec939da 100644 --- a/lib/views/peersettingsview.dart +++ b/lib/views/peersettingsview.dart @@ -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 { super.dispose(); } + final ctrlrNick = TextEditingController(text: ""); + + @override + void initState() { + super.initState(); + final nickname = Provider.of(context, listen: false).nickname; + if (nickname.isNotEmpty) { + ctrlrNick.text = nickname; + } + } + @override Widget build(BuildContext context) { return Scaffold( @@ -43,8 +57,101 @@ class _PeerSettingsViewState extends State { 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(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(context, listen: false).profileOnion; + var onion = Provider.of(context, listen: false).onion; + Provider.of(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(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(context).isBlocked, + onChanged: (bool blocked) { + // Save local blocked status + Provider.of(context, listen: false).isBlocked = blocked; + + // Save New peer authorization + var profileOnion = Provider.of(context, listen: false).profileOnion; + + var onion = Provider.of(context, listen: false).onion; + Provider.of(context, listen: false).nickname = ctrlrNick.text; + + if (blocked) { + final setPeerAttribute = { + "EventType": "UpdatePeerAuthorization", + "Data": {"RemotePeer": onion, "Authorization": "blocked"}, + }; + final setPeerAttributeJson = jsonEncode(setPeerAttribute); + Provider.of(context, listen: false).cwtch.SendProfileEvent(profileOnion, setPeerAttributeJson); + } else { + final setPeerAttribute = { + "EventType": "UpdatePeerAuthorization", + "Data": {"RemotePeer": onion, "Authorization": "authorized"}, + }; + final setPeerAttributeJson = jsonEncode(setPeerAttribute); + Provider.of(context, listen: false).cwtch.SendProfileEvent(profileOnion, setPeerAttributeJson); + } + }, + secondary: Icon(Icons.block, color: settings.current().mainTextColor()), + ), + ]), + ]))))); }); }); } + + void _copyOnion() { + Clipboard.setData(new ClipboardData(text: Provider.of(context, listen: false).onion)); + final snackBar = SnackBar(content: Text(AppLocalizations.of(context).copiedClipboardNotification)); + ScaffoldMessenger.of(context).showSnackBar(snackBar); + } } diff --git a/lib/views/profilemgrview.dart b/lib/views/profilemgrview.dart index eb39270..b584fdb 100644 --- a/lib/views/profilemgrview.dart +++ b/lib/views/profilemgrview.dart @@ -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 { 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 { ); } - void _testChangingContactInfo() { - Provider.of(context, listen: false).profiles.first.nickname = "yay!"; + void _setLoggingLevelDebug() { + final setLoggingLevel = { + "EventType": "SetLoggingLevel", + "Data": {"Debug": "true"}, + }; + final setLoggingLevelJson = jsonEncode(setLoggingLevel); + Provider.of(context, listen: false).cwtch.SendAppEvent(setLoggingLevelJson); } void _pushGlobalSettings() { diff --git a/lib/widgets/buttontextfield.dart b/lib/widgets/buttontextfield.dart index 4b34cfb..3e9a197 100644 --- a/lib/widgets/buttontextfield.dart +++ b/lib/widgets/buttontextfield.dart @@ -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 { @override Widget build(BuildContext context) { return Consumer(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,