server manager

This commit is contained in:
Dan Ballard 2021-10-29 16:37:02 -07:00
parent d4b9f1dc55
commit 9789a42e94
22 changed files with 173 additions and 83 deletions

View File

@ -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()

View File

@ -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<void> 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();

View File

@ -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;
}

View File

@ -42,6 +42,9 @@ typedef VoidFromStringStringStringStringStringFn = void Function(Pointer<Utf8>,
typedef void_from_string_string_int_int_function = Void Function(Pointer<Utf8>, Int32, Pointer<Utf8>, Int32, Int64, Int64);
typedef VoidFromStringStringIntIntFn = void Function(Pointer<Utf8>, int, Pointer<Utf8>, int, int, int);
typedef void_from_string_string_byte_function = Void Function(Pointer<Utf8>, Int32, Pointer<Utf8>, Int32, Int8);
typedef VoidFromStringStringByteFn = void Function(Pointer<Utf8>, int, Pointer<Utf8>, int, int);
typedef string_to_void_function = Void Function(Pointer<Utf8> str, Int32 length);
typedef StringFn = void Function(Pointer<Utf8> dir, int);
@ -575,13 +578,15 @@ class CwtchFfi implements Cwtch {
@override
// ignore: non_constant_identifier_names
void CreateServer(String password) {
var createServer = library.lookup<NativeFunction<string_to_void_function>>("c_CreateServer");
void CreateServer(String password, String description, bool autostart) {
var createServer = library.lookup<NativeFunction<void_from_string_string_byte_function>>("c_CreateServer");
// ignore: non_constant_identifier_names
final CreateServer = createServer.asFunction<StringFn>();
final CreateServer = createServer.asFunction<VoidFromStringStringByteFn>();
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<NativeFunction<void_from_string_string_string_function>>("c_SetServerAttribute");
// ignore: non_constant_identifier_names
final SetServerAttribute = setServerAttribute.asFunction<VoidFromStringStringStringFn>();
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<void> Shutdown() async {

View File

@ -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<void> Shutdown() async {
print("gomobile.dart Shutdown");

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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.",

View File

@ -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",

View File

@ -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",

View File

@ -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",

View File

@ -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<Flwtch> {
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<Flwtch> {
ChangeNotifierProvider<AppState> getAppStateProvider() => ChangeNotifierProvider.value(value: globalAppState);
Provider<FlwtchState> getFlwtchStateProvider() => Provider<FlwtchState>(create: (_) => this);
ChangeNotifierProvider<ProfileListState> getProfileListProvider() => ChangeNotifierProvider(create: (context) => profs);
ChangeNotifierProvider<ServerListState> getServerListStateProvider() => ChangeNotifierProvider.value(value: globalServersList);
@override
Widget build(BuildContext context) {
@ -94,6 +97,7 @@ class FlwtchState extends State<Flwtch> {
getErrorHandlerProvider(),
getTorStatusProvider(),
getAppStateProvider(),
getServerListStateProvider(),
],
builder: (context, widget) {
return Consumer2<Settings, AppState>(

View File

@ -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<dynamic> 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() {

View File

@ -1,15 +1,15 @@
import 'package:flutter/material.dart';
class ServerListState extends ChangeNotifier {
List<ServerInfoState> _servers = [];
class ProfileServerListState extends ChangeNotifier {
List<RemoteServerInfoState> _servers = [];
void replace(Iterable<ServerInfoState> newServers) {
void replace(Iterable<RemoteServerInfoState> 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<ServerInfoState> get servers => _servers.sublist(0); //todo: copy?? dont want caller able to bypass changenotifier
List<RemoteServerInfoState> 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});
}

View File

@ -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 {

View File

@ -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<AddContactView> {
},
isExpanded: true, // magic property
value: server,
items: Provider.of<ProfileInfoState>(context).serverList.servers.map<DropdownMenuItem<String>>((ServerInfoState serverInfo) {
items: Provider.of<ProfileInfoState>(context).serverList.servers.map<DropdownMenuItem<String>>((RemoteServerInfoState serverInfo) {
return DropdownMenuItem<String>(
value: serverInfo.onion,
child: Text(
@ -240,8 +240,8 @@ class _AddContactViewState extends State<AddContactView> {
/// TODO Manage Servers Tab
Widget manageServersTab() {
final tiles = Provider.of<ProfileInfoState>(context).serverList.servers.map((ServerInfoState server) {
return ChangeNotifierProvider<ServerInfoState>.value(
final tiles = Provider.of<ProfileInfoState>(context).serverList.servers.map((RemoteServerInfoState server) {
return ChangeNotifierProvider<RemoteServerInfoState>.value(
value: server,
child: ListTile(
title: Text(server.onion),

View File

@ -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<AddEditProfileView> {
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<AddEditProfileView> {
Provider.of<FlwtchState>(context, listen: false).cwtch.CreateProfile(ctrlrNick.value.text, ctrlrPass.value.text);
Navigator.of(context).pop();
} else {
Provider.of<FlwtchState>(context, listen: false).cwtch.CreateProfile(ctrlrNick.value.text, "be gay do crime");
Provider.of<FlwtchState>(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<FlwtchState>(context, listen: false).cwtch.SendProfileEvent(Provider.of<ProfileInfoState>(context, listen: false).onion, json);
Provider.of<FlwtchState>(context, listen: false).cwtch.SetProfileAttribute(Provider.of<ProfileInfoState>(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<FlwtchState>(context, listen: false).cwtch.SendProfileEvent(Provider.of<ProfileInfoState>(context, listen: false).onion, updateNameEventJson);
Provider.of<FlwtchState>(context, listen: false).cwtch.SetProfileAttribute(Provider.of<ProfileInfoState>(context, listen: false).onion, "public.name", ctrlrNick.value.text);
final updatePasswordEvent = {
"EventType": "ChangePassword",
"Data": {"Password": ctrlrOldPass.text, "NewPassword": ctrlrPass.text}

View File

@ -103,9 +103,10 @@ class _ContactsViewState extends State<ContactsView> {
if (Provider.of<Settings>(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<ContactListState>(context).isFiltered ? Icons.search_off : Icons.search),

View File

@ -188,6 +188,23 @@ class _GlobalSettingsViewState extends State<GlobalSettingsView> {
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),

View File

@ -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<ProfileMgrView> {
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<ProfileMgrView> {
onPressed: _modalUnlockProfiles,
));
// Servers
if (Provider.of<Settings>(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<ProfileMgrView> {
));
}
void _pushServers() {
Navigator.of(context).push(MaterialPageRoute<void>(
builder: (BuildContext context) {
return MultiProvider(
providers: [Provider.value(value: Provider.of<FlwtchState>(context))],
child: ServersView(),
);
},
));
}
void _pushTorStatus() {
Navigator.of(context).push(MaterialPageRoute<void>(
builder: (BuildContext context) {
@ -130,7 +149,7 @@ class _ProfileMgrViewState extends State<ProfileMgrView> {
));
}
void _pushAddEditProfile({onion: ""}) {
void _pushAddProfile({onion: ""}) {
Navigator.of(context).push(MaterialPageRoute<void>(
builder: (BuildContext context) {
return MultiProvider(

View File

@ -61,7 +61,7 @@ class _ProfileRowState extends State<ProfileRow> {
tooltip: AppLocalizations.of(context)!.editProfile + " " + profile.nickname,
icon: Icon(Icons.create, color: Provider.of<Settings>(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<ProfileRow> {
);
}
void _pushAddEditProfile({onion: "", displayName: "", profileImage: "", encrypted: true}) {
void _pushEditProfile({onion: "", displayName: "", profileImage: "", encrypted: true}) {
Navigator.of(context).push(MaterialPageRoute<void>(
builder: (BuildContext context) {
return MultiProvider(