mirror of
https://github.com/DefinedNet/mobile_nebula.git
synced 2025-01-19 03:37:02 +00:00
64d45f66c7
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.
224 lines
7.2 KiB
Dart
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();
|
|
}
|
|
}
|