mirror of
https://github.com/JGeek00/adguard-home-manager.git
synced 2025-05-04 20:30:35 +00:00
Refactor add server form
This commit is contained in:
parent
1f1edf7d98
commit
2389e34571
10 changed files with 749 additions and 906 deletions
|
@ -4,6 +4,7 @@
|
|||
"connect": "Connect",
|
||||
"servers": "Servers",
|
||||
"createConnection": "Create connection",
|
||||
"editConnection": "Edit connection",
|
||||
"name": "Name",
|
||||
"ipDomain": "IP address or domain",
|
||||
"path": "Path",
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
"connect": "Conectar",
|
||||
"servers": "Servidores",
|
||||
"createConnection": "Crear conexión",
|
||||
"editConnection": "Editar conexión",
|
||||
"name": "Nombre",
|
||||
"ipDomain": "Dirección IP o dominio",
|
||||
"path": "Ruta",
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:adguard_home_manager/widgets/add_server_modal.dart';
|
||||
import 'package:adguard_home_manager/widgets/version_warning_modal.dart';
|
||||
import 'package:adguard_home_manager/widgets/add_server/add_server_functions.dart';
|
||||
|
||||
class FabConnect extends StatelessWidget {
|
||||
const FabConnect({Key? key}) : super(key: key);
|
||||
|
@ -12,37 +11,7 @@ class FabConnect extends StatelessWidget {
|
|||
|
||||
void openAddServerModal() async {
|
||||
await Future.delayed(const Duration(seconds: 0), (() => {
|
||||
if (width > 700) {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => AddServerModal(
|
||||
window: true,
|
||||
onUnsupportedVersion: (version) => showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => VersionWarningModal(
|
||||
version: version
|
||||
),
|
||||
barrierDismissible: false
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
else {
|
||||
Navigator.push(context, MaterialPageRoute(
|
||||
fullscreenDialog: true,
|
||||
builder: (BuildContext context) => AddServerModal(
|
||||
window: false,
|
||||
onUnsupportedVersion: (version) => showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => VersionWarningModal(
|
||||
version: version
|
||||
),
|
||||
barrierDismissible: false
|
||||
),
|
||||
)
|
||||
))
|
||||
}
|
||||
openServerFormModal(context: context, width: width)
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
|
@ -6,9 +6,8 @@ import 'package:flutter/rendering.dart';
|
|||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'package:adguard_home_manager/widgets/version_warning_modal.dart';
|
||||
import 'package:adguard_home_manager/widgets/add_server/add_server_functions.dart';
|
||||
import 'package:adguard_home_manager/widgets/servers_list/servers_list.dart';
|
||||
import 'package:adguard_home_manager/widgets/add_server_modal.dart';
|
||||
|
||||
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
||||
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||
|
@ -69,37 +68,7 @@ class _ServersState extends State<Servers> {
|
|||
|
||||
void openAddServerModal() async {
|
||||
await Future.delayed(const Duration(seconds: 0), (() => {
|
||||
if (width > 700) {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => AddServerModal(
|
||||
window: true,
|
||||
onUnsupportedVersion: (version) => showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => VersionWarningModal(
|
||||
version: version
|
||||
),
|
||||
barrierDismissible: false
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
else {
|
||||
Navigator.push(context, MaterialPageRoute(
|
||||
fullscreenDialog: true,
|
||||
builder: (BuildContext context) => AddServerModal(
|
||||
window: false,
|
||||
onUnsupportedVersion: (version) => showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => VersionWarningModal(
|
||||
version: version
|
||||
),
|
||||
barrierDismissible: false
|
||||
),
|
||||
)
|
||||
))
|
||||
}
|
||||
openServerFormModal(context: context, width: width)
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
120
lib/widgets/add_server/add_server_functions.dart
Normal file
120
lib/widgets/add_server/add_server_functions.dart
Normal file
|
@ -0,0 +1,120 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import 'package:adguard_home_manager/models/server.dart';
|
||||
import 'package:adguard_home_manager/widgets/add_server/add_server_modal.dart';
|
||||
import 'package:adguard_home_manager/widgets/version_warning_modal.dart';
|
||||
|
||||
bool checkDataValid({
|
||||
required TextEditingController nameController,
|
||||
required TextEditingController ipDomainController,
|
||||
required String? ipDomainError,
|
||||
required String? pathError,
|
||||
required String? portError,
|
||||
}) {
|
||||
if (
|
||||
nameController.text != '' &&
|
||||
ipDomainController.text != '' &&
|
||||
ipDomainError == null &&
|
||||
pathError == null &&
|
||||
portError == null
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String? validatePort({
|
||||
required String? value,
|
||||
required BuildContext context
|
||||
}) {
|
||||
if (value != null && value != '') {
|
||||
if (int.tryParse(value) != null && int.parse(value) <= 65535) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return AppLocalizations.of(context)!.invalidPort;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String? validateSubroute({
|
||||
required BuildContext context,
|
||||
required String? value
|
||||
}) {
|
||||
if (value != null && value != '') {
|
||||
RegExp subrouteRegexp = RegExp(r'^\/\b([A-Za-z0-9_\-~/]*)[^\/|\.|\:]$');
|
||||
if (subrouteRegexp.hasMatch(value) == true) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return AppLocalizations.of(context)!.invalidPath;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
String? validateAddress({
|
||||
required BuildContext context,
|
||||
required 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'^(([a-z0-9|-]+\.)*[a-z0-9|-]+\.[a-z]+)|((\w|-)+)$');
|
||||
if (ipAddress.hasMatch(value) == true || domain.hasMatch(value) == true) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
return AppLocalizations.of(context)!.invalidIpDomain;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return AppLocalizations.of(context)!.ipDomainNotEmpty;
|
||||
}
|
||||
}
|
||||
|
||||
void openServerFormModal({
|
||||
required BuildContext context,
|
||||
required double width,
|
||||
Server? server,
|
||||
}) {
|
||||
showGeneralDialog(
|
||||
context: context,
|
||||
barrierColor: width <= 700
|
||||
?Colors.transparent
|
||||
: Colors.black54,
|
||||
transitionBuilder: (context, anim1, anim2, child) {
|
||||
return SlideTransition(
|
||||
position: Tween(
|
||||
begin: const Offset(0, 1),
|
||||
end: const Offset(0, 0)
|
||||
).animate(
|
||||
CurvedAnimation(
|
||||
parent: anim1,
|
||||
curve: Curves.easeInOutCubicEmphasized
|
||||
)
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
pageBuilder: (context, animation, secondaryAnimation) => AddServerModal(
|
||||
fullScreen: width <= 700,
|
||||
server: server,
|
||||
onUnsupportedVersion: (version) => showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => VersionWarningModal(
|
||||
version: version
|
||||
),
|
||||
barrierDismissible: false
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
561
lib/widgets/add_server/add_server_modal.dart
Normal file
561
lib/widgets/add_server/add_server_modal.dart
Normal file
|
@ -0,0 +1,561 @@
|
|||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import 'package:adguard_home_manager/widgets/add_server/form_text_field.dart';
|
||||
import 'package:adguard_home_manager/widgets/add_server/add_server_functions.dart';
|
||||
|
||||
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||
import 'package:adguard_home_manager/functions/snackbar.dart';
|
||||
import 'package:adguard_home_manager/constants/urls.dart';
|
||||
import 'package:adguard_home_manager/functions/open_url.dart';
|
||||
import 'package:adguard_home_manager/constants/enums.dart';
|
||||
import 'package:adguard_home_manager/providers/status_provider.dart';
|
||||
import 'package:adguard_home_manager/functions/base64.dart';
|
||||
import 'package:adguard_home_manager/services/http_requests.dart';
|
||||
import 'package:adguard_home_manager/models/app_log.dart';
|
||||
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
||||
import 'package:adguard_home_manager/models/server.dart';
|
||||
|
||||
enum ConnectionType { http, https}
|
||||
|
||||
class AddServerModal extends StatefulWidget {
|
||||
final Server? server;
|
||||
final bool fullScreen;
|
||||
final void Function(String version) onUnsupportedVersion;
|
||||
|
||||
const AddServerModal({
|
||||
Key? key,
|
||||
this.server,
|
||||
required this.fullScreen,
|
||||
required this.onUnsupportedVersion
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<AddServerModal> createState() => _AddServerModalState();
|
||||
}
|
||||
|
||||
class _AddServerModalState extends State<AddServerModal> {
|
||||
final uuid = const Uuid();
|
||||
|
||||
final TextEditingController nameController = TextEditingController();
|
||||
String? nameError;
|
||||
|
||||
ConnectionType connectionType = ConnectionType.http;
|
||||
|
||||
final TextEditingController ipDomainController = TextEditingController();
|
||||
String? ipDomainError;
|
||||
|
||||
final TextEditingController pathController = TextEditingController();
|
||||
String? pathError;
|
||||
|
||||
final TextEditingController portController = TextEditingController();
|
||||
String? portError;
|
||||
|
||||
final TextEditingController userController = TextEditingController();
|
||||
|
||||
final TextEditingController passwordController = TextEditingController();
|
||||
|
||||
bool defaultServer = false;
|
||||
|
||||
bool homeAssistant = false;
|
||||
|
||||
bool allDataValid = false;
|
||||
|
||||
bool isConnecting = false;
|
||||
|
||||
Widget sectionLabel(String label) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 24,
|
||||
vertical: 24
|
||||
),
|
||||
child: Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.primary
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
if (widget.server != null) {
|
||||
nameController.text = widget.server!.name;
|
||||
connectionType = widget.server!.connectionMethod == 'https' ? ConnectionType.https : ConnectionType.http;
|
||||
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;
|
||||
homeAssistant = widget.server!.runningOnHa;
|
||||
}
|
||||
setState(() => allDataValid = checkDataValid(
|
||||
ipDomainController: ipDomainController,
|
||||
nameController: nameController,
|
||||
ipDomainError: ipDomainError,
|
||||
pathError: pathError,
|
||||
portError: portError
|
||||
));
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final serversProvider = Provider.of<ServersProvider>(context, listen: false);
|
||||
final statusProvider = Provider.of<StatusProvider>(context, listen: false);
|
||||
final appConfigProvider = Provider.of<AppConfigProvider>(context, listen: false);
|
||||
|
||||
void cancelConnecting() {
|
||||
if (mounted) {
|
||||
setState(() => isConnecting = false);
|
||||
}
|
||||
else {
|
||||
isConnecting = false;
|
||||
}
|
||||
}
|
||||
|
||||
void validateData() {
|
||||
setState(() => allDataValid = checkDataValid(
|
||||
ipDomainController: ipDomainController,
|
||||
nameController: nameController,
|
||||
ipDomainError: ipDomainError,
|
||||
pathError: pathError,
|
||||
portError: portError
|
||||
));
|
||||
}
|
||||
|
||||
String getErrorMessage(String message) {
|
||||
if (message == 'invalid_username_password') return AppLocalizations.of(context)!.invalidUsernamePassword;
|
||||
if (message == 'many_attempts') return AppLocalizations.of(context)!.tooManyAttempts;
|
||||
if (message == 'no_connection') return AppLocalizations.of(context)!.cantReachServer;
|
||||
if (message == 'server_error') return AppLocalizations.of(context)!.serverError;
|
||||
return AppLocalizations.of(context)!.unknownError;
|
||||
}
|
||||
|
||||
void connect() async {
|
||||
Server serverObj = Server(
|
||||
id: uuid.v4(),
|
||||
name: nameController.text,
|
||||
connectionMethod: connectionType.name,
|
||||
domain: ipDomainController.text,
|
||||
port: portController.text != '' ? int.parse(portController.text) : null,
|
||||
user: userController.text != "" ? userController.text : null,
|
||||
password: passwordController.text != "" ? passwordController.text : null,
|
||||
defaultServer: defaultServer,
|
||||
authToken: homeAssistant == true
|
||||
? encodeBase64UserPass(userController.text, passwordController.text)
|
||||
: null,
|
||||
runningOnHa: homeAssistant
|
||||
);
|
||||
setState(() => isConnecting = true);
|
||||
|
||||
final result = homeAssistant == true
|
||||
? await loginHA(serverObj)
|
||||
: await login(serverObj);
|
||||
|
||||
// If something goes wrong with the connection
|
||||
if (result['result'] != 'success') {
|
||||
cancelConnecting();
|
||||
appConfigProvider.addLog(result['log']);
|
||||
if (mounted) {
|
||||
return showSnacbkar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: getErrorMessage(result['result']),
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (serverObj.user != null && serverObj.password != null) {
|
||||
serverObj.authToken = encodeBase64UserPass(serverObj.user!, serverObj.password!);
|
||||
}
|
||||
|
||||
final serverCreated = await serversProvider.createServer(serverObj);
|
||||
|
||||
// If something goes wrong when saving the connection on the db
|
||||
if (serverCreated == null) {
|
||||
if (mounted) setState(() => isConnecting = false);
|
||||
appConfigProvider.addLog(
|
||||
AppLog(
|
||||
type: 'save_connection_db',
|
||||
dateTime: DateTime.now(),
|
||||
message: serverCreated.toString()
|
||||
)
|
||||
);
|
||||
if (mounted) {
|
||||
showSnacbkar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.connectionNotCreated,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
statusProvider.setServerStatusLoad(LoadStatus.loading);
|
||||
final ApiClient apiClient = ApiClient(server: serverObj);
|
||||
final serverStatus = await apiClient.getServerStatus();
|
||||
|
||||
// If something goes wrong when fetching server status
|
||||
if (serverStatus['result'] != 'success') {
|
||||
appConfigProvider.addLog(serverStatus['log']);
|
||||
statusProvider.setServerStatusLoad(LoadStatus.error);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
|
||||
// If everything is successful
|
||||
statusProvider.setServerStatusData(
|
||||
data: serverStatus['data']
|
||||
);
|
||||
serversProvider.setApiClient(apiClient);
|
||||
statusProvider.setServerStatusLoad(LoadStatus.loaded);
|
||||
if (serverStatus['data'].serverVersion.contains('a') || serverStatus['data'].serverVersion.contains('b')) {
|
||||
Navigator.pop(context);
|
||||
widget.onUnsupportedVersion(serverStatus['data'].serverVersion);
|
||||
}
|
||||
else {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
}
|
||||
|
||||
void edit() async {
|
||||
final Server serverObj = Server(
|
||||
id: widget.server!.id,
|
||||
name: nameController.text,
|
||||
connectionMethod: connectionType.name,
|
||||
domain: ipDomainController.text,
|
||||
port: portController.text != '' ? int.parse(portController.text) : null,
|
||||
user: userController.text != "" ? userController.text : null,
|
||||
password: passwordController.text != "" ? passwordController.text : null,
|
||||
defaultServer: defaultServer,
|
||||
authToken: homeAssistant == true
|
||||
? encodeBase64UserPass(userController.text, passwordController.text)
|
||||
: null,
|
||||
runningOnHa: homeAssistant
|
||||
);
|
||||
|
||||
final result = homeAssistant == true
|
||||
? await loginHA(serverObj)
|
||||
: await login(serverObj);
|
||||
|
||||
// If something goes wrong with the connection
|
||||
if (result['result'] != 'success') {
|
||||
cancelConnecting();
|
||||
appConfigProvider.addLog(result['log']);
|
||||
if (mounted) {
|
||||
return showSnacbkar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: getErrorMessage(result['result']),
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (serverObj.user != null && serverObj.password != null) {
|
||||
serverObj.authToken = encodeBase64UserPass(serverObj.user!, serverObj.password!);
|
||||
}
|
||||
final serverSaved = await serversProvider.editServer(serverObj);
|
||||
|
||||
// If something goes wrong when saving the connection on the db
|
||||
if (serverSaved == null) {
|
||||
if (mounted) setState(() => isConnecting = false);
|
||||
appConfigProvider.addLog(
|
||||
AppLog(
|
||||
type: 'save_connection_db',
|
||||
dateTime: DateTime.now(),
|
||||
message: serverSaved.toString()
|
||||
)
|
||||
);
|
||||
if (mounted) {
|
||||
showSnacbkar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.connectionNotCreated,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// If everything is successful
|
||||
final ApiClient apiClient = ApiClient(server: serverObj);
|
||||
final version = await apiClient.getServerVersion();
|
||||
if (
|
||||
version['result'] == 'success' &&
|
||||
(version['data'].contains('a') || version['data'].contains('b')) // alpha or beta
|
||||
) {
|
||||
Navigator.pop(context);
|
||||
widget.onUnsupportedVersion(version['data']);
|
||||
}
|
||||
else {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
}
|
||||
|
||||
Widget actions() {
|
||||
return Row(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () => openUrl(Urls.connectionInstructions),
|
||||
icon: const Icon(Icons.help_outline_outlined)
|
||||
),
|
||||
IconButton(
|
||||
tooltip: widget.server == null
|
||||
? AppLocalizations.of(context)!.connect
|
||||
: AppLocalizations.of(context)!.save,
|
||||
onPressed: allDataValid == true && isConnecting == false
|
||||
? widget.server == null
|
||||
? () => connect()
|
||||
: () => edit()
|
||||
: null,
|
||||
icon: isConnecting
|
||||
? const CircularProgressIndicator()
|
||||
: Icon(
|
||||
widget.server == null
|
||||
? Icons.login_rounded
|
||||
: Icons.save_rounded
|
||||
)
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
List<Widget> form() {
|
||||
return [
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
||||
margin: const EdgeInsets.only(
|
||||
top: 24,
|
||||
left: 24,
|
||||
right: 24
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.primary.withOpacity(0.05),
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
border: Border.all(
|
||||
color: Theme.of(context).colorScheme.primary
|
||||
)
|
||||
),
|
||||
child: Text(
|
||||
"${connectionType.name}://${ipDomainController.text}${portController.text != '' ? ':${portController.text}' : ""}${pathController.text}",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
fontWeight: FontWeight.w500
|
||||
),
|
||||
),
|
||||
),
|
||||
sectionLabel(AppLocalizations.of(context)!.general),
|
||||
FormTextField(
|
||||
label: AppLocalizations.of(context)!.name,
|
||||
controller: nameController,
|
||||
icon: Icons.badge_rounded,
|
||||
error: nameError,
|
||||
onChanged: (value) {
|
||||
if (value != '') {
|
||||
setState(() => nameError = null);
|
||||
}
|
||||
else {
|
||||
setState(() => nameError = AppLocalizations.of(context)!.nameNotEmpty);
|
||||
}
|
||||
validateData();
|
||||
},
|
||||
isConnecting: isConnecting,
|
||||
),
|
||||
sectionLabel(AppLocalizations.of(context)!.connection),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: SegmentedButton<ConnectionType>(
|
||||
segments: const [
|
||||
ButtonSegment(
|
||||
value: ConnectionType.http,
|
||||
label: Text("HTTP")
|
||||
),
|
||||
ButtonSegment(
|
||||
value: ConnectionType.https,
|
||||
label: Text("HTTPS")
|
||||
),
|
||||
],
|
||||
selected: <ConnectionType>{connectionType},
|
||||
onSelectionChanged: (value) => setState(() => connectionType = value.first),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
FormTextField(
|
||||
label: AppLocalizations.of(context)!.ipDomain,
|
||||
controller: ipDomainController,
|
||||
icon: Icons.link_rounded,
|
||||
error: ipDomainError,
|
||||
keyboardType: TextInputType.url,
|
||||
onChanged: (v) {
|
||||
setState(() => ipDomainError = validateAddress(context: context, value: v));
|
||||
validateData();
|
||||
},
|
||||
isConnecting: isConnecting,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
FormTextField(
|
||||
label: AppLocalizations.of(context)!.path,
|
||||
controller: pathController,
|
||||
icon: Icons.route_rounded,
|
||||
error: pathError,
|
||||
onChanged: (v) {
|
||||
setState(() => pathError = validateSubroute(context: context, value: v));
|
||||
validateData();
|
||||
},
|
||||
hintText: AppLocalizations.of(context)!.examplePath,
|
||||
helperText: AppLocalizations.of(context)!.helperPath,
|
||||
isConnecting: isConnecting,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
FormTextField(
|
||||
label: AppLocalizations.of(context)!.port,
|
||||
controller: portController,
|
||||
icon: Icons.numbers_rounded,
|
||||
error: portError,
|
||||
keyboardType: TextInputType.number,
|
||||
onChanged: (v) {
|
||||
setState(() => portError = validatePort(context: context, value: v));
|
||||
validateData();
|
||||
},
|
||||
isConnecting: isConnecting,
|
||||
),
|
||||
sectionLabel(AppLocalizations.of(context)!.authentication),
|
||||
FormTextField(
|
||||
label: AppLocalizations.of(context)!.username,
|
||||
controller: userController,
|
||||
icon: Icons.person_rounded,
|
||||
isConnecting: isConnecting,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
FormTextField(
|
||||
label: AppLocalizations.of(context)!.password,
|
||||
controller: passwordController,
|
||||
icon: Icons.lock_rounded,
|
||||
keyboardType: TextInputType.visiblePassword,
|
||||
obscureText: true,
|
||||
isConnecting: isConnecting,
|
||||
),
|
||||
sectionLabel(AppLocalizations.of(context)!.other),
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: widget.server == null
|
||||
? () => setState(() => defaultServer = !defaultServer)
|
||||
: null,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
AppLocalizations.of(context)!.defaultServer,
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
Switch(
|
||||
value: defaultServer,
|
||||
onChanged: widget.server == null
|
||||
? (value) => setState(() => defaultServer = value)
|
||||
: null,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: () => setState(() => homeAssistant = !homeAssistant),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
AppLocalizations.of(context)!.runningHomeAssistant,
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
Switch(
|
||||
value: homeAssistant,
|
||||
onChanged: (value) => setState(() => homeAssistant = value),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
];
|
||||
}
|
||||
|
||||
if (widget.fullScreen == true) {
|
||||
return Dialog.fullscreen(
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: widget.server != null
|
||||
? Text(AppLocalizations.of(context)!.createConnection)
|
||||
: Text(AppLocalizations.of(context)!.editConnection),
|
||||
actions: [
|
||||
actions(),
|
||||
const SizedBox(width: 8)
|
||||
],
|
||||
),
|
||||
body: ListView(
|
||||
children: form()
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
else {
|
||||
return Dialog(
|
||||
child: SizedBox(
|
||||
width: 400,
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
icon: const Icon(Icons.clear_rounded)
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
AppLocalizations.of(context)!.createConnection,
|
||||
style: const TextStyle(
|
||||
fontSize: 20
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions()
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ListView(
|
||||
children: form()
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
54
lib/widgets/add_server/form_text_field.dart
Normal file
54
lib/widgets/add_server/form_text_field.dart
Normal file
|
@ -0,0 +1,54 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class FormTextField extends StatelessWidget {
|
||||
final TextEditingController controller;
|
||||
final String label;
|
||||
final String? error;
|
||||
final IconData icon;
|
||||
final TextInputType? keyboardType;
|
||||
final Function(String)? onChanged;
|
||||
final bool? obscureText;
|
||||
final String? hintText;
|
||||
final String? helperText;
|
||||
final bool isConnecting;
|
||||
|
||||
const FormTextField({
|
||||
Key? key,
|
||||
required this.label,
|
||||
required this.controller,
|
||||
this.error,
|
||||
required this.icon,
|
||||
this.keyboardType,
|
||||
this.onChanged,
|
||||
this.obscureText,
|
||||
this.hintText,
|
||||
this.helperText,
|
||||
required this.isConnecting
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: TextFormField(
|
||||
controller: controller,
|
||||
onChanged: onChanged,
|
||||
obscureText: obscureText ?? false,
|
||||
enabled: !isConnecting,
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: Icon(icon),
|
||||
errorText: error,
|
||||
hintText: hintText,
|
||||
helperText: helperText,
|
||||
border: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(10)
|
||||
)
|
||||
),
|
||||
labelText: label,
|
||||
),
|
||||
keyboardType: keyboardType,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,766 +0,0 @@
|
|||
// ignore_for_file: use_build_context_synchronously
|
||||
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:uuid/uuid.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import 'package:adguard_home_manager/providers/app_config_provider.dart';
|
||||
import 'package:adguard_home_manager/functions/snackbar.dart';
|
||||
import 'package:adguard_home_manager/constants/urls.dart';
|
||||
import 'package:adguard_home_manager/functions/open_url.dart';
|
||||
import 'package:adguard_home_manager/constants/enums.dart';
|
||||
import 'package:adguard_home_manager/providers/status_provider.dart';
|
||||
import 'package:adguard_home_manager/functions/base64.dart';
|
||||
import 'package:adguard_home_manager/services/http_requests.dart';
|
||||
import 'package:adguard_home_manager/models/app_log.dart';
|
||||
import 'package:adguard_home_manager/providers/servers_provider.dart';
|
||||
import 'package:adguard_home_manager/models/server.dart';
|
||||
|
||||
enum ConnectionType { http, https}
|
||||
|
||||
class AddServerModal extends StatefulWidget {
|
||||
final Server? server;
|
||||
final bool window;
|
||||
final void Function(String version) onUnsupportedVersion;
|
||||
|
||||
const AddServerModal({
|
||||
Key? key,
|
||||
this.server,
|
||||
required this.window,
|
||||
required this.onUnsupportedVersion
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<AddServerModal> createState() => _AddServerModalState();
|
||||
}
|
||||
|
||||
class _AddServerModalState extends State<AddServerModal> {
|
||||
final uuid = const Uuid();
|
||||
|
||||
final TextEditingController nameController = TextEditingController();
|
||||
String? nameError;
|
||||
|
||||
ConnectionType connectionType = ConnectionType.http;
|
||||
|
||||
final TextEditingController ipDomainController = TextEditingController();
|
||||
String? ipDomainError;
|
||||
|
||||
final TextEditingController pathController = TextEditingController();
|
||||
String? pathError;
|
||||
|
||||
final TextEditingController portController = TextEditingController();
|
||||
String? portError;
|
||||
|
||||
final TextEditingController userController = TextEditingController();
|
||||
|
||||
final TextEditingController passwordController = TextEditingController();
|
||||
|
||||
bool defaultServer = false;
|
||||
|
||||
bool homeAssistant = false;
|
||||
|
||||
bool allDataValid = false;
|
||||
|
||||
bool isConnecting = false;
|
||||
|
||||
Widget sectionLabel(String label) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 24,
|
||||
vertical: 24
|
||||
),
|
||||
child: Text(
|
||||
label,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.primary
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget textField({
|
||||
required String label,
|
||||
required TextEditingController controller,
|
||||
String? error,
|
||||
required IconData icon,
|
||||
TextInputType? keyboardType,
|
||||
Function(String)? onChanged,
|
||||
bool? obscureText,
|
||||
String? hintText,
|
||||
String? helperText
|
||||
}) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: TextFormField(
|
||||
controller: controller,
|
||||
onChanged: onChanged,
|
||||
obscureText: obscureText ?? false,
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: Icon(icon),
|
||||
errorText: error,
|
||||
hintText: hintText,
|
||||
helperText: helperText,
|
||||
border: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(
|
||||
Radius.circular(10)
|
||||
)
|
||||
),
|
||||
labelText: label,
|
||||
),
|
||||
keyboardType: keyboardType,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void checkDataValid() {
|
||||
if (
|
||||
nameController.text != '' &&
|
||||
ipDomainController.text != '' &&
|
||||
ipDomainError == null &&
|
||||
pathError == null &&
|
||||
portError == null
|
||||
) {
|
||||
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'^(([a-z0-9|-]+\.)*[a-z0-9|-]+\.[a-z]+)|((\w|-)+)$');
|
||||
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
|
||||
void initState() {
|
||||
if (widget.server != null) {
|
||||
nameController.text = widget.server!.name;
|
||||
connectionType = widget.server!.connectionMethod == 'https' ? ConnectionType.https : ConnectionType.http;
|
||||
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;
|
||||
homeAssistant = widget.server!.runningOnHa;
|
||||
}
|
||||
checkDataValid();
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final serversProvider = Provider.of<ServersProvider>(context, listen: false);
|
||||
final statusProvider = Provider.of<StatusProvider>(context, listen: false);
|
||||
final appConfigProvider = Provider.of<AppConfigProvider>(context, listen: false);
|
||||
|
||||
final mediaQuery = MediaQuery.of(context);
|
||||
|
||||
void cancelConnecting() {
|
||||
if (mounted) {
|
||||
setState(() => isConnecting = false);
|
||||
}
|
||||
else {
|
||||
isConnecting = false;
|
||||
}
|
||||
}
|
||||
|
||||
void connect() async {
|
||||
Server serverObj = Server(
|
||||
id: uuid.v4(),
|
||||
name: nameController.text,
|
||||
connectionMethod: connectionType.name,
|
||||
domain: ipDomainController.text,
|
||||
port: portController.text != '' ? int.parse(portController.text) : null,
|
||||
user: userController.text != "" ? userController.text : null,
|
||||
password: passwordController.text != "" ? passwordController.text : null,
|
||||
defaultServer: defaultServer,
|
||||
authToken: homeAssistant == true
|
||||
? encodeBase64UserPass(userController.text, passwordController.text)
|
||||
: null,
|
||||
runningOnHa: homeAssistant
|
||||
);
|
||||
setState(() => isConnecting = true);
|
||||
|
||||
final result = homeAssistant == true
|
||||
? await loginHA(serverObj)
|
||||
: await login(serverObj);
|
||||
|
||||
if (!mounted) return;
|
||||
|
||||
if (result['result'] == 'success') {
|
||||
if (serverObj.user != null && serverObj.password != null) {
|
||||
serverObj.authToken = encodeBase64UserPass(serverObj.user!, serverObj.password!);
|
||||
}
|
||||
final serverCreated = await serversProvider.createServer(serverObj);
|
||||
if (serverCreated == null) {
|
||||
statusProvider.setServerStatusLoad(LoadStatus.loading);
|
||||
|
||||
final ApiClient apiClient = ApiClient(server: serverObj);
|
||||
|
||||
final serverStatus = await apiClient.getServerStatus();
|
||||
|
||||
if (!mounted) return;
|
||||
|
||||
if (serverStatus['result'] == 'success') {
|
||||
statusProvider.setServerStatusData(
|
||||
data: serverStatus['data']
|
||||
);
|
||||
serversProvider.setApiClient(apiClient);
|
||||
statusProvider.setServerStatusLoad(LoadStatus.loaded);
|
||||
if (serverStatus['data'].serverVersion.contains('a') || serverStatus['data'].serverVersion.contains('b')) {
|
||||
Navigator.pop(context);
|
||||
widget.onUnsupportedVersion(serverStatus['data'].serverVersion);
|
||||
}
|
||||
else {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
}
|
||||
else {
|
||||
appConfigProvider.addLog(serverStatus['log']);
|
||||
statusProvider.setServerStatusLoad(LoadStatus.error);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
}
|
||||
else {
|
||||
setState(() => isConnecting = false);
|
||||
appConfigProvider.addLog(
|
||||
AppLog(
|
||||
type: 'save_connection_db',
|
||||
dateTime: DateTime.now(),
|
||||
message: serverCreated.toString()
|
||||
)
|
||||
);
|
||||
showSnacbkar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.connectionNotCreated,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
}
|
||||
else if (result['result'] == 'invalid_username_password') {
|
||||
cancelConnecting();
|
||||
appConfigProvider.addLog(result['log']);
|
||||
showSnacbkar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.invalidUsernamePassword,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
else if (result['result'] == 'many_attempts') {
|
||||
cancelConnecting();
|
||||
appConfigProvider.addLog(result['log']);
|
||||
showSnacbkar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.tooManyAttempts,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
else if (result['result'] == 'no_connection') {
|
||||
cancelConnecting();
|
||||
appConfigProvider.addLog(result['log']);
|
||||
showSnacbkar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.cantReachServer,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
else if (result['result'] == 'ssl_error') {
|
||||
cancelConnecting();
|
||||
appConfigProvider.addLog(result['log']);
|
||||
showSnacbkar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.sslError,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
else if (result['result'] == 'server_error') {
|
||||
cancelConnecting();
|
||||
appConfigProvider.addLog(result['log']);
|
||||
showSnacbkar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.serverError,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
else {
|
||||
cancelConnecting();
|
||||
appConfigProvider.addLog(result['log']);
|
||||
showSnacbkar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.unknownError,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void edit() async {
|
||||
final Server serverObj = Server(
|
||||
id: widget.server!.id,
|
||||
name: nameController.text,
|
||||
connectionMethod: connectionType.name,
|
||||
domain: ipDomainController.text,
|
||||
port: portController.text != '' ? int.parse(portController.text) : null,
|
||||
user: userController.text != "" ? userController.text : null,
|
||||
password: passwordController.text != "" ? passwordController.text : null,
|
||||
defaultServer: defaultServer,
|
||||
authToken: homeAssistant == true
|
||||
? encodeBase64UserPass(userController.text, passwordController.text)
|
||||
: null,
|
||||
runningOnHa: homeAssistant
|
||||
);
|
||||
|
||||
final result = homeAssistant == true
|
||||
? await loginHA(serverObj)
|
||||
: await login(serverObj);
|
||||
|
||||
if (!mounted) return;
|
||||
if (result['result'] == 'success') {
|
||||
if (serverObj.user != null && serverObj.password != null) {
|
||||
serverObj.authToken = encodeBase64UserPass(serverObj.user!, serverObj.password!);
|
||||
}
|
||||
final serverSaved = await serversProvider.editServer(serverObj);
|
||||
|
||||
if (!mounted) return;
|
||||
if (serverSaved == null) {
|
||||
final ApiClient apiClient = ApiClient(server: serverObj);
|
||||
final version = await apiClient.getServerVersion();
|
||||
if (
|
||||
version['result'] == 'success' &&
|
||||
(version['data'].contains('a') || version['data'].contains('b')) // alpha or beta
|
||||
) {
|
||||
Navigator.pop(context);
|
||||
widget.onUnsupportedVersion(version['data']);
|
||||
}
|
||||
else {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
}
|
||||
else {
|
||||
appConfigProvider.addLog(
|
||||
AppLog(
|
||||
type: 'edit_connection_db',
|
||||
dateTime: DateTime.now(),
|
||||
message: serverSaved.toString()
|
||||
)
|
||||
);
|
||||
showSnacbkar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.connectionNotCreated,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
}
|
||||
else if (result['result'] == 'invalid_username_password') {
|
||||
appConfigProvider.addLog(result['log']);
|
||||
showSnacbkar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.invalidUsernamePassword,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
else if (result['result'] == 'many_attempts') {
|
||||
appConfigProvider.addLog(result['log']);
|
||||
showSnacbkar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.tooManyAttempts,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
else if (result['result'] == 'no_connection') {
|
||||
appConfigProvider.addLog(result['log']);
|
||||
showSnacbkar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.cantReachServer,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
else if (result['result'] == 'ssl_error') {
|
||||
appConfigProvider.addLog(result['log']);
|
||||
showSnacbkar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.sslError,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
else if (result['result'] == 'server_error') {
|
||||
appConfigProvider.addLog(result['log']);
|
||||
showSnacbkar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.serverError,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
else {
|
||||
appConfigProvider.addLog(result['log']);
|
||||
showSnacbkar(
|
||||
appConfigProvider: appConfigProvider,
|
||||
label: AppLocalizations.of(context)!.unknownError,
|
||||
color: Colors.red
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
List<Widget> form() {
|
||||
return [
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
|
||||
margin: const EdgeInsets.only(
|
||||
top: 24,
|
||||
left: 24,
|
||||
right: 24
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.primary.withOpacity(0.05),
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
border: Border.all(
|
||||
color: Theme.of(context).colorScheme.primary
|
||||
)
|
||||
),
|
||||
child: Text(
|
||||
"${connectionType.name}://${ipDomainController.text}${portController.text != '' ? ':${portController.text}' : ""}${pathController.text}",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
fontWeight: FontWeight.w500
|
||||
),
|
||||
),
|
||||
),
|
||||
sectionLabel(AppLocalizations.of(context)!.general),
|
||||
textField(
|
||||
label: AppLocalizations.of(context)!.name,
|
||||
controller: nameController,
|
||||
icon: Icons.badge_rounded,
|
||||
error: nameError,
|
||||
onChanged: (value) {
|
||||
if (value != '') {
|
||||
setState(() => nameError = null);
|
||||
}
|
||||
else {
|
||||
setState(() => nameError = AppLocalizations.of(context)!.nameNotEmpty);
|
||||
}
|
||||
checkDataValid();
|
||||
}
|
||||
),
|
||||
sectionLabel(AppLocalizations.of(context)!.connection),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: SegmentedButton<ConnectionType>(
|
||||
segments: const [
|
||||
ButtonSegment(
|
||||
value: ConnectionType.http,
|
||||
label: Text("HTTP")
|
||||
),
|
||||
ButtonSegment(
|
||||
value: ConnectionType.https,
|
||||
label: Text("HTTPS")
|
||||
),
|
||||
],
|
||||
selected: <ConnectionType>{connectionType},
|
||||
onSelectionChanged: (value) => setState(() => connectionType = value.first),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 30),
|
||||
textField(
|
||||
label: AppLocalizations.of(context)!.ipDomain,
|
||||
controller: ipDomainController,
|
||||
icon: Icons.link_rounded,
|
||||
error: ipDomainError,
|
||||
keyboardType: TextInputType.url,
|
||||
onChanged: validateAddress
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
textField(
|
||||
label: AppLocalizations.of(context)!.path,
|
||||
controller: pathController,
|
||||
icon: Icons.route_rounded,
|
||||
error: pathError,
|
||||
onChanged: validateSubroute,
|
||||
hintText: AppLocalizations.of(context)!.examplePath,
|
||||
helperText: AppLocalizations.of(context)!.helperPath,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
textField(
|
||||
label: AppLocalizations.of(context)!.port,
|
||||
controller: portController,
|
||||
icon: Icons.numbers_rounded,
|
||||
error: portError,
|
||||
keyboardType: TextInputType.number,
|
||||
onChanged: validatePort
|
||||
),
|
||||
sectionLabel(AppLocalizations.of(context)!.authentication),
|
||||
textField(
|
||||
label: AppLocalizations.of(context)!.username,
|
||||
controller: userController,
|
||||
icon: Icons.person_rounded,
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
textField(
|
||||
label: AppLocalizations.of(context)!.password,
|
||||
controller: passwordController,
|
||||
icon: Icons.lock_rounded,
|
||||
keyboardType: TextInputType.visiblePassword,
|
||||
obscureText: true
|
||||
),
|
||||
sectionLabel(AppLocalizations.of(context)!.other),
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: widget.server == null
|
||||
? () => setState(() => defaultServer = !defaultServer)
|
||||
: null,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
AppLocalizations.of(context)!.defaultServer,
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
Switch(
|
||||
value: defaultServer,
|
||||
onChanged: widget.server == null
|
||||
? (value) => setState(() => defaultServer = value)
|
||||
: null,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
onTap: () => setState(() => homeAssistant = !homeAssistant),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
AppLocalizations.of(context)!.runningHomeAssistant,
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
Switch(
|
||||
value: homeAssistant,
|
||||
onChanged: (value) => setState(() => homeAssistant = value),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
];
|
||||
}
|
||||
|
||||
if (widget.window == true) {
|
||||
return Dialog(
|
||||
child: SizedBox(
|
||||
width: 400,
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
icon: const Icon(Icons.clear_rounded)
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
AppLocalizations.of(context)!.createConnection,
|
||||
style: const TextStyle(
|
||||
fontSize: 20
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () => openUrl(Urls.connectionInstructions),
|
||||
icon: const Icon(Icons.help_outline_outlined)
|
||||
),
|
||||
IconButton(
|
||||
tooltip: widget.server == null
|
||||
? AppLocalizations.of(context)!.connect
|
||||
: AppLocalizations.of(context)!.save,
|
||||
onPressed: allDataValid == true
|
||||
? widget.server == null
|
||||
? () => connect()
|
||||
: () => edit()
|
||||
: null,
|
||||
icon: Icon(
|
||||
widget.server == null
|
||||
? Icons.login_rounded
|
||||
: Icons.save_rounded
|
||||
)
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ListView(
|
||||
children: form()
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
else {
|
||||
return Stack(
|
||||
children: [
|
||||
Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(AppLocalizations.of(context)!.createConnection),
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: () => openUrl(Urls.connectionInstructions),
|
||||
icon: const Icon(Icons.help_outline_outlined)
|
||||
),
|
||||
IconButton(
|
||||
tooltip: widget.server == null
|
||||
? AppLocalizations.of(context)!.connect
|
||||
: AppLocalizations.of(context)!.save,
|
||||
onPressed: allDataValid == true
|
||||
? widget.server == null
|
||||
? () => connect()
|
||||
: () => edit()
|
||||
: null,
|
||||
icon: Icon(
|
||||
widget.server == null
|
||||
? Icons.login_rounded
|
||||
: Icons.save_rounded
|
||||
)
|
||||
),
|
||||
const SizedBox(width: 10)
|
||||
],
|
||||
toolbarHeight: 70,
|
||||
),
|
||||
body: ListView(
|
||||
children: form(),
|
||||
)
|
||||
),
|
||||
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
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,8 +5,7 @@ import 'package:expandable/expandable.dart';
|
|||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import 'package:adguard_home_manager/widgets/version_warning_modal.dart';
|
||||
import 'package:adguard_home_manager/widgets/add_server_modal.dart';
|
||||
import 'package:adguard_home_manager/widgets/add_server/add_server_functions.dart';
|
||||
import 'package:adguard_home_manager/widgets/servers_list/delete_modal.dart';
|
||||
|
||||
import 'package:adguard_home_manager/classes/process_modal.dart';
|
||||
|
@ -88,41 +87,9 @@ class _ServersListItemState extends State<ServersListItem> with SingleTickerProv
|
|||
});
|
||||
}
|
||||
|
||||
void openAddServerBottomSheet({Server? server}) async {
|
||||
void openServerModal({Server? server}) async {
|
||||
await Future.delayed(const Duration(seconds: 0), (() => {
|
||||
if (width > 700) {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => AddServerModal(
|
||||
server: server,
|
||||
window: true,
|
||||
onUnsupportedVersion: (version) => showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => VersionWarningModal(
|
||||
version: version
|
||||
),
|
||||
barrierDismissible: false
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
else {
|
||||
Navigator.push(context, MaterialPageRoute(
|
||||
fullscreenDialog: true,
|
||||
builder: (BuildContext context) => AddServerModal(
|
||||
server: server,
|
||||
window: false,
|
||||
onUnsupportedVersion: (version) => showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => VersionWarningModal(
|
||||
version: version
|
||||
),
|
||||
barrierDismissible: false
|
||||
),
|
||||
)
|
||||
))
|
||||
}
|
||||
openServerFormModal(context: context, width: width, server: server)
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -326,7 +293,7 @@ class _ServersListItemState extends State<ServersListItem> with SingleTickerProv
|
|||
)
|
||||
),
|
||||
PopupMenuItem(
|
||||
onTap: (() => openAddServerBottomSheet(server: server)),
|
||||
onTap: (() => openServerModal(server: server)),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.edit),
|
||||
|
|
|
@ -4,8 +4,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:provider/provider.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
|
||||
import 'package:adguard_home_manager/widgets/version_warning_modal.dart';
|
||||
import 'package:adguard_home_manager/widgets/add_server_modal.dart';
|
||||
import 'package:adguard_home_manager/widgets/add_server/add_server_functions.dart';
|
||||
import 'package:adguard_home_manager/widgets/servers_list/delete_modal.dart';
|
||||
|
||||
import 'package:adguard_home_manager/classes/process_modal.dart';
|
||||
|
@ -57,41 +56,9 @@ class _ServersTileItemState extends State<ServersTileItem> with SingleTickerProv
|
|||
});
|
||||
}
|
||||
|
||||
void openAddServerBottomSheet({Server? server}) async {
|
||||
void openServerModal({Server? server}) async {
|
||||
await Future.delayed(const Duration(seconds: 0), (() => {
|
||||
if (width > 700) {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (context) => AddServerModal(
|
||||
server: server,
|
||||
window: true,
|
||||
onUnsupportedVersion: (version) => showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => VersionWarningModal(
|
||||
version: version
|
||||
),
|
||||
barrierDismissible: false
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
else {
|
||||
Navigator.push(context, MaterialPageRoute(
|
||||
fullscreenDialog: true,
|
||||
builder: (BuildContext context) => AddServerModal(
|
||||
server: server,
|
||||
window: false,
|
||||
onUnsupportedVersion: (version) => showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => VersionWarningModal(
|
||||
version: version
|
||||
),
|
||||
barrierDismissible: false
|
||||
),
|
||||
)
|
||||
))
|
||||
}
|
||||
openServerFormModal(context: context, width: width, server: server)
|
||||
}));
|
||||
}
|
||||
|
||||
|
@ -291,7 +258,7 @@ class _ServersTileItemState extends State<ServersTileItem> with SingleTickerProv
|
|||
)
|
||||
),
|
||||
PopupMenuItem(
|
||||
onTap: (() => openAddServerBottomSheet(server: server)),
|
||||
onTap: (() => openServerModal(server: server)),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.edit),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue