import 'dart:io'; import 'package:flutter/material.dart'; import 'package:liteauthconfig/appconfig.dart'; import 'package:liteauthconfig/dialogs/esptouchdialog.dart'; import 'package:liteauthconfig/l10n/app_localizations.dart'; import 'package:multicast_dns/multicast_dns.dart'; import 'package:network_info_plus/network_info_plus.dart'; import 'package:permission_handler/permission_handler.dart'; // ignore_for_file: use_build_context_synchronously class RegisterPage extends StatefulWidget { final bool setup; const RegisterPage(this.setup, {super.key}); @override State createState() => _RegisterPageState(); } class _RegisterPageState extends State { TextEditingController nameController = TextEditingController(); TextEditingController ssidController = TextEditingController(); TextEditingController bssidController = TextEditingController(); TextEditingController passwordController = TextEditingController(); bool potentially5GHz = false; bool obscurePassword = true; @override void initState() { super.initState(); askForNetworkInfo(); } void askForNetworkInfo() async { await Future.delayed(Duration(milliseconds: 250)); if (!context.mounted) { return; } var appLocal = AppLocalizations.of(context)!; var appTheme = Theme.of(context); if (await Permission.location.isDenied) { showDialog( context: context, builder: (context) => AlertDialog.adaptive( backgroundColor: appTheme.cardColor, title: Text(appLocal.networkInfoHeadline), content: Text(appLocal.networkInfoPrompt), actions: [ TextButton( onPressed: () { Navigator.pop(context); }, child: Text(appLocal.cancel), ), TextButton( onPressed: () async { Navigator.pop(context); if (await Permission.location.request().isGranted) { fetchNetworkInfo(); } }, child: Text(appLocal.continueText), ), ], ), ); } else if (await Permission.location.isGranted) { fetchNetworkInfo(); } } void fetchNetworkInfo() async { var netInfo = NetworkInfo(); var name = await netInfo.getWifiName() ?? ""; if (Platform.isAndroid) { name = name.substring(1, name.length - 1); } ssidController.text = name; bssidController.text = await netInfo.getWifiBSSID() ?? ""; if (name.contains("5G")) { setState(() { potentially5GHz = true; }); } } void submit() async { if (widget.setup) { await showDialog( context: context, barrierDismissible: false, builder: (context) => ESPTouchDialog( name: nameController.text, ssid: ssidController.text, bssid: bssidController.text, password: passwordController.text, addNewEntry: true, ), ); } else { final dev = Device( name: nameController.text, routerSsid: ssidController.text, routerBssid: bssidController.text, networkPassword: passwordController.text, ); final MDnsClient client = MDnsClient(); await client.start(); // TODO: Change to dynamic mDNS name String name = "liteauth.local"; await for (final PtrResourceRecord ptr in client.lookup( ResourceRecordQuery.serverPointer(name), )) { await for (final SrvResourceRecord srv in client.lookup(ResourceRecordQuery.service(ptr.domainName))) { // TODO: Actually implement record lookup } } AppConfig().devices.add(dev); } if (context.mounted) { Navigator.pop(context); } } @override Widget build(BuildContext context) { var appLocal = AppLocalizations.of(context)!; return Scaffold( appBar: AppBar(title: Text(appLocal.registerDevice)), body: SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(16), child: Column( spacing: 16, children: [ if (potentially5GHz) Card( child: Column( children: [ ListTile( leading: const Icon(Icons.warning), title: Text(appLocal.networkLimitation), subtitle: Text(appLocal.networkLimitationDesc), ), ], ), ), TextField( controller: nameController, decoration: InputDecoration( border: OutlineInputBorder(), labelText: appLocal.deviceName, ), ), TextField( controller: ssidController, decoration: InputDecoration( border: OutlineInputBorder(), labelText: appLocal.networkName, ), onChanged: (name) { setState(() { potentially5GHz = name.contains("5G"); }); }, ), TextField( controller: bssidController, decoration: InputDecoration( border: OutlineInputBorder(), labelText: appLocal.routerMacAddress, ), ), TextField( obscureText: obscurePassword, controller: passwordController, decoration: InputDecoration( border: OutlineInputBorder(), labelText: appLocal.networkPassword, suffixIcon: IconButton( onPressed: () { setState(() { obscurePassword = !obscurePassword; }); }, icon: Icon( obscurePassword ? Icons.remove_red_eye : Icons.remove_red_eye_outlined, ), ), ), ), ], ), ), ), floatingActionButton: FloatingActionButton( onPressed: submit, child: const Icon(Icons.check), ), ); } }