mirror of
https://github.com/JGeek00/adguard-home-manager.git
synced 2025-04-22 06:49:11 +00:00
Added create connection
This commit is contained in:
parent
a97ae20631
commit
3acfc7c5a5
10 changed files with 411 additions and 21 deletions
|
@ -14,5 +14,17 @@
|
||||||
"general": "General",
|
"general": "General",
|
||||||
"connection": "Connection",
|
"connection": "Connection",
|
||||||
"authentication": "Authentication",
|
"authentication": "Authentication",
|
||||||
"other": "Other"
|
"other": "Other",
|
||||||
|
"invalidPort": "Invalid port",
|
||||||
|
"invalidPath": "Invalid path",
|
||||||
|
"invalidIpDomain": "Invalid IP or domain",
|
||||||
|
"ipDomainNotEmpty": "IP or domain cannot be empty",
|
||||||
|
"nameNotEmpty": "Name cannot be empty",
|
||||||
|
"invalidUsernamePassword": "Invalid username or password",
|
||||||
|
"tooManyAttempts": "Too many attempts. Try again later.",
|
||||||
|
"cantReachServer": "Can't reach server. Check connection data.",
|
||||||
|
"sslError": "SSL error",
|
||||||
|
"unknownError": "Unknown error",
|
||||||
|
"connectionNotCreated": "Connection couldn't be created",
|
||||||
|
"connecting": "Connecting..."
|
||||||
}
|
}
|
|
@ -14,5 +14,17 @@
|
||||||
"general": "General",
|
"general": "General",
|
||||||
"connection": "Conexión",
|
"connection": "Conexión",
|
||||||
"authentication": "Autenticación",
|
"authentication": "Autenticación",
|
||||||
"other": "Otros"
|
"other": "Otros",
|
||||||
|
"invalidPort": "Puerto no válido",
|
||||||
|
"invalidPath": "Ruta no válida",
|
||||||
|
"invalidIpDomain": "IP o dominio no válido",
|
||||||
|
"ipDomainNotEmpty": "IP o dominio no puede estar vacío",
|
||||||
|
"nameNotEmpty": "Name cannot be empty",
|
||||||
|
"invalidUsernamePassword": "Usuario o contraseña no válidos.",
|
||||||
|
"tooManyAttempts": "Demasiados intentos. Prueba de nuevo más tarde.",
|
||||||
|
"cantReachServer": "No se puede alcanzar el servidor. Comprueba los datos de conexión.",
|
||||||
|
"sslError": "Error de SSL",
|
||||||
|
"unknownError": "Error desconocido",
|
||||||
|
"connectionNotCreated": "No se pudo crear la conexión",
|
||||||
|
"connecting": "Conectando..."
|
||||||
}
|
}
|
|
@ -1,14 +1,16 @@
|
||||||
class Server {
|
class Server {
|
||||||
final String name;
|
final String id;
|
||||||
final String connectionMethod;
|
String name;
|
||||||
final String domain;
|
String connectionMethod;
|
||||||
final String? path;
|
String domain;
|
||||||
final int? port;
|
String? path;
|
||||||
final String user;
|
int? port;
|
||||||
final String password;
|
String user;
|
||||||
final bool defaultServer;
|
String password;
|
||||||
|
bool defaultServer;
|
||||||
|
|
||||||
const Server({
|
Server({
|
||||||
|
required this.id,
|
||||||
required this.name,
|
required this.name,
|
||||||
required this.connectionMethod,
|
required this.connectionMethod,
|
||||||
required this.domain,
|
required this.domain,
|
||||||
|
|
|
@ -27,10 +27,87 @@ class ServersProvider with ChangeNotifier {
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<bool> createServer(Server server) async {
|
||||||
|
final saved = await saveServerIntoDb(server);
|
||||||
|
if (saved == true) {
|
||||||
|
if (server.defaultServer == true) {
|
||||||
|
final defaultServer = await setDefaultServer(server);
|
||||||
|
if (defaultServer == true) {
|
||||||
|
_serversList.add(server);
|
||||||
|
notifyListeners();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_serversList.add(server);
|
||||||
|
notifyListeners();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> setDefaultServer(Server server) async {
|
||||||
|
final updated = await setDefaultServerDb(server.id);
|
||||||
|
if (updated == true) {
|
||||||
|
List<Server> newServers = _serversList.map((s) {
|
||||||
|
if (s.id == server.id) {
|
||||||
|
s.defaultServer = true;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
s.defaultServer = false;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}).toList();
|
||||||
|
_serversList = newServers;
|
||||||
|
notifyListeners();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> saveServerIntoDb(Server server) async {
|
||||||
|
try {
|
||||||
|
return await _dbInstance!.transaction((txn) async {
|
||||||
|
await txn.rawInsert(
|
||||||
|
'INSERT INTO servers (id, name, connectionMethod, domain, path, port, user, password, defaultServer) VALUES ("${server.id}", "${server.name}", "${server.connectionMethod}", "${server.domain}", "${server.path}", ${server.port}, "${server.user}", "${server.password}", 0)',
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<bool> setDefaultServerDb(String id) async {
|
||||||
|
try {
|
||||||
|
return await _dbInstance!.transaction((txn) async {
|
||||||
|
await txn.rawUpdate(
|
||||||
|
'UPDATE servers SET defaultServer = 0 WHERE defaultServer = 1',
|
||||||
|
);
|
||||||
|
await txn.rawUpdate(
|
||||||
|
'UPDATE servers SET defaultServer = 1 WHERE id = "$id"',
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void saveFromDb(List<Map<String, dynamic>>? data) async {
|
void saveFromDb(List<Map<String, dynamic>>? data) async {
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
for (var server in data) {
|
for (var server in data) {
|
||||||
final Server serverObj = Server(
|
final Server serverObj = Server(
|
||||||
|
id: server['id'],
|
||||||
name: server['name'],
|
name: server['name'],
|
||||||
connectionMethod: server['connectionMethod'],
|
connectionMethod: server['connectionMethod'],
|
||||||
domain: server['domain'],
|
domain: server['domain'],
|
||||||
|
@ -38,10 +115,10 @@ class ServersProvider with ChangeNotifier {
|
||||||
port: server['port'],
|
port: server['port'],
|
||||||
user: server['user'],
|
user: server['user'],
|
||||||
password: server['password'],
|
password: server['password'],
|
||||||
defaultServer: convertFromIntToBool(server['isDefaultServer'])!,
|
defaultServer: convertFromIntToBool(server['defaultServer'])!,
|
||||||
);
|
);
|
||||||
_serversList.add(serverObj);
|
_serversList.add(serverObj);
|
||||||
if (convertFromIntToBool(server['isDefaultServer']) == true) {
|
if (convertFromIntToBool(server['defaultServer']) == true) {
|
||||||
_selectedServer = serverObj;
|
_selectedServer = serverObj;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
||||||
|
|
||||||
class Connect extends StatelessWidget {
|
class Connect extends StatelessWidget {
|
||||||
const Connect({Key? key}) : super(key: key);
|
const Connect({Key? key}) : super(key: key);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final serversProvider = Provider.of<ServersProvider>(context);
|
||||||
|
|
||||||
return Container();
|
return Container();
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,7 +8,7 @@ Future<Map<String, dynamic>> loadDb() async {
|
||||||
'adguard_home_manager.db',
|
'adguard_home_manager.db',
|
||||||
version: 1,
|
version: 1,
|
||||||
onCreate: (Database db, int version) async {
|
onCreate: (Database db, int version) async {
|
||||||
await db.execute("CREATE TABLE servers (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, connectionMethod TEXT, domain TEXT, path TEXT, port INTEGER, user TEXT, password TEXT, defaultServer INTEGER)");
|
await db.execute("CREATE TABLE servers (id TEXT PRIMARY KEY, name TEXT, connectionMethod TEXT, domain TEXT, path TEXT, port INTEGER, user TEXT, password TEXT, defaultServer INTEGER)");
|
||||||
},
|
},
|
||||||
onUpgrade: (Database db, int oldVersion, int newVersion) async {
|
onUpgrade: (Database db, int oldVersion, int newVersion) async {
|
||||||
|
|
||||||
|
|
47
lib/services/http_requests.dart
Normal file
47
lib/services/http_requests.dart
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
// ignore_for_file: depend_on_referenced_packages
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/models/server.dart';
|
||||||
|
|
||||||
|
Future login(Server server) async {
|
||||||
|
try {
|
||||||
|
final result = await http.post(
|
||||||
|
Uri.parse("${server.connectionMethod}://${server.domain}${server.path ?? ""}${server.port != null ? ':${server.port}' : ""}/control/login"),
|
||||||
|
body: jsonEncode({
|
||||||
|
"name": server.user,
|
||||||
|
"password": server.password
|
||||||
|
})
|
||||||
|
);
|
||||||
|
if (result.statusCode == 200) {
|
||||||
|
return {'result': 'success'};
|
||||||
|
}
|
||||||
|
else if (result.statusCode == 400) {
|
||||||
|
return {
|
||||||
|
'result': 'error',
|
||||||
|
'message': 'invalid_username_password'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else if (result.statusCode == 429) {
|
||||||
|
return {
|
||||||
|
'result': 'error',
|
||||||
|
'message': 'many_attempts'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return {'result': 'error'};
|
||||||
|
}
|
||||||
|
} on SocketException {
|
||||||
|
return {'result': 'no_connection'};
|
||||||
|
} on TimeoutException {
|
||||||
|
return {'result': 'no_connection'};
|
||||||
|
} on HandshakeException {
|
||||||
|
return {'result': 'ssl_error'};
|
||||||
|
} catch (e) {
|
||||||
|
return {'result': 'error'};
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,15 @@
|
||||||
|
// ignore_for_file: use_build_context_synchronously
|
||||||
|
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:uuid/uuid.dart';
|
||||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
|
|
||||||
import 'package:adguard_home_manager/widgets/custom_radio_toggle.dart';
|
import 'package:adguard_home_manager/widgets/custom_radio_toggle.dart';
|
||||||
|
|
||||||
|
import 'package:adguard_home_manager/services/http_requests.dart';
|
||||||
|
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
||||||
|
import 'package:adguard_home_manager/models/server.dart';
|
||||||
import 'package:adguard_home_manager/config/system_overlay_style.dart';
|
import 'package:adguard_home_manager/config/system_overlay_style.dart';
|
||||||
|
|
||||||
class AddServerModal extends StatefulWidget {
|
class AddServerModal extends StatefulWidget {
|
||||||
|
@ -13,7 +20,10 @@ class AddServerModal extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AddServerModalState extends State<AddServerModal> {
|
class _AddServerModalState extends State<AddServerModal> {
|
||||||
|
final uuid = const Uuid();
|
||||||
|
|
||||||
final TextEditingController nameController = TextEditingController();
|
final TextEditingController nameController = TextEditingController();
|
||||||
|
String? nameError;
|
||||||
|
|
||||||
String connectionType = "http";
|
String connectionType = "http";
|
||||||
|
|
||||||
|
@ -32,6 +42,10 @@ class _AddServerModalState extends State<AddServerModal> {
|
||||||
|
|
||||||
bool defaultServer = false;
|
bool defaultServer = false;
|
||||||
|
|
||||||
|
bool allDataValid = false;
|
||||||
|
|
||||||
|
bool isConnecting = false;
|
||||||
|
|
||||||
Widget sectionLabel(String label) {
|
Widget sectionLabel(String label) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(
|
padding: const EdgeInsets.symmetric(
|
||||||
|
@ -53,12 +67,14 @@ class _AddServerModalState extends State<AddServerModal> {
|
||||||
required TextEditingController controller,
|
required TextEditingController controller,
|
||||||
String? error,
|
String? error,
|
||||||
required IconData icon,
|
required IconData icon,
|
||||||
TextInputType? keyboardType
|
TextInputType? keyboardType,
|
||||||
|
Function(String)? onChanged,
|
||||||
}) {
|
}) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 20),
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
|
onChanged: onChanged,
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
prefixIcon: Icon(icon),
|
prefixIcon: Icon(icon),
|
||||||
errorText: error,
|
errorText: error,
|
||||||
|
@ -74,8 +90,168 @@ class _AddServerModalState extends State<AddServerModal> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void checkDataValid() {
|
||||||
|
if (
|
||||||
|
nameController.text != '' &&
|
||||||
|
ipDomainController.text != '' &&
|
||||||
|
ipDomainError == null &&
|
||||||
|
pathError == null &&
|
||||||
|
portError == null &&
|
||||||
|
userController.text != '' &&
|
||||||
|
passwordController.text != ''
|
||||||
|
) {
|
||||||
|
setState(() {
|
||||||
|
allDataValid = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setState(() {
|
||||||
|
allDataValid = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void validatePort(String? value) {
|
||||||
|
if (value != null && value != '') {
|
||||||
|
if (int.tryParse(value) != null && int.parse(value) <= 65535) {
|
||||||
|
setState(() {
|
||||||
|
portError = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setState(() {
|
||||||
|
portError = AppLocalizations.of(context)!.invalidPort;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setState(() {
|
||||||
|
portError = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
checkDataValid();
|
||||||
|
}
|
||||||
|
|
||||||
|
void validateSubroute(String? value) {
|
||||||
|
if (value != null && value != '') {
|
||||||
|
RegExp subrouteRegexp = RegExp(r'^\/\b([A-Za-z0-9_\-~/]*)[^\/|\.|\:]$');
|
||||||
|
if (subrouteRegexp.hasMatch(value) == true) {
|
||||||
|
setState(() {
|
||||||
|
pathError = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setState(() {
|
||||||
|
pathError = AppLocalizations.of(context)!.invalidPath;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setState(() {
|
||||||
|
pathError = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
checkDataValid();
|
||||||
|
}
|
||||||
|
|
||||||
|
void validateAddress(String? value) {
|
||||||
|
if (value != null && value != '') {
|
||||||
|
RegExp ipAddress = RegExp(r'^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)(\.(?!$)|$)){4}$');
|
||||||
|
RegExp domain = RegExp(r'^((?!-))(xn--)?[a-z0-9][a-z0-9-_]{0,61}[a-z0-9]{0,1}\.(xn--)?([a-z0-9\-]{1,61}|[a-z0-9-]{1,30}\.[a-z]{2,})$');
|
||||||
|
if (ipAddress.hasMatch(value) == true || domain.hasMatch(value) == true) {
|
||||||
|
setState(() {
|
||||||
|
ipDomainError = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setState(() {
|
||||||
|
ipDomainError = AppLocalizations.of(context)!.invalidIpDomain;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setState(() {
|
||||||
|
ipDomainError = AppLocalizations.of(context)!.ipDomainNotEmpty;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
checkDataValid();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final serversProvider = Provider.of<ServersProvider>(context, listen: false);
|
||||||
|
|
||||||
|
final mediaQuery = MediaQuery.of(context);
|
||||||
|
|
||||||
|
void connect() async {
|
||||||
|
final Server serverObj = Server(
|
||||||
|
id: uuid.v4(),
|
||||||
|
name: nameController.text,
|
||||||
|
connectionMethod: connectionType,
|
||||||
|
domain: ipDomainController.text,
|
||||||
|
port: int.parse(portController.text),
|
||||||
|
user: userController.text,
|
||||||
|
password: passwordController.text,
|
||||||
|
defaultServer: defaultServer
|
||||||
|
);
|
||||||
|
final result = await login(serverObj);
|
||||||
|
if (result['result'] == 'success') {
|
||||||
|
final serverCreated = await serversProvider.createServer(serverObj);
|
||||||
|
if (serverCreated == true) {
|
||||||
|
Navigator.pop(context);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(AppLocalizations.of(context)!.connectionNotCreated),
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (result['result'] == 'error' && result['message'] == 'invalid_username_password') {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(AppLocalizations.of(context)!.invalidUsernamePassword),
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (result['result'] == 'error' && result['message'] == 'many_attempts') {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(AppLocalizations.of(context)!.tooManyAttempts),
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (result['result'] == 'error' && result['message'] == 'no_connection') {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(AppLocalizations.of(context)!.cantReachServer),
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (result['result'] == 'error' && result['message'] == 'ssl_error') {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(AppLocalizations.of(context)!.sslError),
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(AppLocalizations.of(context)!.unknownError),
|
||||||
|
backgroundColor: Colors.red,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Stack(
|
return Stack(
|
||||||
children: [
|
children: [
|
||||||
Scaffold(
|
Scaffold(
|
||||||
|
@ -89,7 +265,9 @@ class _AddServerModalState extends State<AddServerModal> {
|
||||||
padding: const EdgeInsets.only(right: 10),
|
padding: const EdgeInsets.only(right: 10),
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
tooltip: AppLocalizations.of(context)!.connect,
|
tooltip: AppLocalizations.of(context)!.connect,
|
||||||
onPressed: () => {},
|
onPressed: allDataValid == true
|
||||||
|
? () => connect()
|
||||||
|
: null,
|
||||||
icon: const Icon(Icons.login_rounded)
|
icon: const Icon(Icons.login_rounded)
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -102,7 +280,11 @@ class _AddServerModalState extends State<AddServerModal> {
|
||||||
textField(
|
textField(
|
||||||
label: AppLocalizations.of(context)!.name,
|
label: AppLocalizations.of(context)!.name,
|
||||||
controller: nameController,
|
controller: nameController,
|
||||||
icon: Icons.badge_rounded
|
icon: Icons.badge_rounded,
|
||||||
|
error: nameError,
|
||||||
|
onChanged: (value) => value == ''
|
||||||
|
? setState(() => nameError = AppLocalizations.of(context)!.nameNotEmpty)
|
||||||
|
: setState(() => nameError = null)
|
||||||
),
|
),
|
||||||
sectionLabel(AppLocalizations.of(context)!.connection),
|
sectionLabel(AppLocalizations.of(context)!.connection),
|
||||||
Row(
|
Row(
|
||||||
|
@ -128,14 +310,16 @@ class _AddServerModalState extends State<AddServerModal> {
|
||||||
controller: ipDomainController,
|
controller: ipDomainController,
|
||||||
icon: Icons.link_rounded,
|
icon: Icons.link_rounded,
|
||||||
error: ipDomainError,
|
error: ipDomainError,
|
||||||
keyboardType: TextInputType.url
|
keyboardType: TextInputType.url,
|
||||||
|
onChanged: validateAddress
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
textField(
|
textField(
|
||||||
label: AppLocalizations.of(context)!.path,
|
label: AppLocalizations.of(context)!.path,
|
||||||
controller: pathController,
|
controller: pathController,
|
||||||
icon: Icons.route_rounded,
|
icon: Icons.route_rounded,
|
||||||
error: pathError
|
error: pathError,
|
||||||
|
onChanged: validateSubroute
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
textField(
|
textField(
|
||||||
|
@ -143,20 +327,23 @@ class _AddServerModalState extends State<AddServerModal> {
|
||||||
controller: portController,
|
controller: portController,
|
||||||
icon: Icons.numbers_rounded,
|
icon: Icons.numbers_rounded,
|
||||||
error: portError,
|
error: portError,
|
||||||
keyboardType: TextInputType.number
|
keyboardType: TextInputType.number,
|
||||||
|
onChanged: validatePort
|
||||||
),
|
),
|
||||||
sectionLabel(AppLocalizations.of(context)!.authentication),
|
sectionLabel(AppLocalizations.of(context)!.authentication),
|
||||||
textField(
|
textField(
|
||||||
label: AppLocalizations.of(context)!.username,
|
label: AppLocalizations.of(context)!.username,
|
||||||
controller: userController,
|
controller: userController,
|
||||||
icon: Icons.person_rounded,
|
icon: Icons.person_rounded,
|
||||||
|
onChanged: (_) => checkDataValid()
|
||||||
),
|
),
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
textField(
|
textField(
|
||||||
label: AppLocalizations.of(context)!.password,
|
label: AppLocalizations.of(context)!.password,
|
||||||
controller: passwordController,
|
controller: passwordController,
|
||||||
icon: Icons.lock_rounded,
|
icon: Icons.lock_rounded,
|
||||||
keyboardType: TextInputType.visiblePassword
|
keyboardType: TextInputType.visiblePassword,
|
||||||
|
onChanged: (_) => checkDataValid()
|
||||||
),
|
),
|
||||||
sectionLabel(AppLocalizations.of(context)!.other),
|
sectionLabel(AppLocalizations.of(context)!.other),
|
||||||
Material(
|
Material(
|
||||||
|
@ -187,6 +374,39 @@ class _AddServerModalState extends State<AddServerModal> {
|
||||||
const SizedBox(height: 20),
|
const SizedBox(height: 20),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
AnimatedOpacity(
|
||||||
|
opacity: isConnecting == true ? 1 : 0,
|
||||||
|
duration: const Duration(milliseconds: 250),
|
||||||
|
curve: Curves.easeInOut,
|
||||||
|
child: IgnorePointer(
|
||||||
|
ignoring: isConnecting == true ? false : true,
|
||||||
|
child: Scaffold(
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
body: Container(
|
||||||
|
width: mediaQuery.size.width,
|
||||||
|
height: mediaQuery.size.height,
|
||||||
|
color: const Color.fromRGBO(0, 0, 0, 0.7),
|
||||||
|
child: Column(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
const CircularProgressIndicator(
|
||||||
|
color: Colors.white,
|
||||||
|
),
|
||||||
|
const SizedBox(height: 30),
|
||||||
|
Text(
|
||||||
|
AppLocalizations.of(context)!.connecting,
|
||||||
|
style: const TextStyle(
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
|
fontSize: 26
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
14
pubspec.lock
14
pubspec.lock
|
@ -43,6 +43,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.16.0"
|
version: "1.16.0"
|
||||||
|
crypto:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: crypto
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.2"
|
||||||
cupertino_icons:
|
cupertino_icons:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -355,6 +362,13 @@ packages:
|
||||||
url: "https://pub.dartlang.org"
|
url: "https://pub.dartlang.org"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.1"
|
version: "1.3.1"
|
||||||
|
uuid:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: uuid
|
||||||
|
url: "https://pub.dartlang.org"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.6"
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -42,6 +42,7 @@ dependencies:
|
||||||
dynamic_color: ^1.5.4
|
dynamic_color: ^1.5.4
|
||||||
animations: ^2.0.5
|
animations: ^2.0.5
|
||||||
device_info_plus: ^4.1.2
|
device_info_plus: ^4.1.2
|
||||||
|
uuid: ^3.0.6
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
Loading…
Add table
Reference in a new issue