From 9789a42e94eec4ead5bcce32e83c5f92d495e3af Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Fri, 29 Oct 2021 16:37:02 -0700 Subject: [PATCH] server manager --- .../kotlin/im/cwtch/flwtch/FlwtchWorker.kt | 10 ++++++- lib/cwtch/cwtch.dart | 6 +++- lib/cwtch/cwtchNotifier.dart | 20 +++++++++++-- lib/cwtch/ffi.dart | 28 ++++++++++++++++--- lib/cwtch/gomobile.dart | 10 +++++-- lib/l10n/intl_de.arb | 5 ++-- lib/l10n/intl_en.arb | 5 ++-- lib/l10n/intl_es.arb | 5 ++-- lib/l10n/intl_fr.arb | 27 +++++++++--------- lib/l10n/intl_it.arb | 13 +++++---- lib/l10n/intl_pl.arb | 5 ++-- lib/l10n/intl_pt.arb | 5 ++-- lib/main.dart | 10 +++++-- lib/model.dart | 8 +++--- .../{servers.dart => profileservers.dart} | 16 +++++------ lib/settings.dart | 1 + lib/views/addcontactview.dart | 8 +++--- lib/views/addeditprofileview.dart | 21 ++++---------- lib/views/contactsview.dart | 7 +++-- lib/views/globalsettingsview.dart | 17 +++++++++++ lib/views/profilemgrview.dart | 25 +++++++++++++++-- lib/widgets/profilerow.dart | 4 +-- 22 files changed, 173 insertions(+), 83 deletions(-) rename lib/models/{servers.dart => profileservers.dart} (52%) diff --git a/android/app/src/main/kotlin/im/cwtch/flwtch/FlwtchWorker.kt b/android/app/src/main/kotlin/im/cwtch/flwtch/FlwtchWorker.kt index 3a7e9bc8..6ee8a912 100644 --- a/android/app/src/main/kotlin/im/cwtch/flwtch/FlwtchWorker.kt +++ b/android/app/src/main/kotlin/im/cwtch/flwtch/FlwtchWorker.kt @@ -314,7 +314,9 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) : } "CreateServer" -> { val password = (a.get("Password") as? String) ?: "" - Cwtch.createServer(password) + val desc = (a.get("Description") as? String) ?: "" + val autostart = (a.get("Autostart") as? Byte) ?: "" + Cwtch.createServer(password, desc, autostart) } "DeleteServer" -> { val serverOnion = (a.get("ServerOnion") as? String) ?: "" @@ -335,6 +337,12 @@ class FlwtchWorker(context: Context, parameters: WorkerParameters) : "ShutdownServers" -> { Cwtch.shutdownServers() } + "SetServerAttribute" -> { + val serverOnion = (a.get("ServerOnion") as? String) ?: "" + val key = (a.get("Key") as? String) ?: "" + val v = (a.get("Val") as? String) ?: "" + Cwtch.setServerAttribute(serverOnion, key, v) + } else -> return Result.failure() } return Result.success() diff --git a/lib/cwtch/cwtch.dart b/lib/cwtch/cwtch.dart index be2c466b..d9763f43 100644 --- a/lib/cwtch/cwtch.dart +++ b/lib/cwtch/cwtch.dart @@ -1,5 +1,7 @@ import 'package:flutter/src/services/text_input.dart'; +const DefaultPassword = "be gay do crime"; + abstract class Cwtch { // ignore: non_constant_identifier_names Future Start(); @@ -71,7 +73,7 @@ abstract class Cwtch { // ignore: non_constant_identifier_names void LoadServers(String password); // ignore: non_constant_identifier_names - void CreateServer(String password); + void CreateServer(String password, String description, bool autostart); // ignore: non_constant_identifier_names void DeleteServer(String serverOnion, String password); // ignore: non_constant_identifier_names @@ -82,6 +84,8 @@ abstract class Cwtch { void ShutdownServer(String serverOnion); // ignore: non_constant_identifier_names void ShutdownServers(); + // ignore: non_constant_identifier_names + void SetServerAttribute(String serverOnion, String key, String val); // ignore: non_constant_identifier_names void Shutdown(); diff --git a/lib/cwtch/cwtchNotifier.dart b/lib/cwtch/cwtchNotifier.dart index 2f952dd0..0ae5d98d 100644 --- a/lib/cwtch/cwtchNotifier.dart +++ b/lib/cwtch/cwtchNotifier.dart @@ -1,5 +1,6 @@ import 'dart:convert'; import 'package:cwtch/models/message.dart'; +import 'package:cwtch/models/profileservers.dart'; import 'package:cwtch/models/servers.dart'; import 'package:cwtch/notification_manager.dart'; import 'package:provider/provider.dart'; @@ -20,17 +21,20 @@ class CwtchNotifier { late TorStatus torStatus; late NotificationsManager notificationManager; late AppState appState; + late ServerListState serverListState; - CwtchNotifier(ProfileListState pcn, Settings settingsCN, ErrorHandler errorCN, TorStatus torStatusCN, NotificationsManager notificationManagerP, AppState appStateCN) { + CwtchNotifier(ProfileListState pcn, Settings settingsCN, ErrorHandler errorCN, TorStatus torStatusCN, NotificationsManager notificationManagerP, AppState appStateCN, ServerListState serverListStateCN) { profileCN = pcn; settings = settingsCN; error = errorCN; torStatus = torStatusCN; notificationManager = notificationManagerP; appState = appStateCN; + serverListState = serverListStateCN; } void handleMessage(String type, dynamic data) { + print("EVENT $type $data"); switch (type) { case "CwtchStarted": appState.SetCwtchInit(); @@ -59,11 +63,21 @@ class CwtchNotifier { lastMessageTime: DateTime.now(), //show at the top of the contact list even if no messages yet )); break; + case "NewServer": + var serverData = jsonDecode(data["Data"]); + serverListState.add( + serverData["onion"], + serverData["serverbundle"], + serverData["enabled"] == "true", + serverData["description"], + serverData["autostart"] == "true", + serverData["storageType"] == "storage-password"); + break; case "GroupCreated": // Retrieve Server Status from Cache... String status = ""; - ServerInfoState? serverInfoState = profileCN.getProfile(data["ProfileOnion"])?.serverList.getServer(data["GroupServer"]); + RemoteServerInfoState? serverInfoState = profileCN.getProfile(data["ProfileOnion"])?.serverList.getServer(data["GroupServer"]); if (serverInfoState != null) { status = serverInfoState.status; } @@ -263,7 +277,7 @@ class CwtchNotifier { // Retrieve Server Status from Cache... String status = ""; - ServerInfoState? serverInfoState = profileCN.getProfile(data["ProfileOnion"])!.serverList.getServer(groupInvite["ServerHost"]); + RemoteServerInfoState? serverInfoState = profileCN.getProfile(data["ProfileOnion"])!.serverList.getServer(groupInvite["ServerHost"]); if (serverInfoState != null) { status = serverInfoState.status; } diff --git a/lib/cwtch/ffi.dart b/lib/cwtch/ffi.dart index 8a76bb2d..e022fe8a 100644 --- a/lib/cwtch/ffi.dart +++ b/lib/cwtch/ffi.dart @@ -42,6 +42,9 @@ typedef VoidFromStringStringStringStringStringFn = void Function(Pointer, typedef void_from_string_string_int_int_function = Void Function(Pointer, Int32, Pointer, Int32, Int64, Int64); typedef VoidFromStringStringIntIntFn = void Function(Pointer, int, Pointer, int, int, int); +typedef void_from_string_string_byte_function = Void Function(Pointer, Int32, Pointer, Int32, Int8); +typedef VoidFromStringStringByteFn = void Function(Pointer, int, Pointer, int, int); + typedef string_to_void_function = Void Function(Pointer str, Int32 length); typedef StringFn = void Function(Pointer dir, int); @@ -575,13 +578,15 @@ class CwtchFfi implements Cwtch { @override // ignore: non_constant_identifier_names - void CreateServer(String password) { - var createServer = library.lookup>("c_CreateServer"); + void CreateServer(String password, String description, bool autostart) { + var createServer = library.lookup>("c_CreateServer"); // ignore: non_constant_identifier_names - final CreateServer = createServer.asFunction(); + final CreateServer = createServer.asFunction(); final u1 = password.toNativeUtf8(); - CreateServer(u1, u1.length); + final u2 = description.toNativeUtf8(); + CreateServer(u1, u1.length, u2, u2.length, autostart ? 1 : 0); malloc.free(u1); + malloc.free(u2); } @override @@ -637,6 +642,21 @@ class CwtchFfi implements Cwtch { ShutdownServers(); } + @override + // ignore: non_constant_identifier_names + void SetServerAttribute(String serverOnion, String key, String val) { + var setServerAttribute = library.lookup>("c_SetServerAttribute"); + // ignore: non_constant_identifier_names + final SetServerAttribute = setServerAttribute.asFunction(); + final u1 = serverOnion.toNativeUtf8(); + final u2 = key.toNativeUtf8(); + final u3 = val.toNativeUtf8(); + SetServerAttribute(u1, u1.length, u2, u2.length, u3, u3.length); + malloc.free(u1); + malloc.free(u2); + malloc.free(u3); + } + @override // ignore: non_constant_identifier_names Future Shutdown() async { diff --git a/lib/cwtch/gomobile.dart b/lib/cwtch/gomobile.dart index ab436570..458defef 100644 --- a/lib/cwtch/gomobile.dart +++ b/lib/cwtch/gomobile.dart @@ -221,8 +221,8 @@ class CwtchGomobile implements Cwtch { @override // ignore: non_constant_identifier_names - void CreateServer(String password) { - cwtchPlatform.invokeMethod("CreateServer", {"Password": password}); + void CreateServer(String password, String description, bool autostart) { + cwtchPlatform.invokeMethod("CreateServer", {"Password": password, "Description": description, "Autostart": autostart ? 1 : 0}); } @override @@ -255,6 +255,12 @@ class CwtchGomobile implements Cwtch { cwtchPlatform.invokeMethod("ShutdownServers", {}); } + @override + // ignore: non_constant_identifier_names + void SetServerAttribute(String serverOnion, String key, String val) { + cwtchPlatform.invokeMethod("SetServerAttribute", {"ServerOnion": serverOnion, "Key": key, "Val": val}); + } + @override Future Shutdown() async { print("gomobile.dart Shutdown"); diff --git a/lib/l10n/intl_de.arb b/lib/l10n/intl_de.arb index e8d93349..bd883204 100644 --- a/lib/l10n/intl_de.arb +++ b/lib/l10n/intl_de.arb @@ -1,6 +1,8 @@ { "@@locale": "de", - "@@last_modified": "2021-09-21T23:09:19+02:00", + "@@last_modified": "2021-10-15T20:45:29+02:00", + "titleManageProfilesShort": "Profiles", + "descriptionStreamerMode": "If turned on, this option makes the app more visually private for streaming or presenting with, for example, hiding profile and contact addresses", "descriptionFileSharing": "The file sharing experiment allows you to send and receive files from Cwtch contacts and groups. Note that sharing a file with a group will result in members of that group connecting with you directly over Cwtch to download it.", "settingFileSharing": "File Sharing", "tooltipSendFile": "Send File", @@ -12,7 +14,6 @@ "downloadFileButton": "Download", "openFolderButton": "Open Folder", "retrievingManifestMessage": "Retrieving file information...", - "descriptionStreamerMode": "If turned on, this option makes the app more visually private for streaming or presenting with, for example, hiding profile and contact onions", "streamerModeLabel": "Streamer\/Presentation Mode", "archiveConversation": "Archive this Conversation", "profileOnionLabel": "Senden Sie diese Adresse an Peers, mit denen Sie sich verbinden möchten", diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index d36736f1..4ff01827 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -1,6 +1,8 @@ { "@@locale": "en", - "@@last_modified": "2021-09-21T23:09:19+02:00", + "@@last_modified": "2021-10-15T20:45:29+02:00", + "titleManageProfilesShort": "Profiles", + "descriptionStreamerMode": "If turned on, this option makes the app more visually private for streaming or presenting with, for example, hiding profile and contact addresses", "descriptionFileSharing": "The file sharing experiment allows you to send and receive files from Cwtch contacts and groups. Note that sharing a file with a group will result in members of that group connecting with you directly over Cwtch to download it.", "settingFileSharing": "File Sharing", "tooltipSendFile": "Send File", @@ -12,7 +14,6 @@ "downloadFileButton": "Download", "openFolderButton": "Open Folder", "retrievingManifestMessage": "Retrieving file information...", - "descriptionStreamerMode": "If turned on, this option makes the app more visually private for streaming or presenting with, for example, hiding profile and contact onions", "streamerModeLabel": "Streamer\/Presentation Mode", "archiveConversation": "Archive this Conversation", "profileOnionLabel": "Send this address to people you want to connect with", diff --git a/lib/l10n/intl_es.arb b/lib/l10n/intl_es.arb index 449a7d18..5b234376 100644 --- a/lib/l10n/intl_es.arb +++ b/lib/l10n/intl_es.arb @@ -1,6 +1,8 @@ { "@@locale": "es", - "@@last_modified": "2021-09-21T23:09:19+02:00", + "@@last_modified": "2021-10-15T20:45:29+02:00", + "titleManageProfilesShort": "Profiles", + "descriptionStreamerMode": "If turned on, this option makes the app more visually private for streaming or presenting with, for example, hiding profile and contact addresses", "descriptionFileSharing": "The file sharing experiment allows you to send and receive files from Cwtch contacts and groups. Note that sharing a file with a group will result in members of that group connecting with you directly over Cwtch to download it.", "settingFileSharing": "File Sharing", "tooltipSendFile": "Send File", @@ -12,7 +14,6 @@ "downloadFileButton": "Download", "openFolderButton": "Open Folder", "retrievingManifestMessage": "Retrieving file information...", - "descriptionStreamerMode": "If turned on, this option makes the app more visually private for streaming or presenting with, for example, hiding profile and contact onions", "streamerModeLabel": "Streamer\/Presentation Mode", "archiveConversation": "Archive this Conversation", "profileOnionLabel": "Envía esta dirección a los contactos con los que quieras conectarte", diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index a6a1ea5d..0add5f25 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -1,18 +1,19 @@ { "@@locale": "fr", - "@@last_modified": "2021-09-21T23:09:19+02:00", - "descriptionFileSharing": "The file sharing experiment allows you to send and receive files from Cwtch contacts and groups. Note that sharing a file with a group will result in members of that group connecting with you directly over Cwtch to download it.", - "settingFileSharing": "File Sharing", - "tooltipSendFile": "Send File", - "messageFileOffered": "Contact is offering to send you a file", - "messageFileSent": "You sent a file", - "messageEnableFileSharing": "Enable the file sharing experiment to view this message.", - "labelFilesize": "Size", - "labelFilename": "Filename", - "downloadFileButton": "Download", - "openFolderButton": "Open Folder", - "retrievingManifestMessage": "Retrieving file information...", - "descriptionStreamerMode": "Si elle est activée, cette option donne un rendu visuel plus privé à l'application pour la diffusion ou la présentation, par exemple en masquant les profils et les contacts.", + "@@last_modified": "2021-10-15T20:45:29+02:00", + "titleManageProfilesShort": "Profiles", + "descriptionStreamerMode": "Si elle est activée, cette option donne un rendu visuel plus privé à l'application pour la diffusion en direct ou la présentation, par exemple, en masquant profil et adresses de contacts.", + "descriptionFileSharing": "L'expérience de partage de fichiers vous permet d'envoyer et de recevoir des fichiers à partir de contacts et de groupes Cwtch. Notez que si vous partagez un fichier avec un groupe, les membres de ce groupe se connecteront avec vous directement via Cwtch pour le télécharger.", + "settingFileSharing": "Partage de fichiers", + "tooltipSendFile": "Envoyer le fichier", + "messageFileOffered": "Contact vous propose de vous envoyer un fichier", + "messageFileSent": "Vous avez envoyé un fichier", + "messageEnableFileSharing": "Activez l'expérience de partage de fichiers pour afficher ce message.", + "labelFilesize": "Taille", + "labelFilename": "Nom de fichier", + "downloadFileButton": "Télécharger", + "openFolderButton": "Ouvrir le dossier", + "retrievingManifestMessage": "Récupération des informations sur le fichier...", "streamerModeLabel": "Mode Streamer\/Présentation", "archiveConversation": "Archiver cette conversation", "profileOnionLabel": "Envoyez cette adresse aux personnes avec lesquelles vous souhaitez entrer en contact.", diff --git a/lib/l10n/intl_it.arb b/lib/l10n/intl_it.arb index 51fe624d..95878777 100644 --- a/lib/l10n/intl_it.arb +++ b/lib/l10n/intl_it.arb @@ -1,10 +1,12 @@ { "@@locale": "it", - "@@last_modified": "2021-09-21T23:09:19+02:00", - "descriptionFileSharing": "The file sharing experiment allows you to send and receive files from Cwtch contacts and groups. Note that sharing a file with a group will result in members of that group connecting with you directly over Cwtch to download it.", - "settingFileSharing": "File Sharing", - "tooltipSendFile": "Send File", - "messageFileOffered": "Contact is offering to send you a file", + "@@last_modified": "2021-10-15T20:45:29+02:00", + "titleManageProfilesShort": "Profiles", + "descriptionStreamerMode": "If turned on, this option makes the app more visually private for streaming or presenting with, for example, hiding profile and contact addresses", + "descriptionFileSharing": "L'esperimento di condivisione dei file ti consente di inviare e ricevere file dai contatti e dai gruppi di Cwtch. Tieni presente che la condivisione di un file con un gruppo farà sì che i membri di quel gruppo si colleghino con te direttamente su Cwtch per scaricarlo.", + "settingFileSharing": "Condivisione file", + "tooltipSendFile": "Invia file", + "messageFileOffered": "Il contatto offre l'invio di un file", "messageFileSent": "You sent a file", "messageEnableFileSharing": "Enable the file sharing experiment to view this message.", "labelFilesize": "Size", @@ -12,7 +14,6 @@ "downloadFileButton": "Download", "openFolderButton": "Open Folder", "retrievingManifestMessage": "Retrieving file information...", - "descriptionStreamerMode": "If turned on, this option makes the app more visually private for streaming or presenting with, for example, hiding profile and contact onions", "streamerModeLabel": "Streamer\/Presentation Mode", "archiveConversation": "Archive this Conversation", "profileOnionLabel": "Inviare questo indirizzo ai peer con cui si desidera connettersi", diff --git a/lib/l10n/intl_pl.arb b/lib/l10n/intl_pl.arb index 84a5523f..84d27a9d 100644 --- a/lib/l10n/intl_pl.arb +++ b/lib/l10n/intl_pl.arb @@ -1,6 +1,8 @@ { "@@locale": "pl", - "@@last_modified": "2021-09-21T23:09:19+02:00", + "@@last_modified": "2021-10-15T20:45:29+02:00", + "titleManageProfilesShort": "Profiles", + "descriptionStreamerMode": "If turned on, this option makes the app more visually private for streaming or presenting with, for example, hiding profile and contact addresses", "descriptionFileSharing": "The file sharing experiment allows you to send and receive files from Cwtch contacts and groups. Note that sharing a file with a group will result in members of that group connecting with you directly over Cwtch to download it.", "settingFileSharing": "File Sharing", "tooltipSendFile": "Send File", @@ -12,7 +14,6 @@ "downloadFileButton": "Download", "openFolderButton": "Open Folder", "retrievingManifestMessage": "Retrieving file information...", - "descriptionStreamerMode": "If turned on, this option makes the app more visually private for streaming or presenting with, for example, hiding profile and contact onions", "streamerModeLabel": "Streamer\/Presentation Mode", "archiveConversation": "Archive this Conversation", "profileOnionLabel": "Send this address to contacts you want to connect with", diff --git a/lib/l10n/intl_pt.arb b/lib/l10n/intl_pt.arb index 3c16f8cc..9e593a6b 100644 --- a/lib/l10n/intl_pt.arb +++ b/lib/l10n/intl_pt.arb @@ -1,6 +1,8 @@ { "@@locale": "pt", - "@@last_modified": "2021-09-21T23:09:19+02:00", + "@@last_modified": "2021-10-15T20:45:29+02:00", + "titleManageProfilesShort": "Profiles", + "descriptionStreamerMode": "If turned on, this option makes the app more visually private for streaming or presenting with, for example, hiding profile and contact addresses", "descriptionFileSharing": "The file sharing experiment allows you to send and receive files from Cwtch contacts and groups. Note that sharing a file with a group will result in members of that group connecting with you directly over Cwtch to download it.", "settingFileSharing": "File Sharing", "tooltipSendFile": "Send File", @@ -12,7 +14,6 @@ "downloadFileButton": "Download", "openFolderButton": "Open Folder", "retrievingManifestMessage": "Retrieving file information...", - "descriptionStreamerMode": "If turned on, this option makes the app more visually private for streaming or presenting with, for example, hiding profile and contact onions", "streamerModeLabel": "Streamer\/Presentation Mode", "archiveConversation": "Archive this Conversation", "profileOnionLabel": "Send this address to contacts you want to connect with", diff --git a/lib/main.dart b/lib/main.dart index c0c56d69..9ab2ad4b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -17,6 +17,7 @@ import 'cwtch/cwtch.dart'; import 'cwtch/cwtchNotifier.dart'; import 'licenses.dart'; import 'model.dart'; +import 'models/servers.dart'; import 'views/profilemgrview.dart'; import 'views/splashView.dart'; import 'dart:io' show Platform, exit; @@ -27,6 +28,7 @@ var globalSettings = Settings(Locale("en", ''), OpaqueDark()); var globalErrorHandler = ErrorHandler(); var globalTorStatus = TorStatus(); var globalAppState = AppState(); +var globalServersList = ServerListState(); void main() { print("Cwtch version: ${EnvironmentConfig.BUILD_VER} built on: ${EnvironmentConfig.BUILD_DATE}"); @@ -62,13 +64,13 @@ class FlwtchState extends State { shutdownMethodChannel.setMethodCallHandler(modalShutdown); print("initState: creating cwtchnotifier, ffi"); if (Platform.isAndroid) { - var cwtchNotifier = new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, NullNotificationsManager(), globalAppState); + var cwtchNotifier = new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, NullNotificationsManager(), globalAppState, globalServersList); cwtch = CwtchGomobile(cwtchNotifier); } else if (Platform.isLinux) { - var cwtchNotifier = new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, newDesktopNotificationsManager(), globalAppState); + var cwtchNotifier = new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, newDesktopNotificationsManager(), globalAppState, globalServersList); cwtch = CwtchFfi(cwtchNotifier); } else { - var cwtchNotifier = new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, NullNotificationsManager(), globalAppState); + var cwtchNotifier = new CwtchNotifier(profs, globalSettings, globalErrorHandler, globalTorStatus, NullNotificationsManager(), globalAppState, globalServersList); cwtch = CwtchFfi(cwtchNotifier); } print("initState: invoking cwtch.Start()"); @@ -82,6 +84,7 @@ class FlwtchState extends State { ChangeNotifierProvider getAppStateProvider() => ChangeNotifierProvider.value(value: globalAppState); Provider getFlwtchStateProvider() => Provider(create: (_) => this); ChangeNotifierProvider getProfileListProvider() => ChangeNotifierProvider(create: (context) => profs); + ChangeNotifierProvider getServerListStateProvider() => ChangeNotifierProvider.value(value: globalServersList); @override Widget build(BuildContext context) { @@ -94,6 +97,7 @@ class FlwtchState extends State { getErrorHandlerProvider(), getTorStatusProvider(), getAppStateProvider(), + getServerListStateProvider(), ], builder: (context, widget) { return Consumer2( diff --git a/lib/model.dart b/lib/model.dart index f036be0f..cb6d2e5d 100644 --- a/lib/model.dart +++ b/lib/model.dart @@ -2,7 +2,7 @@ import 'dart:convert'; import 'package:cwtch/widgets/messagerow.dart'; import 'package:flutter/cupertino.dart'; -import 'package:cwtch/models/servers.dart'; +import 'package:cwtch/models/profileservers.dart'; //////////////////// /// UI State /// @@ -207,7 +207,7 @@ class ContactListState extends ChangeNotifier { class ProfileInfoState extends ChangeNotifier { ContactListState _contacts = ContactListState(); - ServerListState _servers = ServerListState(); + ProfileServerListState _servers = ProfileServerListState(); final String onion; String _nickname = ""; String _imagePath = ""; @@ -267,7 +267,7 @@ class ProfileInfoState extends ChangeNotifier { List servers = jsonDecode(serversJson); this._servers.replace(servers.map((server) { // TODO Keys... - return ServerInfoState(onion: server["onion"], status: server["status"]); + return RemoteServerInfoState(onion: server["onion"], status: server["status"]); })); notifyListeners(); } @@ -316,7 +316,7 @@ class ProfileInfoState extends ChangeNotifier { } ContactListState get contactList => this._contacts; - ServerListState get serverList => this._servers; + ProfileServerListState get serverList => this._servers; @override void dispose() { diff --git a/lib/models/servers.dart b/lib/models/profileservers.dart similarity index 52% rename from lib/models/servers.dart rename to lib/models/profileservers.dart index 6996aed9..cb86d392 100644 --- a/lib/models/servers.dart +++ b/lib/models/profileservers.dart @@ -1,15 +1,15 @@ import 'package:flutter/material.dart'; -class ServerListState extends ChangeNotifier { - List _servers = []; +class ProfileServerListState extends ChangeNotifier { + List _servers = []; - void replace(Iterable newServers) { + void replace(Iterable newServers) { _servers.clear(); _servers.addAll(newServers); notifyListeners(); } - ServerInfoState? getServer(String onion) { + RemoteServerInfoState? getServer(String onion) { int idx = _servers.indexWhere((element) => element.onion == onion); return idx >= 0 ? _servers[idx] : null; } @@ -17,20 +17,20 @@ class ServerListState extends ChangeNotifier { void updateServerCache(String onion, String status) { int idx = _servers.indexWhere((element) => element.onion == onion); if (idx >= 0) { - _servers[idx] = ServerInfoState(onion: onion, status: status); + _servers[idx] = RemoteServerInfoState(onion: onion, status: status); } else { print("Tried to update server cache without a starting state...this is probably an error"); } notifyListeners(); } - List get servers => _servers.sublist(0); //todo: copy?? dont want caller able to bypass changenotifier + List get servers => _servers.sublist(0); //todo: copy?? dont want caller able to bypass changenotifier } -class ServerInfoState extends ChangeNotifier { +class RemoteServerInfoState extends ChangeNotifier { final String onion; final String status; - ServerInfoState({required this.onion, required this.status}); + RemoteServerInfoState({required this.onion, required this.status}); } diff --git a/lib/settings.dart b/lib/settings.dart index c0955489..436e7d88 100644 --- a/lib/settings.dart +++ b/lib/settings.dart @@ -9,6 +9,7 @@ import 'opaque.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; const TapirGroupsExperiment = "tapir-groups-experiment"; +const ServerManagementExperiment = "servers-experiment"; const FileSharingExperiment = "filesharing"; enum DualpaneMode { diff --git a/lib/views/addcontactview.dart b/lib/views/addcontactview.dart index a8a1a422..8485058f 100644 --- a/lib/views/addcontactview.dart +++ b/lib/views/addcontactview.dart @@ -4,7 +4,7 @@ import 'package:cwtch/cwtch_icons_icons.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:cwtch/errorHandler.dart'; -import 'package:cwtch/models/servers.dart'; +import 'package:cwtch/models/profileservers.dart'; import 'package:cwtch/settings.dart'; import 'package:cwtch/widgets/buttontextfield.dart'; import 'package:cwtch/widgets/cwtchlabel.dart'; @@ -197,7 +197,7 @@ class _AddContactViewState extends State { }, isExpanded: true, // magic property value: server, - items: Provider.of(context).serverList.servers.map>((ServerInfoState serverInfo) { + items: Provider.of(context).serverList.servers.map>((RemoteServerInfoState serverInfo) { return DropdownMenuItem( value: serverInfo.onion, child: Text( @@ -240,8 +240,8 @@ class _AddContactViewState extends State { /// TODO Manage Servers Tab Widget manageServersTab() { - final tiles = Provider.of(context).serverList.servers.map((ServerInfoState server) { - return ChangeNotifierProvider.value( + final tiles = Provider.of(context).serverList.servers.map((RemoteServerInfoState server) { + return ChangeNotifierProvider.value( value: server, child: ListTile( title: Text(server.onion), diff --git a/lib/views/addeditprofileview.dart b/lib/views/addeditprofileview.dart index 97ebe133..25e0749b 100644 --- a/lib/views/addeditprofileview.dart +++ b/lib/views/addeditprofileview.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'dart:math'; +import 'package:cwtch/cwtch/cwtch.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:cwtch/model.dart'; @@ -106,6 +107,7 @@ class _AddEditProfileViewState extends State { labelText: AppLocalizations.of(context)!.yourDisplayName, validator: (value) { if (value.isEmpty) { + // TODO l10n ize return "Please enter a display name"; } return null; @@ -287,32 +289,19 @@ class _AddEditProfileViewState extends State { Provider.of(context, listen: false).cwtch.CreateProfile(ctrlrNick.value.text, ctrlrPass.value.text); Navigator.of(context).pop(); } else { - Provider.of(context, listen: false).cwtch.CreateProfile(ctrlrNick.value.text, "be gay do crime"); + Provider.of(context, listen: false).cwtch.CreateProfile(ctrlrNick.value.text, DefaultPassword); Navigator.of(context).pop(); } } else { // Profile Editing if (ctrlrPass.value.text.isEmpty) { // Don't update password, only update name - final event = { - "EventType": "SetAttribute", - "Data": {"Key": "public.name", "Data": ctrlrNick.value.text} - }; - final json = jsonEncode(event); - - Provider.of(context, listen: false).cwtch.SendProfileEvent(Provider.of(context, listen: false).onion, json); + Provider.of(context, listen: false).cwtch.SetProfileAttribute(Provider.of(context, listen: false).onion, "public.name", ctrlrNick.value.text); Navigator.of(context).pop(); } else { // At this points passwords have been validated to be the same and not empty // Update both password and name, even if name hasn't been changed... - final updateNameEvent = { - "EventType": "SetAttribute", - "Data": {"Key": "public.name", "Data": ctrlrNick.value.text} - }; - final updateNameEventJson = jsonEncode(updateNameEvent); - - Provider.of(context, listen: false).cwtch.SendProfileEvent(Provider.of(context, listen: false).onion, updateNameEventJson); - + Provider.of(context, listen: false).cwtch.SetProfileAttribute(Provider.of(context, listen: false).onion, "public.name", ctrlrNick.value.text); final updatePasswordEvent = { "EventType": "ChangePassword", "Data": {"Password": ctrlrOldPass.text, "NewPassword": ctrlrPass.text} diff --git a/lib/views/contactsview.dart b/lib/views/contactsview.dart index f1caeb6d..ae2af434 100644 --- a/lib/views/contactsview.dart +++ b/lib/views/contactsview.dart @@ -103,9 +103,10 @@ class _ContactsViewState extends State { if (Provider.of(context).blockUnknownConnections) { actions.add(Tooltip(message: AppLocalizations.of(context)!.blockUnknownConnectionsEnabledDescription, child: Icon(CwtchIcons.block_unknown))); } - actions.add( - IconButton(icon: TorIcon(), onPressed: _pushTorStatus), - ); + + // TODO copy ID + // TODO servers + actions.add(IconButton( // need both conditions for displaying initial empty textfield and also allowing filters to be cleared if this widget gets lost/reset icon: Icon(showSearchBar || Provider.of(context).isFiltered ? Icons.search_off : Icons.search), diff --git a/lib/views/globalsettingsview.dart b/lib/views/globalsettingsview.dart index 20695220..8b19e27b 100644 --- a/lib/views/globalsettingsview.dart +++ b/lib/views/globalsettingsview.dart @@ -188,6 +188,23 @@ class _GlobalSettingsViewState extends State { inactiveTrackColor: settings.theme.defaultButtonDisabledColor(), secondary: Icon(CwtchIcons.enable_groups, color: settings.current().mainTextColor()), ), + SwitchListTile( + title: Text("Enable Servers", /*AppLocalizations.of(context)!.enableGroups,*/ style: TextStyle(color: settings.current().mainTextColor())), + subtitle: Text("Enable Servers"), //AppLocalizations.of(context)!.descriptionExperimentsGroups), + value: settings.isExperimentEnabled(ServerManagementExperiment), + onChanged: (bool value) { + if (value) { + settings.enableExperiment(ServerManagementExperiment); + } else { + settings.disableExperiment(ServerManagementExperiment); + } + // Save Settings... + saveSettings(context); + }, + activeTrackColor: settings.theme.defaultButtonActiveColor(), + inactiveTrackColor: settings.theme.defaultButtonDisabledColor(), + secondary: Icon(CwtchIcons.dns_24px, color: settings.current().mainTextColor()), + ), SwitchListTile( title: Text(AppLocalizations.of(context)!.settingFileSharing, style: TextStyle(color: settings.current().mainTextColor())), subtitle: Text(AppLocalizations.of(context)!.descriptionFileSharing), diff --git a/lib/views/profilemgrview.dart b/lib/views/profilemgrview.dart index 33f62340..ea896a7d 100644 --- a/lib/views/profilemgrview.dart +++ b/lib/views/profilemgrview.dart @@ -17,6 +17,7 @@ import '../model.dart'; import '../torstatus.dart'; import 'addeditprofileview.dart'; import 'globalsettingsview.dart'; +import 'serversview.dart'; class ProfileMgrView extends StatefulWidget { ProfileMgrView(); @@ -56,12 +57,14 @@ class _ProfileMgrViewState extends State { SizedBox( width: 10, ), - Expanded(child: Text(AppLocalizations.of(context)!.titleManageProfiles, style: TextStyle(color: settings.current().mainTextColor()))) + Expanded(child: Text(MediaQuery.of(context).size.width > 600 ? + AppLocalizations.of(context)!.titleManageProfiles : AppLocalizations.of(context)!.titleManageProfilesShort, + style: TextStyle(color: settings.current().mainTextColor()))) ]), actions: getActions(), ), floatingActionButton: FloatingActionButton( - onPressed: _pushAddEditProfile, + onPressed: _pushAddProfile, tooltip: AppLocalizations.of(context)!.addNewProfileBtn, child: Icon( Icons.add, @@ -95,6 +98,11 @@ class _ProfileMgrViewState extends State { onPressed: _modalUnlockProfiles, )); + // Servers + if (Provider.of(context).isExperimentEnabled(ServerManagementExperiment)) { + actions.add(IconButton(icon: Icon(CwtchIcons.dns_black_24dp), tooltip: "Servers", onPressed: _pushServers)); + } + // Global Settings actions.add(IconButton(icon: Icon(Icons.settings), tooltip: AppLocalizations.of(context)!.tooltipOpenSettings, onPressed: _pushGlobalSettings)); @@ -119,6 +127,17 @@ class _ProfileMgrViewState extends State { )); } + void _pushServers() { + Navigator.of(context).push(MaterialPageRoute( + builder: (BuildContext context) { + return MultiProvider( + providers: [Provider.value(value: Provider.of(context))], + child: ServersView(), + ); + }, + )); + } + void _pushTorStatus() { Navigator.of(context).push(MaterialPageRoute( builder: (BuildContext context) { @@ -130,7 +149,7 @@ class _ProfileMgrViewState extends State { )); } - void _pushAddEditProfile({onion: ""}) { + void _pushAddProfile({onion: ""}) { Navigator.of(context).push(MaterialPageRoute( builder: (BuildContext context) { return MultiProvider( diff --git a/lib/widgets/profilerow.dart b/lib/widgets/profilerow.dart index 9d43997f..d2df0f66 100644 --- a/lib/widgets/profilerow.dart +++ b/lib/widgets/profilerow.dart @@ -61,7 +61,7 @@ class _ProfileRowState extends State { tooltip: AppLocalizations.of(context)!.editProfile + " " + profile.nickname, icon: Icon(Icons.create, color: Provider.of(context).current().mainTextColor()), onPressed: () { - _pushAddEditProfile(onion: profile.onion, displayName: profile.nickname, profileImage: profile.imagePath, encrypted: profile.isEncrypted); + _pushEditProfile(onion: profile.onion, displayName: profile.nickname, profileImage: profile.imagePath, encrypted: profile.isEncrypted); }, ) ], @@ -100,7 +100,7 @@ class _ProfileRowState extends State { ); } - void _pushAddEditProfile({onion: "", displayName: "", profileImage: "", encrypted: true}) { + void _pushEditProfile({onion: "", displayName: "", profileImage: "", encrypted: true}) { Navigator.of(context).push(MaterialPageRoute( builder: (BuildContext context) { return MultiProvider(