2022-09-26 18:49:41 +02:00
|
|
|
// ignore_for_file: use_build_context_synchronously
|
|
|
|
|
|
|
|
import 'package:provider/provider.dart';
|
2022-09-26 16:08:56 +02:00
|
|
|
import 'package:flutter/material.dart';
|
2022-09-26 18:49:41 +02:00
|
|
|
import 'package:uuid/uuid.dart';
|
2022-09-26 16:08:56 +02:00
|
|
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
|
|
|
|
|
|
|
import 'package:adguard_home_manager/widgets/custom_radio_toggle.dart';
|
|
|
|
|
2022-09-30 00:24:56 +02:00
|
|
|
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
|
|
|
import 'package:adguard_home_manager/functions/encode_base64.dart';
|
2022-09-26 18:49:41 +02:00
|
|
|
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';
|
2022-09-26 16:08:56 +02:00
|
|
|
import 'package:adguard_home_manager/config/system_overlay_style.dart';
|
|
|
|
|
|
|
|
class AddServerModal extends StatefulWidget {
|
2022-09-26 22:43:30 +02:00
|
|
|
final Server? server;
|
|
|
|
|
|
|
|
const AddServerModal({
|
|
|
|
Key? key,
|
|
|
|
this.server,
|
|
|
|
}) : super(key: key);
|
2022-09-26 16:08:56 +02:00
|
|
|
|
|
|
|
@override
|
|
|
|
State<AddServerModal> createState() => _AddServerModalState();
|
|
|
|
}
|
|
|
|
|
|
|
|
class _AddServerModalState extends State<AddServerModal> {
|
2022-09-26 18:49:41 +02:00
|
|
|
final uuid = const Uuid();
|
|
|
|
|
2022-09-26 16:08:56 +02:00
|
|
|
final TextEditingController nameController = TextEditingController();
|
2022-09-26 18:49:41 +02:00
|
|
|
String? nameError;
|
2022-09-26 16:08:56 +02:00
|
|
|
|
|
|
|
String connectionType = "http";
|
|
|
|
|
|
|
|
final TextEditingController ipDomainController = TextEditingController();
|
|
|
|
String? ipDomainError;
|
|
|
|
|
|
|
|
final TextEditingController pathController = TextEditingController();
|
|
|
|
String? pathError;
|
|
|
|
|
|
|
|
final TextEditingController portController = TextEditingController();
|
|
|
|
String? portError;
|
|
|
|
|
|
|
|
final TextEditingController userController = TextEditingController();
|
2022-09-28 01:25:04 +02:00
|
|
|
String? userError;
|
2022-09-26 16:08:56 +02:00
|
|
|
|
|
|
|
final TextEditingController passwordController = TextEditingController();
|
2022-09-28 01:25:04 +02:00
|
|
|
String? passwordError;
|
2022-09-26 16:08:56 +02:00
|
|
|
|
|
|
|
bool defaultServer = false;
|
|
|
|
|
2022-09-26 18:49:41 +02:00
|
|
|
bool allDataValid = false;
|
|
|
|
|
|
|
|
bool isConnecting = false;
|
|
|
|
|
2022-09-26 16:08:56 +02:00
|
|
|
Widget sectionLabel(String label) {
|
|
|
|
return Padding(
|
|
|
|
padding: const EdgeInsets.symmetric(
|
|
|
|
horizontal: 20,
|
|
|
|
vertical: 30
|
|
|
|
),
|
|
|
|
child: Text(
|
|
|
|
label,
|
|
|
|
style: const TextStyle(
|
|
|
|
fontSize: 16,
|
|
|
|
fontWeight: FontWeight.w500,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
Widget textField({
|
|
|
|
required String label,
|
|
|
|
required TextEditingController controller,
|
|
|
|
String? error,
|
|
|
|
required IconData icon,
|
2022-09-26 18:49:41 +02:00
|
|
|
TextInputType? keyboardType,
|
|
|
|
Function(String)? onChanged,
|
2022-09-28 01:25:04 +02:00
|
|
|
bool? obscureText,
|
|
|
|
String? hintText,
|
|
|
|
String? helperText
|
2022-09-26 16:08:56 +02:00
|
|
|
}) {
|
|
|
|
return Padding(
|
|
|
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
|
|
|
child: TextFormField(
|
|
|
|
controller: controller,
|
2022-09-26 18:49:41 +02:00
|
|
|
onChanged: onChanged,
|
2022-09-28 01:25:04 +02:00
|
|
|
obscureText: obscureText ?? false,
|
2022-09-26 16:08:56 +02:00
|
|
|
decoration: InputDecoration(
|
|
|
|
prefixIcon: Icon(icon),
|
|
|
|
errorText: error,
|
2022-09-28 01:25:04 +02:00
|
|
|
hintText: hintText,
|
|
|
|
helperText: helperText,
|
2022-09-26 16:08:56 +02:00
|
|
|
border: const OutlineInputBorder(
|
|
|
|
borderRadius: BorderRadius.all(
|
|
|
|
Radius.circular(10)
|
|
|
|
)
|
|
|
|
),
|
|
|
|
labelText: label,
|
|
|
|
),
|
|
|
|
keyboardType: keyboardType,
|
|
|
|
),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2022-09-26 18:49:41 +02:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2022-09-28 01:25:04 +02:00
|
|
|
void validateUser(String? value) {
|
|
|
|
if (value != null && value != '') {
|
|
|
|
setState(() {
|
|
|
|
userError = null;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
setState(() {
|
|
|
|
userError = AppLocalizations.of(context)!.userNotEmpty;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
checkDataValid();
|
|
|
|
}
|
|
|
|
|
|
|
|
void validatePassword(String? value) {
|
|
|
|
if (value != null && value != '') {
|
|
|
|
setState(() {
|
|
|
|
passwordError = null;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
setState(() {
|
|
|
|
passwordError = AppLocalizations.of(context)!.passwordNotEmpty;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
checkDataValid();
|
|
|
|
}
|
|
|
|
|
2022-09-26 22:43:30 +02:00
|
|
|
@override
|
|
|
|
void initState() {
|
|
|
|
if (widget.server != null) {
|
|
|
|
nameController.text = widget.server!.name;
|
|
|
|
connectionType = widget.server!.connectionMethod;
|
|
|
|
ipDomainController.text = widget.server!.domain;
|
|
|
|
pathController.text = widget.server!.path ?? '';
|
|
|
|
portController.text = widget.server!.port != null ? widget.server!.port.toString() : "";
|
|
|
|
userController.text = widget.server!.user;
|
|
|
|
passwordController.text = widget.server!.password;
|
|
|
|
defaultServer = widget.server!.defaultServer;
|
|
|
|
}
|
|
|
|
checkDataValid();
|
|
|
|
super.initState();
|
|
|
|
}
|
|
|
|
|
2022-09-26 16:08:56 +02:00
|
|
|
@override
|
|
|
|
Widget build(BuildContext context) {
|
2022-09-26 18:49:41 +02:00
|
|
|
final serversProvider = Provider.of<ServersProvider>(context, listen: false);
|
2022-09-30 00:24:56 +02:00
|
|
|
final appConfigProvider = Provider.of<AppConfigProvider>(context, listen: false);
|
2022-09-26 18:49:41 +02:00
|
|
|
|
|
|
|
final mediaQuery = MediaQuery.of(context);
|
|
|
|
|
|
|
|
void connect() async {
|
2022-09-27 02:38:59 +02:00
|
|
|
Server serverObj = Server(
|
2022-09-26 18:49:41 +02:00
|
|
|
id: uuid.v4(),
|
|
|
|
name: nameController.text,
|
|
|
|
connectionMethod: connectionType,
|
|
|
|
domain: ipDomainController.text,
|
|
|
|
port: int.parse(portController.text),
|
|
|
|
user: userController.text,
|
|
|
|
password: passwordController.text,
|
2022-09-27 02:38:59 +02:00
|
|
|
defaultServer: defaultServer,
|
|
|
|
authToken: ''
|
2022-09-26 18:49:41 +02:00
|
|
|
);
|
2022-09-26 22:43:30 +02:00
|
|
|
setState(() => isConnecting = true);
|
2022-09-26 18:49:41 +02:00
|
|
|
final result = await login(serverObj);
|
2022-09-26 22:43:30 +02:00
|
|
|
setState(() => isConnecting = false);
|
2022-09-26 18:49:41 +02:00
|
|
|
if (result['result'] == 'success') {
|
2022-09-27 02:38:59 +02:00
|
|
|
serverObj.authToken = encodeBase64UserPass(serverObj.user, serverObj.password);
|
2022-09-26 18:49:41 +02:00
|
|
|
final serverCreated = await serversProvider.createServer(serverObj);
|
|
|
|
if (serverCreated == true) {
|
2022-09-27 14:29:36 +02:00
|
|
|
serversProvider.setServerStatusLoad(0);
|
2022-09-27 12:43:25 +02:00
|
|
|
final serverStatus = await getServerStatus(serverObj);
|
|
|
|
if (serverStatus['result'] == 'success') {
|
2022-09-27 14:29:36 +02:00
|
|
|
serversProvider.setServerStatusData(serverStatus['data']);
|
|
|
|
serversProvider.setServerStatusLoad(1);
|
2022-09-27 02:38:59 +02:00
|
|
|
}
|
|
|
|
else {
|
2022-09-27 14:29:36 +02:00
|
|
|
serversProvider.setServerStatusLoad(2);
|
2022-09-27 02:38:59 +02:00
|
|
|
}
|
2022-09-26 18:49:41 +02:00
|
|
|
Navigator.pop(context);
|
|
|
|
}
|
|
|
|
else {
|
2022-09-30 00:24:56 +02:00
|
|
|
appConfigProvider.addLog({
|
|
|
|
'type': 'login',
|
|
|
|
'time': DateTime.now().toString(),
|
|
|
|
'message': result['message']
|
|
|
|
});
|
2022-09-26 18:49:41 +02:00
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
|
|
SnackBar(
|
|
|
|
content: Text(AppLocalizations.of(context)!.connectionNotCreated),
|
|
|
|
backgroundColor: Colors.red,
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2022-09-30 00:24:56 +02:00
|
|
|
else if (result['result'] == 'invalid_username_password') {
|
|
|
|
appConfigProvider.addLog({
|
|
|
|
'type': 'login',
|
|
|
|
'time': DateTime.now().toString(),
|
|
|
|
'message': result['message']
|
|
|
|
});
|
2022-09-26 18:49:41 +02:00
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
|
|
SnackBar(
|
|
|
|
content: Text(AppLocalizations.of(context)!.invalidUsernamePassword),
|
|
|
|
backgroundColor: Colors.red,
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
2022-09-30 00:24:56 +02:00
|
|
|
else if (result['result'] == 'many_attempts') {
|
|
|
|
appConfigProvider.addLog({
|
|
|
|
'type': 'login',
|
|
|
|
'time': DateTime.now().toString(),
|
|
|
|
'message': result['message']
|
|
|
|
});
|
2022-09-26 18:49:41 +02:00
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
|
|
SnackBar(
|
|
|
|
content: Text(AppLocalizations.of(context)!.tooManyAttempts),
|
|
|
|
backgroundColor: Colors.red,
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
2022-09-30 00:24:56 +02:00
|
|
|
else if (result['result'] == 'no_connection') {
|
|
|
|
appConfigProvider.addLog({
|
|
|
|
'type': 'login',
|
|
|
|
'time': DateTime.now().toString(),
|
|
|
|
'message': result['message']
|
|
|
|
});
|
2022-09-26 18:49:41 +02:00
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
|
|
SnackBar(
|
|
|
|
content: Text(AppLocalizations.of(context)!.cantReachServer),
|
|
|
|
backgroundColor: Colors.red,
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
2022-09-30 00:24:56 +02:00
|
|
|
else if (result['result'] == 'ssl_error') {
|
|
|
|
appConfigProvider.addLog({
|
|
|
|
'type': 'login',
|
|
|
|
'time': DateTime.now().toString(),
|
|
|
|
'message': result['message']
|
|
|
|
});
|
2022-09-26 18:49:41 +02:00
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
|
|
SnackBar(
|
|
|
|
content: Text(AppLocalizations.of(context)!.sslError),
|
|
|
|
backgroundColor: Colors.red,
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
else {
|
2022-09-30 00:24:56 +02:00
|
|
|
appConfigProvider.addLog({
|
|
|
|
'type': 'login',
|
|
|
|
'time': DateTime.now().toString(),
|
|
|
|
'message': result['message']
|
|
|
|
});
|
2022-09-26 18:49:41 +02:00
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
|
|
SnackBar(
|
|
|
|
content: Text(AppLocalizations.of(context)!.unknownError),
|
|
|
|
backgroundColor: Colors.red,
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-26 22:43:30 +02:00
|
|
|
void edit() async {
|
|
|
|
final Server serverObj = Server(
|
|
|
|
id: widget.server!.id,
|
|
|
|
name: nameController.text,
|
|
|
|
connectionMethod: connectionType,
|
|
|
|
domain: ipDomainController.text,
|
|
|
|
port: int.parse(portController.text),
|
|
|
|
user: userController.text,
|
|
|
|
password: passwordController.text,
|
2022-09-27 02:38:59 +02:00
|
|
|
defaultServer: defaultServer,
|
|
|
|
authToken: ''
|
2022-09-26 22:43:30 +02:00
|
|
|
);
|
|
|
|
final result = await login(serverObj);
|
|
|
|
if (result['result'] == 'success') {
|
2022-09-27 02:38:59 +02:00
|
|
|
serverObj.authToken = encodeBase64UserPass(serverObj.user, serverObj.password);
|
2022-09-26 22:43:30 +02:00
|
|
|
final serverSaved = await serversProvider.editServer(serverObj);
|
|
|
|
if (serverSaved == true) {
|
|
|
|
Navigator.pop(context);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ScaffoldMessenger.of(context).showSnackBar(
|
|
|
|
SnackBar(
|
|
|
|
content: Text(AppLocalizations.of(context)!.connectionNotUpdated),
|
|
|
|
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,
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-26 16:08:56 +02:00
|
|
|
return Stack(
|
|
|
|
children: [
|
|
|
|
Scaffold(
|
|
|
|
backgroundColor: Theme.of(context).dialogBackgroundColor,
|
|
|
|
appBar: AppBar(
|
|
|
|
systemOverlayStyle: systemUiOverlayStyleConfig(context),
|
|
|
|
title: Text(AppLocalizations.of(context)!.createConnection),
|
|
|
|
elevation: 5,
|
|
|
|
actions: [
|
|
|
|
Padding(
|
|
|
|
padding: const EdgeInsets.only(right: 10),
|
|
|
|
child: IconButton(
|
2022-09-26 22:43:30 +02:00
|
|
|
tooltip: widget.server == null
|
|
|
|
? AppLocalizations.of(context)!.connect
|
|
|
|
: AppLocalizations.of(context)!.save,
|
2022-09-26 18:49:41 +02:00
|
|
|
onPressed: allDataValid == true
|
2022-09-26 22:43:30 +02:00
|
|
|
? widget.server == null
|
|
|
|
? () => connect()
|
|
|
|
: () => edit()
|
2022-09-26 18:49:41 +02:00
|
|
|
: null,
|
2022-09-26 22:43:30 +02:00
|
|
|
icon: Icon(
|
|
|
|
widget.server == null
|
|
|
|
? Icons.login_rounded
|
|
|
|
: Icons.save_rounded
|
|
|
|
)
|
2022-09-26 16:08:56 +02:00
|
|
|
),
|
|
|
|
),
|
|
|
|
],
|
|
|
|
toolbarHeight: 70,
|
|
|
|
),
|
|
|
|
body: ListView(
|
|
|
|
children: [
|
|
|
|
sectionLabel(AppLocalizations.of(context)!.general),
|
|
|
|
textField(
|
|
|
|
label: AppLocalizations.of(context)!.name,
|
|
|
|
controller: nameController,
|
2022-09-26 18:49:41 +02:00
|
|
|
icon: Icons.badge_rounded,
|
|
|
|
error: nameError,
|
|
|
|
onChanged: (value) => value == ''
|
|
|
|
? setState(() => nameError = AppLocalizations.of(context)!.nameNotEmpty)
|
|
|
|
: setState(() => nameError = null)
|
2022-09-26 16:08:56 +02:00
|
|
|
),
|
|
|
|
sectionLabel(AppLocalizations.of(context)!.connection),
|
|
|
|
Row(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
|
|
children: [
|
|
|
|
CustomRadioToggle(
|
|
|
|
groupSelected: connectionType,
|
|
|
|
value: 'http',
|
|
|
|
label: 'HTTP',
|
|
|
|
onTap: (value) => setState(() => connectionType = value)
|
|
|
|
),
|
|
|
|
CustomRadioToggle(
|
|
|
|
groupSelected: connectionType,
|
|
|
|
value: 'https',
|
|
|
|
label: 'HTTPS',
|
|
|
|
onTap: (value) => setState(() => connectionType = value)
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
const SizedBox(height: 20),
|
|
|
|
textField(
|
|
|
|
label: AppLocalizations.of(context)!.ipDomain,
|
|
|
|
controller: ipDomainController,
|
|
|
|
icon: Icons.link_rounded,
|
|
|
|
error: ipDomainError,
|
2022-09-26 18:49:41 +02:00
|
|
|
keyboardType: TextInputType.url,
|
|
|
|
onChanged: validateAddress
|
2022-09-26 16:08:56 +02:00
|
|
|
),
|
|
|
|
const SizedBox(height: 20),
|
|
|
|
textField(
|
|
|
|
label: AppLocalizations.of(context)!.path,
|
|
|
|
controller: pathController,
|
|
|
|
icon: Icons.route_rounded,
|
2022-09-26 18:49:41 +02:00
|
|
|
error: pathError,
|
2022-09-28 01:25:04 +02:00
|
|
|
onChanged: validateSubroute,
|
|
|
|
hintText: AppLocalizations.of(context)!.examplePath,
|
|
|
|
helperText: AppLocalizations.of(context)!.helperPath,
|
2022-09-26 16:08:56 +02:00
|
|
|
),
|
|
|
|
const SizedBox(height: 20),
|
|
|
|
textField(
|
|
|
|
label: AppLocalizations.of(context)!.port,
|
|
|
|
controller: portController,
|
|
|
|
icon: Icons.numbers_rounded,
|
|
|
|
error: portError,
|
2022-09-26 18:49:41 +02:00
|
|
|
keyboardType: TextInputType.number,
|
|
|
|
onChanged: validatePort
|
2022-09-26 16:08:56 +02:00
|
|
|
),
|
|
|
|
sectionLabel(AppLocalizations.of(context)!.authentication),
|
|
|
|
textField(
|
|
|
|
label: AppLocalizations.of(context)!.username,
|
|
|
|
controller: userController,
|
|
|
|
icon: Icons.person_rounded,
|
2022-09-28 01:25:04 +02:00
|
|
|
onChanged: validateUser,
|
|
|
|
error: userError
|
2022-09-26 16:08:56 +02:00
|
|
|
),
|
|
|
|
const SizedBox(height: 20),
|
|
|
|
textField(
|
|
|
|
label: AppLocalizations.of(context)!.password,
|
|
|
|
controller: passwordController,
|
|
|
|
icon: Icons.lock_rounded,
|
2022-09-26 18:49:41 +02:00
|
|
|
keyboardType: TextInputType.visiblePassword,
|
2022-09-28 01:25:04 +02:00
|
|
|
onChanged: validatePassword,
|
|
|
|
error: passwordError,
|
|
|
|
obscureText: true
|
2022-09-26 16:08:56 +02:00
|
|
|
),
|
|
|
|
sectionLabel(AppLocalizations.of(context)!.other),
|
|
|
|
Material(
|
|
|
|
color: Colors.transparent,
|
|
|
|
child: InkWell(
|
2022-09-26 22:43:30 +02:00
|
|
|
onTap: widget.server == null
|
|
|
|
? () => setState(() => defaultServer = !defaultServer)
|
|
|
|
: null,
|
2022-09-26 16:08:56 +02:00
|
|
|
child: Padding(
|
|
|
|
padding: const EdgeInsets.symmetric(horizontal: 20),
|
|
|
|
child: Row(
|
|
|
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
|
|
children: [
|
|
|
|
Text(
|
|
|
|
AppLocalizations.of(context)!.defaultServer,
|
|
|
|
style: const TextStyle(
|
|
|
|
fontSize: 15,
|
|
|
|
),
|
|
|
|
),
|
|
|
|
Switch(
|
|
|
|
value: defaultServer,
|
2022-09-26 22:43:30 +02:00
|
|
|
onChanged: widget.server == null
|
|
|
|
? (value) => setState(() => defaultServer = value)
|
|
|
|
: null,
|
2022-09-26 16:08:56 +02:00
|
|
|
activeColor: Theme.of(context).primaryColor,
|
|
|
|
)
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
const SizedBox(height: 20),
|
|
|
|
],
|
|
|
|
),
|
2022-09-26 18:49:41 +02:00
|
|
|
),
|
|
|
|
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
|
|
|
|
),
|
|
|
|
)
|
|
|
|
],
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
|
|
|
),
|
2022-09-26 16:08:56 +02:00
|
|
|
)
|
|
|
|
],
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|