mobile_nebula/lib/screens/siteConfig/StaticHostmapScreen.dart
Ian VanSchooten 64d45f66c7
Update Flutter, target android SDK 34 (#160)
This updates flutter to 3.24.1, the latest stable version, and also updates our flutter dependencies to latest.

It targets the latest android sdk, 34, which is required if we want to publish a new version to the Google Play store.

I also needed to make a few adjustments to handle deprecations. The biggest change is that I needed to wrap the main widget in MaterialApp to avoid problems with AdaptiveSwitch in iOS.
2024-09-20 14:19:23 -04:00

224 lines
7.2 KiB
Dart

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:mobile_nebula/components/FormPage.dart';
import 'package:mobile_nebula/components/IPAndPortFormField.dart';
import 'package:mobile_nebula/components/IPFormField.dart';
import 'package:mobile_nebula/components/config/ConfigButtonItem.dart';
import 'package:mobile_nebula/components/config/ConfigItem.dart';
import 'package:mobile_nebula/components/config/ConfigSection.dart';
import 'package:mobile_nebula/models/Hostmap.dart';
import 'package:mobile_nebula/models/IPAndPort.dart';
import 'package:mobile_nebula/services/utils.dart';
class _IPAndPort {
final FocusNode focusNode;
IPAndPort destination;
_IPAndPort({required this.focusNode, required this.destination});
}
class StaticHostmapScreen extends StatefulWidget {
StaticHostmapScreen({
Key? key,
this.nebulaIp = '',
destinations,
this.lighthouse = false,
this.onDelete,
required this.onSave,
}) : this.destinations = destinations ?? [],
super(key: key);
final List<IPAndPort> destinations;
final String nebulaIp;
final bool lighthouse;
final ValueChanged<Hostmap>? onSave;
final Function? onDelete;
@override
_StaticHostmapScreenState createState() => _StaticHostmapScreenState();
}
class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
late Map<Key, _IPAndPort> _destinations;
late String _nebulaIp;
late bool _lighthouse;
bool changed = false;
@override
void initState() {
_nebulaIp = widget.nebulaIp;
_lighthouse = widget.lighthouse;
_destinations = {};
widget.destinations.forEach((dest) {
_destinations[UniqueKey()] = _IPAndPort(focusNode: FocusNode(), destination: dest);
});
if (_destinations.length == 0) {
_addDestination();
}
// _addDestination() above sets us to changed, set it back to false since we are at the default state
changed = false;
super.initState();
}
@override
Widget build(BuildContext context) {
return FormPage(
title: widget.onDelete == null
? widget.onSave == null
? 'View Static Host'
: 'New Static Host'
: 'Edit Static Host',
changed: changed,
onSave: _onSave,
child: Column(children: [
ConfigSection(label: 'Maps a nebula ip address to multiple real world addresses', children: <Widget>[
ConfigItem(
label: Text('Nebula IP'),
labelWidth: 200,
content: widget.onSave == null
? Text(_nebulaIp, textAlign: TextAlign.end)
: IPFormField(
help: "Required",
initialValue: _nebulaIp,
ipOnly: true,
textAlign: TextAlign.end,
crossAxisAlignment: CrossAxisAlignment.end,
textInputAction: TextInputAction.next,
onSaved: (v) {
if (v != null) {
_nebulaIp = v;
}
})),
ConfigItem(
label: Text('Lighthouse'),
labelWidth: 200,
content: Container(
alignment: Alignment.centerRight,
child: Switch.adaptive(
value: _lighthouse,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
onChanged: widget.onSave == null
? null
: (v) {
setState(() {
changed = true;
_lighthouse = v;
});
})),
),
]),
ConfigSection(
label: 'List of public ips or dns names where for this host',
children: _buildHosts(),
),
widget.onDelete != null
? Padding(
padding: EdgeInsets.only(top: 50, bottom: 10, left: 10, right: 10),
child: SizedBox(
width: double.infinity,
child: PlatformElevatedButton(
child: Text('Delete'),
color: CupertinoColors.systemRed.resolveFrom(context),
onPressed: () => Utils.confirmDelete(context, 'Delete host map?', () {
Navigator.of(context).pop();
widget.onDelete!();
}),
)))
: Container()
]));
}
_onSave() {
Navigator.pop(context);
if (widget.onSave != null) {
var map = Hostmap(nebulaIp: _nebulaIp, destinations: [], lighthouse: _lighthouse);
_destinations.forEach((_, dest) {
map.destinations.add(dest.destination);
});
widget.onSave!(map);
}
}
List<Widget> _buildHosts() {
List<Widget> items = [];
_destinations.forEach((key, dest) {
items.add(ConfigItem(
key: key,
label: Align(
alignment: Alignment.centerLeft,
child: widget.onSave == null
? Container()
: PlatformIconButton(
padding: EdgeInsets.zero,
icon: Icon(Icons.remove_circle, color: CupertinoColors.systemRed.resolveFrom(context)),
onPressed: () => setState(() {
_removeDestination(key);
_dismissKeyboard();
}))),
labelWidth: 70,
content: Row(children: <Widget>[
Expanded(
child: widget.onSave == null
? Text(dest.destination.toString(), textAlign: TextAlign.end)
: IPAndPortFormField(
ipHelp: 'public ip or name',
ipTextAlign: TextAlign.end,
enableIPV6: true,
noBorder: true,
initialValue: dest.destination,
onSaved: (v) {
if (v != null) {
dest.destination = v;
}
},
)),
]),
));
});
if (widget.onSave != null) {
items.add(ConfigButtonItem(
content: Text('Add another'),
onPressed: () => setState(() {
_addDestination();
_dismissKeyboard();
})));
}
return items;
}
_addDestination() {
changed = true;
_destinations[UniqueKey()] = _IPAndPort(focusNode: FocusNode(), destination: IPAndPort());
// We can't onChanged here because it causes rendering issues on first build due to ensuring there is a single destination
}
_removeDestination(Key key) {
changed = true;
_destinations.remove(key);
}
_dismissKeyboard() {
FocusScopeNode currentFocus = FocusScope.of(context);
if (!currentFocus.hasPrimaryFocus) {
currentFocus.unfocus();
}
}
@override
void dispose() {
_destinations.forEach((key, dest) {
dest.focusNode.dispose();
});
super.dispose();
}
}