Some improvements

This commit is contained in:
Juan Gilsanz Polo 2022-10-23 19:27:23 +02:00
parent d57572cc56
commit c3690902c8
7 changed files with 355 additions and 393 deletions

View file

@ -523,5 +523,7 @@
"dataNotValid": "Data not valid", "dataNotValid": "Data not valid",
"encryptionConfigSaved": "Encryption configuration saved successfully", "encryptionConfigSaved": "Encryption configuration saved successfully",
"encryptionConfigNotSaved": "Encryption configuration could not be saved", "encryptionConfigNotSaved": "Encryption configuration could not be saved",
"configError": "Configuration error" "configError": "Configuration error",
"enterOnlyCertificate": "Enter only the certificate. Do not input the ---BEGIN--- and ---END--- lines.",
"enterOnlyPrivateKey": "Enter only the key. Do not input the ---BEGIN--- and ---END--- lines."
} }

View file

@ -523,5 +523,7 @@
"dataNotValid": "Datos no válidos", "dataNotValid": "Datos no válidos",
"encryptionConfigSaved": "Configuración de cifrado guardada correctamente", "encryptionConfigSaved": "Configuración de cifrado guardada correctamente",
"encryptionConfigNotSaved": "No se pudo guardar la configuración de encriptado", "encryptionConfigNotSaved": "No se pudo guardar la configuración de encriptado",
"configError": "Configuration error" "configError": "Configuration error",
"enterOnlyCertificate": "Introduce sólo el certificado. No introduzcas las líneas ---BEGIN--- y ---END---.",
"enterOnlyPrivateKey": "Introduce sólo la clave privada. No introduzcas las líneas ---BEGIN--- y ---END---."
} }

View file

@ -50,11 +50,6 @@ class ServersProvider with ChangeNotifier {
data: null data: null
); );
final Encryption _encryptionSettings = Encryption(
loadStatus: 0, // 0 = loading, 1 = loaded, 2 = error,
data: null
);
FilteringStatus? _filteringStatus; FilteringStatus? _filteringStatus;
List<Server> get serversList { List<Server> get serversList {
@ -97,10 +92,6 @@ class ServersProvider with ChangeNotifier {
return _dnsInfo; return _dnsInfo;
} }
Encryption get encryptionSettings {
return _encryptionSettings;
}
void setDbInstance(Database db) { void setDbInstance(Database db) {
_dbInstance = db; _dbInstance = db;
} }
@ -211,18 +202,6 @@ class ServersProvider with ChangeNotifier {
} }
} }
void setEncryptionSettings(EncryptionData data) {
_encryptionSettings.data = data;
notifyListeners();
}
void setEncryptionSettingsLoadStatus(int status, bool notify) {
_encryptionSettings.loadStatus = status;
if (notify == true) {
notifyListeners();
}
}
Future<bool> createServer(Server server) async { Future<bool> createServer(Server server) async {
final saved = await saveServerIntoDb(server); final saved = await saveServerIntoDb(server);
if (saved == true) { if (saved == true) {

View file

@ -0,0 +1,60 @@
import 'package:flutter/material.dart';
class EncryptionTextField extends StatelessWidget {
final bool enabled;
final TextEditingController controller;
final IconData icon;
final void Function(String) onChanged;
final String? errorText;
final String label;
final TextInputType? keyboardType;
final bool? multiline;
final String? helperText;
const EncryptionTextField({
Key? key,
required this.enabled,
required this.controller,
required this.icon,
required this.onChanged,
this.errorText,
required this.label,
this.keyboardType,
this.multiline,
this.helperText,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: ConstrainedBox(
constraints: const BoxConstraints(
maxHeight: 200
),
child: TextFormField(
enabled: enabled,
controller: controller,
onChanged: onChanged,
decoration: InputDecoration(
prefixIcon: Icon(icon),
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(10)
)
),
errorText: errorText,
labelText: label,
helperText: helperText,
helperMaxLines: 10,
helperStyle: TextStyle(
color: Theme.of(context).listTileTheme.iconColor
)
),
keyboardType: TextInputType.multiline,
maxLines: multiline == true ? null : 1,
),
),
);
}
}

View file

@ -6,6 +6,9 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:adguard_home_manager/screens/settings/section_label.dart'; import 'package:adguard_home_manager/screens/settings/section_label.dart';
import 'package:adguard_home_manager/screens/settings/encryption/config_error_modal.dart'; import 'package:adguard_home_manager/screens/settings/encryption/config_error_modal.dart';
import 'package:adguard_home_manager/screens/settings/encryption/custom_text_field.dart';
import 'package:adguard_home_manager/screens/settings/encryption/master_switch.dart';
import 'package:adguard_home_manager/screens/settings/encryption/encryption_functions.dart';
import 'package:adguard_home_manager/widgets/custom_switch_list_tile.dart'; import 'package:adguard_home_manager/widgets/custom_switch_list_tile.dart';
import 'package:adguard_home_manager/classes/process_modal.dart'; import 'package:adguard_home_manager/classes/process_modal.dart';
@ -44,6 +47,8 @@ class EncryptionSettingsWidget extends StatefulWidget {
} }
class _EncryptionSettingsWidgetState extends State<EncryptionSettingsWidget> { class _EncryptionSettingsWidgetState extends State<EncryptionSettingsWidget> {
int loadStatus = 0;
bool enabled = false; bool enabled = false;
final TextEditingController domainNameController = TextEditingController(); final TextEditingController domainNameController = TextEditingController();
@ -78,12 +83,12 @@ class _EncryptionSettingsWidgetState extends State<EncryptionSettingsWidget> {
final TextEditingController pastePrivateKeyController = TextEditingController(); final TextEditingController pastePrivateKeyController = TextEditingController();
String? pastePrivateKeyError; String? pastePrivateKeyError;
bool validData = false; bool localValidationValid = false;
String? validDataError; String? validDataError;
int dataValidApi = 0; int dataValidApi = 0;
void fetchData({bool? showRefreshIndicator}) async { void fetchData({bool? showRefreshIndicator}) async {
widget.serversProvider.setEncryptionSettingsLoadStatus(0, showRefreshIndicator ?? false); setState(() => loadStatus = 0);
final result = await getEncryptionSettings(server: widget.serversProvider.selectedServer!); final result = await getEncryptionSettings(server: widget.serversProvider.selectedServer!);
@ -115,120 +120,17 @@ class _EncryptionSettingsWidgetState extends State<EncryptionSettingsWidget> {
privateKeyPathController.text = result['data'].privateKeyPath; privateKeyPathController.text = result['data'].privateKeyPath;
} }
usePreviouslySavedKey = result['data'].privateKeySaved; usePreviouslySavedKey = result['data'].privateKeySaved;
});
widget.serversProvider.setEncryptionSettings(result['data']); loadStatus = 1;
widget.serversProvider.setEncryptionSettingsLoadStatus(1, true); });
} }
else { else {
widget.appConfigProvider.addLog(result['log']); widget.appConfigProvider.addLog(result['log']);
widget.serversProvider.setEncryptionSettingsLoadStatus(2, true); setState(() => loadStatus = 2);
} }
} }
} }
void validateDomain(String domain) {
RegExp regExp = RegExp(r'^([a-z0-9|-]+\.)*[a-z0-9|-]+\.[a-z]+$');
if (regExp.hasMatch(domain)) {
setState(() => domainError = null);
checkValidDataApi();
}
else {
setState(() => domainError = AppLocalizations.of(context)!.domainNotValid);
}
checkDataValid();
}
void validatePort(String value, String portType) {
if (int.tryParse(value) != null && int.parse(value) <= 65535) {
setState(() {
switch (portType) {
case 'https':
setState(() => httpsPortError = null);
break;
case 'tls':
setState(() => tlsPortError = null);
break;
case 'quic':
setState(() => dnsOverQuicPortError = null);
break;
default:
break;
}
});
checkValidDataApi();
}
else {
setState(() {
switch (portType) {
case 'https':
setState(() => httpsPortError = AppLocalizations.of(context)!.invalidPort);
break;
case 'tls':
setState(() => tlsPortError = AppLocalizations.of(context)!.invalidPort);
break;
case 'quic':
setState(() => dnsOverQuicPortError = AppLocalizations.of(context)!.invalidPort);
break;
default:
break;
}
});
}
checkDataValid();
}
void validateCertificate(String cert) {
final regExp = RegExp(r'(-{3,}(\bBEGIN CERTIFICATE\b))|(-{3,}-{3,}(\END CERTIFICATE\b)-{3,})', multiLine: true);
if (regExp.hasMatch(cert.replaceAll('\n', ''))) {
setState(() => certificateContentError = AppLocalizations.of(context)!.invalidCertificate);
}
else {
setState(() => certificateContentError = null);
}
checkDataValid();
checkValidDataApi();
}
void validatePrivateKey(String cert) {
final regExp = RegExp(r'(-{3,}(\bBEGIN\b).*(PRIVATE KEY\b))|(-{3,}-{3,}(\bEND\b).*(PRIVATE KEY\b)-{3,})', multiLine: true);
if (regExp.hasMatch(cert.replaceAll('\n', ''))) {
setState(() => pastePrivateKeyError = AppLocalizations.of(context)!.invalidPrivateKey);
}
else {
setState(() => pastePrivateKeyError = null);
}
checkValidDataApi();
}
void validatePath(String cert, String item) {
final regExp = RegExp(r'^(\/{0,1}(?!\/))[A-Za-z0-9\/\-_]+(\.([a-zA-Z]+))?$');
if (regExp.hasMatch(cert)) {
if (item == 'cert') {
setState(() => certificatePathError = null);
}
else if (item == 'private_key') {
setState(() => privateKeyPathError = null);
}
checkValidDataApi();
}
else {
if (item == 'cert') {
setState(() => certificatePathError = AppLocalizations.of(context)!.invalidPath);
}
else if (item == 'private_key') {
setState(() => privateKeyPathError = AppLocalizations.of(context)!.invalidPath);
}
}
checkDataValid();
}
Future checkValidDataApi({Map<String, dynamic>? data}) async { Future checkValidDataApi({Map<String, dynamic>? data}) async {
setState(() => dataValidApi = 0); setState(() => dataValidApi = 0);
@ -295,11 +197,11 @@ class _EncryptionSettingsWidgetState extends State<EncryptionSettingsWidget> {
pastePrivateKeyError == null pastePrivateKeyError == null
)) ))
) { ) {
setState(() => validData = true); setState(() => localValidationValid = true);
checkValidDataApi(); checkValidDataApi();
} }
else { else {
setState(() => validData = false); setState(() => localValidationValid = false);
} }
} }
@ -355,50 +257,8 @@ class _EncryptionSettingsWidgetState extends State<EncryptionSettingsWidget> {
} }
} }
Widget generateStatus() {
if (dataValidApi == 0) {
return const SizedBox(
height: 25,
width: 25,
child: CircularProgressIndicator(
strokeWidth: 3,
)
);
}
else if (dataValidApi == 1) {
return const Icon(
Icons.check_circle_rounded,
color: Colors.green,
);
}
else if (dataValidApi == 2) {
return const Icon(
Icons.cancel_rounded,
color: Colors.red,
);
}
else {
return const SizedBox();
}
}
String generateStatusString() {
if (dataValidApi == 0) {
return AppLocalizations.of(context)!.validatingData;
}
else if (dataValidApi == 1) {
return AppLocalizations.of(context)!.dataValid;
}
else if (dataValidApi == 2) {
return AppLocalizations.of(context)!.dataNotValid;
}
else {
return "";
}
}
Widget generateBody() { Widget generateBody() {
switch (widget.serversProvider.encryptionSettings.loadStatus) { switch (loadStatus) {
case 0: case 0:
return SizedBox( return SizedBox(
width: double.maxFinite, width: double.maxFinite,
@ -423,89 +283,25 @@ class _EncryptionSettingsWidgetState extends State<EncryptionSettingsWidget> {
case 1: case 1:
return ListView( return ListView(
children: [ children: [
Padding( EncryptionMasterSwitch(
padding: const EdgeInsets.only( value: enabled,
top: 10, onChange: (value) {
left: 12, setState(() => enabled = value);
right: 12 checkDataValid();
), }
child: Material(
color: Theme.of(context).primaryColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(28),
child: InkWell(
onTap: () {
setState(() => enabled = !enabled);
checkDataValid();
checkValidDataApi();
},
borderRadius: BorderRadius.circular(28),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 12
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
AppLocalizations.of(context)!.enableEncryption,
style: const TextStyle(
fontSize: 18,
),
),
const SizedBox(height: 3),
Text(
AppLocalizations.of(context)!.enableEncryptionTypes,
style: TextStyle(
fontSize: 14,
color: Theme.of(context).listTileTheme.iconColor,
),
)
],
),
),
Switch(
value: enabled,
onChanged: (value) {
setState(() => enabled = value);
checkDataValid();
checkValidDataApi();
},
activeColor: Theme.of(context).primaryColor,
),
],
),
),
),
),
), ),
SectionLabel(label: AppLocalizations.of(context)!.serverConfiguration), SectionLabel(label: AppLocalizations.of(context)!.serverConfiguration),
Padding( EncryptionTextField(
padding: const EdgeInsets.symmetric(horizontal: 20), enabled: enabled,
child: TextFormField( controller: domainNameController,
enabled: enabled, icon: Icons.link_rounded,
controller: domainNameController, onChanged: (value) {
onChanged: validateDomain, setState(() => domainError = validateDomain(context, value));
decoration: InputDecoration( checkDataValid();
prefixIcon: const Icon(Icons.link_rounded), },
border: const OutlineInputBorder( errorText: domainError,
borderRadius: BorderRadius.all( label: AppLocalizations.of(context)!.domainName,
Radius.circular(10) helperText: AppLocalizations.of(context)!.domainNameDescription,
)
),
errorText: domainError,
labelText: AppLocalizations.of(context)!.domainName,
helperText: AppLocalizations.of(context)!.domainNameDescription,
helperStyle: TextStyle(
color: Theme.of(context).listTileTheme.iconColor
),
helperMaxLines: 10
),
),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
CustomSwitchListTile( CustomSwitchListTile(
@ -513,70 +309,48 @@ class _EncryptionSettingsWidgetState extends State<EncryptionSettingsWidget> {
onChanged: (value) { onChanged: (value) {
setState(() => redirectHttps = value); setState(() => redirectHttps = value);
checkDataValid(); checkDataValid();
checkValidDataApi();
}, },
title: AppLocalizations.of(context)!.redirectHttps, title: AppLocalizations.of(context)!.redirectHttps,
disabled: !enabled, disabled: !enabled,
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
Padding( EncryptionTextField(
padding: const EdgeInsets.symmetric(horizontal: 20), enabled: enabled,
child: TextFormField( controller: httpsPortController,
enabled: enabled, icon: Icons.numbers_rounded,
controller: httpsPortController, onChanged: (value) {
onChanged: (value) => validatePort(value, 'https'), setState(() => httpsPortError = validatePort(context, value));
decoration: InputDecoration( checkDataValid();
prefixIcon: const Icon(Icons.numbers_rounded), },
border: const OutlineInputBorder( errorText: httpsPortError,
borderRadius: BorderRadius.all( label: AppLocalizations.of(context)!.httpsPort,
Radius.circular(10) keyboardType: TextInputType.number,
)
),
errorText: httpsPortError,
labelText: AppLocalizations.of(context)!.httpsPort,
),
keyboardType: TextInputType.number,
),
), ),
const SizedBox(height: 30), const SizedBox(height: 30),
Padding( EncryptionTextField(
padding: const EdgeInsets.symmetric(horizontal: 20), enabled: enabled,
child: TextFormField( controller: tlsPortController,
enabled: enabled, icon: Icons.numbers_rounded,
controller: tlsPortController, onChanged: (value) {
onChanged: (value) => validatePort(value, 'tls'), setState(() => tlsPortError = validatePort(context, value));
decoration: InputDecoration( checkDataValid();
prefixIcon: const Icon(Icons.numbers_rounded), },
border: const OutlineInputBorder( errorText: tlsPortError,
borderRadius: BorderRadius.all( label: AppLocalizations.of(context)!.tlsPort,
Radius.circular(10) keyboardType: TextInputType.number,
)
),
errorText: tlsPortError,
labelText: AppLocalizations.of(context)!.tlsPort,
),
keyboardType: TextInputType.number,
),
), ),
const SizedBox(height: 30), const SizedBox(height: 30),
Padding( EncryptionTextField(
padding: const EdgeInsets.symmetric(horizontal: 20), enabled: enabled,
child: TextFormField( controller: dnsOverQuicPortController,
enabled: enabled, icon: Icons.numbers_rounded,
controller: dnsOverQuicPortController, onChanged: (value) {
onChanged: (value) => validatePort(value, 'quic'), setState(() => dnsOverQuicPortError = validatePort(context, value));
decoration: InputDecoration( checkDataValid();
prefixIcon: const Icon(Icons.numbers_rounded), },
border: const OutlineInputBorder( errorText: dnsOverQuicPortError,
borderRadius: BorderRadius.all( label: AppLocalizations.of(context)!.dnsOverQuicPort,
Radius.circular(10) keyboardType: TextInputType.number,
)
),
errorText: dnsOverQuicPortError,
labelText: AppLocalizations.of(context)!.dnsOverQuicPort,
),
keyboardType: TextInputType.number,
),
), ),
SectionLabel(label: AppLocalizations.of(context)!.certificates), SectionLabel(label: AppLocalizations.of(context)!.certificates),
Card( Card(
@ -602,7 +376,6 @@ class _EncryptionSettingsWidgetState extends State<EncryptionSettingsWidget> {
? (value) { ? (value) {
setState(() => certificateOption = int.parse(value.toString())); setState(() => certificateOption = int.parse(value.toString()));
checkDataValid(); checkDataValid();
checkValidDataApi();
} }
: null, : null,
title: Text( title: Text(
@ -619,7 +392,6 @@ class _EncryptionSettingsWidgetState extends State<EncryptionSettingsWidget> {
? (value) { ? (value) {
setState(() => certificateOption = int.parse(value.toString())); setState(() => certificateOption = int.parse(value.toString()));
checkDataValid(); checkDataValid();
checkValidDataApi();
} }
: null, : null,
title: Text( title: Text(
@ -630,43 +402,30 @@ class _EncryptionSettingsWidgetState extends State<EncryptionSettingsWidget> {
), ),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
if (certificateOption == 0) Padding( if (certificateOption == 0) EncryptionTextField(
padding: const EdgeInsets.symmetric(horizontal: 20), enabled: enabled,
child: TextFormField( controller: certificatePathController,
enabled: enabled, icon: Icons.description_rounded,
controller: certificatePathController, onChanged: (value) {
onChanged: (value) => validatePath(value, 'cert'), setState(() => certificatePathError = validatePath(context, value));
decoration: InputDecoration( checkDataValid();
prefixIcon: const Icon(Icons.description_rounded), },
border: const OutlineInputBorder( label: AppLocalizations.of(context)!.certificatePath,
borderRadius: BorderRadius.all( errorText: certificatePathError,
Radius.circular(10)
)
),
errorText: certificatePathError,
labelText: AppLocalizations.of(context)!.certificatePath,
),
),
), ),
if (certificateOption == 1) Padding( if (certificateOption == 1) EncryptionTextField(
padding: const EdgeInsets.symmetric(horizontal: 20), enabled: enabled,
child: TextFormField( controller: certificateContentController,
enabled: enabled, icon: Icons.description_rounded,
controller: certificateContentController, onChanged: (value) {
onChanged: validateCertificate, setState(() => certificateContentError = validateCertificate(context, value));
decoration: InputDecoration( checkDataValid();
prefixIcon: const Icon(Icons.description_rounded), },
border: const OutlineInputBorder( label: AppLocalizations.of(context)!.certificateContent,
borderRadius: BorderRadius.all( helperText: AppLocalizations.of(context)!.enterOnlyCertificate,
Radius.circular(10) errorText: certificateContentError,
) multiline: true,
), keyboardType: TextInputType.multiline,
errorText: certificateContentError,
labelText: AppLocalizations.of(context)!.certificateContent,
),
keyboardType: TextInputType.multiline,
maxLines: null,
),
), ),
SectionLabel(label: AppLocalizations.of(context)!.privateKey), SectionLabel(label: AppLocalizations.of(context)!.privateKey),
RadioListTile( RadioListTile(
@ -676,7 +435,6 @@ class _EncryptionSettingsWidgetState extends State<EncryptionSettingsWidget> {
? (value) { ? (value) {
setState(() => privateKeyOption = int.parse(value.toString())); setState(() => privateKeyOption = int.parse(value.toString()));
checkDataValid(); checkDataValid();
checkValidDataApi();
} }
: null, : null,
title: Text( title: Text(
@ -693,7 +451,6 @@ class _EncryptionSettingsWidgetState extends State<EncryptionSettingsWidget> {
? (value) { ? (value) {
setState(() => privateKeyOption = int.parse(value.toString())); setState(() => privateKeyOption = int.parse(value.toString()));
checkDataValid(); checkDataValid();
checkValidDataApi();
} }
: null, : null,
title: Text( title: Text(
@ -712,45 +469,32 @@ class _EncryptionSettingsWidgetState extends State<EncryptionSettingsWidget> {
), ),
const SizedBox(height: 10) const SizedBox(height: 10)
], ],
if (privateKeyOption == 0) Padding( if (privateKeyOption == 0) EncryptionTextField(
padding: const EdgeInsets.symmetric(horizontal: 20), enabled: enabled,
child: TextFormField( controller: privateKeyPathController,
enabled: enabled, icon: Icons.description_rounded,
controller: privateKeyPathController, onChanged: (value) {
onChanged: (value) => validatePath(value, 'private_key'), setState(() => privateKeyPathError = validatePath(context, value));
decoration: InputDecoration( checkDataValid();
prefixIcon: const Icon(Icons.description_rounded), },
border: const OutlineInputBorder( label: AppLocalizations.of(context)!.privateKeyPath,
borderRadius: BorderRadius.all( errorText: privateKeyPathError,
Radius.circular(10)
)
),
errorText: privateKeyPathError,
labelText: AppLocalizations.of(context)!.privateKeyPath,
),
),
), ),
if (privateKeyOption == 1) Padding( if (privateKeyOption == 1) EncryptionTextField(
padding: const EdgeInsets.symmetric(horizontal: 20), enabled: enabled == true
child: TextFormField( ? !usePreviouslySavedKey
enabled: enabled == true : false,
? !usePreviouslySavedKey controller: pastePrivateKeyController,
: false, icon: Icons.description_rounded,
controller: pastePrivateKeyController, onChanged: (value) {
onChanged: validatePrivateKey, setState(() => pastePrivateKeyError = validatePrivateKey(context, value));
decoration: InputDecoration( checkDataValid();
prefixIcon: const Icon(Icons.description_rounded), },
border: const OutlineInputBorder( label: AppLocalizations.of(context)!.pastePrivateKey,
borderRadius: BorderRadius.all( helperText: AppLocalizations.of(context)!.enterOnlyPrivateKey,
Radius.circular(10) errorText: pastePrivateKeyError,
) keyboardType: TextInputType.multiline,
), multiline: true,
errorText: pastePrivateKeyError,
labelText: AppLocalizations.of(context)!.pastePrivateKey,
),
keyboardType: TextInputType.multiline,
maxLines: null,
),
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
], ],
@ -798,11 +542,11 @@ class _EncryptionSettingsWidgetState extends State<EncryptionSettingsWidget> {
builder: (context) => EncryptionErrorModal(error: validDataError!) builder: (context) => EncryptionErrorModal(error: validDataError!)
) )
} : null, } : null,
icon: generateStatus(), icon: generateStatus(localValidationValid, dataValidApi),
tooltip: generateStatusString() tooltip: generateStatusString(context, localValidationValid, dataValidApi)
), ),
IconButton( IconButton(
onPressed: validData == true && dataValidApi == 1 onPressed: localValidationValid == true && dataValidApi == 1
? () => saveData() ? () => saveData()
: null, : null,
icon: const Icon(Icons.save), icon: const Icon(Icons.save),

View file

@ -0,0 +1,106 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
String? validateDomain(BuildContext context, String domain) {
RegExp regExp = RegExp(r'^([a-z0-9|-]+\.)*[a-z0-9|-]+\.[a-z]+$');
if (regExp.hasMatch(domain)) {
return null;
}
else {
return AppLocalizations.of(context)!.domainNotValid;
}
}
String? validatePort(BuildContext context, String value) {
if (int.tryParse(value) != null && int.parse(value) <= 65535) {
return null;
}
else {
return AppLocalizations.of(context)!.invalidPort;
}
}
String? validateCertificate(BuildContext context, String cert) {
final regExp = RegExp(r'(-{3,}(\bBEGIN CERTIFICATE\b))|(-{3,}-{3,}(\END CERTIFICATE\b)-{3,})', multiLine: true);
if (regExp.hasMatch(cert.replaceAll('\n', ''))) {
return AppLocalizations.of(context)!.invalidCertificate;
}
else {
return null;
}
}
String? validatePrivateKey(BuildContext context, String cert) {
final regExp = RegExp(r'(-{3,}(\bBEGIN\b).*(PRIVATE KEY\b))|(-{3,}-{3,}(\bEND\b).*(PRIVATE KEY\b)-{3,})', multiLine: true);
if (regExp.hasMatch(cert.replaceAll('\n', ''))) {
return AppLocalizations.of(context)!.invalidPrivateKey;
}
else {
return null;
}
}
String? validatePath(BuildContext context, String cert) {
final regExp = RegExp(r'^(\/{0,1}(?!\/))[A-Za-z0-9\/\-_]+(\.([a-zA-Z]+))?$');
if (regExp.hasMatch(cert)) {
return null;
}
else {
return AppLocalizations.of(context)!.invalidPath;
}
}
Widget generateStatus(bool localValidation, int dataValidApi) {
if (localValidation == true) {
if (dataValidApi == 0) {
return const SizedBox(
height: 25,
width: 25,
child: CircularProgressIndicator(
strokeWidth: 3,
)
);
}
else if (dataValidApi == 1) {
return const Icon(
Icons.check_circle_rounded,
color: Colors.green,
);
}
else if (dataValidApi == 2) {
return const Icon(
Icons.cancel_rounded,
color: Colors.red,
);
}
else {
return const SizedBox();
}
}
else {
return const Icon(
Icons.error_rounded,
color: Colors.grey,
);
}
}
String generateStatusString(BuildContext context, bool localValidation, int dataValidApi) {
if (localValidation == true) {
if (dataValidApi == 0) {
return AppLocalizations.of(context)!.validatingData;
}
else if (dataValidApi == 1) {
return AppLocalizations.of(context)!.dataValid;
}
else if (dataValidApi == 2) {
return AppLocalizations.of(context)!.dataNotValid;
}
else {
return "";
}
}
else {
return AppLocalizations.of(context)!.dataNotValid;
}
}

View file

@ -0,0 +1,69 @@
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class EncryptionMasterSwitch extends StatelessWidget {
final bool value;
final void Function(bool) onChange;
const EncryptionMasterSwitch({
Key? key,
required this.value,
required this.onChange
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(
top: 10,
left: 12,
right: 12
),
child: Material(
color: Theme.of(context).primaryColor.withOpacity(0.1),
borderRadius: BorderRadius.circular(28),
child: InkWell(
onTap: () => onChange(!value),
borderRadius: BorderRadius.circular(28),
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 12
),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
AppLocalizations.of(context)!.enableEncryption,
style: const TextStyle(
fontSize: 18,
),
),
const SizedBox(height: 3),
Text(
AppLocalizations.of(context)!.enableEncryptionTypes,
style: TextStyle(
fontSize: 14,
color: Theme.of(context).listTileTheme.iconColor,
),
)
],
),
),
Switch(
value: value,
onChanged: (value) => onChange(value),
activeColor: Theme.of(context).primaryColor,
),
],
),
),
),
),
);
}
}