Format code

This commit is contained in:
Ian VanSchooten 2024-08-28 14:46:03 -04:00
parent b598aa338f
commit 35fbf86c8c
20 changed files with 377 additions and 370 deletions

View File

@ -28,7 +28,8 @@ class SiteItem extends StatelessWidget {
Widget _buildContent(BuildContext context) { Widget _buildContent(BuildContext context) {
final border = BorderSide(color: Utils.configSectionBorder(context)); final border = BorderSide(color: Utils.configSectionBorder(context));
final dnIcon = Theme.of(context).brightness == Brightness.dark ? 'images/dn-logo-dark.svg' : 'images/dn-logo-light.svg'; final dnIcon =
Theme.of(context).brightness == Brightness.dark ? 'images/dn-logo-dark.svg' : 'images/dn-logo-light.svg';
return SpecialButton( return SpecialButton(
decoration: decoration:
@ -39,9 +40,9 @@ class SiteItem extends StatelessWidget {
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[ children: <Widget>[
site.managed ? site.managed
Padding(padding: EdgeInsets.only(right: 10), child: SvgPicture.asset(dnIcon, width: 12)) : ? Padding(padding: EdgeInsets.only(right: 10), child: SvgPicture.asset(dnIcon, width: 12))
Container(), : Container(),
Expanded(child: Text(site.name, style: TextStyle(fontWeight: FontWeight.bold))), Expanded(child: Text(site.name, style: TextStyle(fontWeight: FontWeight.bold))),
Padding(padding: EdgeInsets.only(right: 10)), Padding(padding: EdgeInsets.only(right: 10)),
Icon(CupertinoIcons.forward, color: CupertinoColors.placeholderText.resolveFrom(context), size: 18) Icon(CupertinoIcons.forward, color: CupertinoColors.placeholderText.resolveFrom(context), size: 18)

View File

@ -52,7 +52,9 @@ class ConfigPageItem extends StatelessWidget {
children: <Widget>[ children: <Widget>[
label != null ? Container(width: labelWidth, child: label) : Container(), label != null ? Container(width: labelWidth, child: label) : Container(),
Expanded(child: Container(child: content, padding: EdgeInsets.only(right: 10))), Expanded(child: Container(child: content, padding: EdgeInsets.only(right: 10))),
this.disabled ? Container() : Icon(CupertinoIcons.forward, color: CupertinoColors.placeholderText.resolveFrom(context), size: 18) this.disabled
? Container()
: Icon(CupertinoIcons.forward, color: CupertinoColors.placeholderText.resolveFrom(context), size: 18)
], ],
)), )),
); );

View File

@ -111,10 +111,8 @@ class _AppState extends State<App> {
// TODO: maybe implement this as a dialog instead of a page, you can stack multiple enrollment screens which is annoying in dev // TODO: maybe implement this as a dialog instead of a page, you can stack multiple enrollment screens which is annoying in dev
return platformPageRoute( return platformPageRoute(
context: context, context: context,
builder: (context) => EnrollmentScreen( builder: (context) =>
code: EnrollmentScreen.parseCode(settings.name!), EnrollmentScreen(code: EnrollmentScreen.parseCode(settings.name!), stream: this.dnEnrolled),
stream: this.dnEnrolled
),
); );
} }

View File

@ -206,8 +206,7 @@ class Site {
"unsafeRoutes": unsafeRoutes, "unsafeRoutes": unsafeRoutes,
"managed": json['managed'] ?? false, "managed": json['managed'] ?? false,
"rawConfig": json['rawConfig'], "rawConfig": json['rawConfig'],
"lastManagedUpdate": json["lastManagedUpdate"] == null ? "lastManagedUpdate": json["lastManagedUpdate"] == null ? null : DateTime.parse(json["lastManagedUpdate"]),
null : DateTime.parse(json["lastManagedUpdate"]),
}; };
} }

View File

@ -91,24 +91,24 @@ class _EnrollmentScreenState extends State<EnrollmentScreen> {
} else { } else {
// No code, show the error // No code, show the error
child = Padding( child = Padding(
child: Center(child: Text( child: Center(
child: Text(
'No valid enrollment code was found.\n\nContact your administrator to obtain a new enrollment code.', 'No valid enrollment code was found.\n\nContact your administrator to obtain a new enrollment code.',
textAlign: TextAlign.center, textAlign: TextAlign.center,
)), )),
padding: EdgeInsets.only(top: 20) padding: EdgeInsets.only(top: 20));
);
} }
} else if (this.error != null) { } else if (this.error != null) {
// Error while enrolling, display it // Error while enrolling, display it
child = Center(child: Column( child = Center(
child: Column(
children: [ children: [
Padding( Padding(
child: SelectableText('There was an issue while attempting to enroll this device. Contact your administrator to obtain a new enrollment code.'), child: SelectableText(
padding: EdgeInsets.symmetric(vertical: 20) 'There was an issue while attempting to enroll this device. Contact your administrator to obtain a new enrollment code.'),
), padding: EdgeInsets.symmetric(vertical: 20)),
Padding(child: SelectableText.rich(TextSpan(children: [ Padding(
child: SelectableText.rich(TextSpan(children: [
TextSpan(text: 'If the problem persists, please let us know at '), TextSpan(text: 'If the problem persists, please let us know at '),
TextSpan( TextSpan(
text: 'support@defined.net', text: 'support@defined.net',
@ -121,7 +121,8 @@ class _EnrollmentScreenState extends State<EnrollmentScreen> {
}, },
), ),
TextSpan(text: ' and provide the following error:'), TextSpan(text: ' and provide the following error:'),
])), padding: EdgeInsets.only(bottom: 10)), ])),
padding: EdgeInsets.only(bottom: 10)),
Container( Container(
child: Padding(child: SelectableText(this.error!), padding: EdgeInsets.all(10)), child: Padding(child: SelectableText(this.error!), padding: EdgeInsets.all(10)),
color: Theme.of(context).colorScheme.errorContainer, color: Theme.of(context).colorScheme.errorContainer,
@ -130,36 +131,33 @@ class _EnrollmentScreenState extends State<EnrollmentScreen> {
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
)); ));
} else if (this.enrolled) { } else if (this.enrolled) {
// Enrollment complete! // Enrollment complete!
child = Padding( child = Padding(
child: Center(child: Text( child: Center(
child: Text(
'Enrollment complete! 🎉', 'Enrollment complete! 🎉',
textAlign: TextAlign.center, textAlign: TextAlign.center,
)), )),
padding: EdgeInsets.only(top: 20) padding: EdgeInsets.only(top: 20));
);
} else { } else {
// Have a code and actively enrolling // Have a code and actively enrolling
alignment = Alignment.center; alignment = Alignment.center;
child = Center(child: Column( child = Center(
children: [ child: Column(children: [
Padding(child: Text('Contacting DN for enrollment'), padding: EdgeInsets.only(bottom: 25)), Padding(child: Text('Contacting DN for enrollment'), padding: EdgeInsets.only(bottom: 25)),
PlatformCircularProgressIndicator(cupertino: (_, __) { PlatformCircularProgressIndicator(cupertino: (_, __) {
return CupertinoProgressIndicatorData(radius: 50); return CupertinoProgressIndicatorData(radius: 50);
}) })
] ]));
));
} }
final dnIcon = Theme.of(context).brightness == Brightness.dark ? 'images/dn-logo-dark.svg' : 'images/dn-logo-light.svg'; final dnIcon =
Theme.of(context).brightness == Brightness.dark ? 'images/dn-logo-dark.svg' : 'images/dn-logo-light.svg';
return SimplePage( return SimplePage(
title: Text('Enroll with Managed Nebula', style: TextStyle(fontWeight: FontWeight.bold)), title: Text('Enroll with Managed Nebula', style: TextStyle(fontWeight: FontWeight.bold)),
child: Padding(child: child, padding: EdgeInsets.symmetric(horizontal: 10)), child: Padding(child: child, padding: EdgeInsets.symmetric(horizontal: 10)),
alignment: alignment alignment: alignment);
);
} }
Widget _codeEntry() { Widget _codeEntry() {
@ -169,8 +167,7 @@ class _EnrollmentScreenState extends State<EnrollmentScreen> {
child: PlatformTextField( child: PlatformTextField(
hintText: 'defined.net enrollment code or link', hintText: 'defined.net enrollment code or link',
controller: enrollInput, controller: enrollInput,
) )),
),
PlatformTextButton( PlatformTextButton(
child: Text('Submit'), child: Text('Submit'),
onPressed: () { onPressed: () {

View File

@ -75,7 +75,8 @@ class _HostInfoScreenState extends State<HostInfoScreen> {
labelWidth: 150, labelWidth: 150,
content: Text(hostInfo.cert!.details.name), content: Text(hostInfo.cert!.details.name),
onPressed: () => Utils.openPage( onPressed: () => Utils.openPage(
context, (context) => CertificateDetailsScreen( context,
(context) => CertificateDetailsScreen(
certInfo: CertificateInfo(cert: hostInfo.cert!), certInfo: CertificateInfo(cert: hostInfo.cert!),
supportsQRScanning: widget.supportsQRScanning, supportsQRScanning: widget.supportsQRScanning,
))) )))

View File

@ -128,9 +128,9 @@ class _MainScreenState extends State<MainScreen> {
// Determine whether the device supports QR scanning. For example, some // Determine whether the device supports QR scanning. For example, some
// Chromebooks do not have camera support. // Chromebooks do not have camera support.
if (Platform.isAndroid) { if (Platform.isAndroid) {
platform.invokeMethod("android.deviceHasCamera").then( platform
(hasCamera) => setState(() => supportsQRScanning = hasCamera) .invokeMethod("android.deviceHasCamera")
); .then((hasCamera) => setState(() => supportsQRScanning = hasCamera));
} else { } else {
supportsQRScanning = true; supportsQRScanning = true;
} }
@ -143,9 +143,11 @@ class _MainScreenState extends State<MainScreen> {
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
icon: Icon(Icons.add, size: 28.0), icon: Icon(Icons.add, size: 28.0),
onPressed: () => Utils.openPage(context, (context) { onPressed: () => Utils.openPage(context, (context) {
return SiteConfigScreen(onSave: (_) { return SiteConfigScreen(
onSave: (_) {
_loadSites(); _loadSites();
}, supportsQRScanning: supportsQRScanning); },
supportsQRScanning: supportsQRScanning);
}), }),
), ),
refreshController: refreshController, refreshController: refreshController,
@ -298,7 +300,6 @@ class _MainScreenState extends State<MainScreen> {
); );
} }
_loadSites() async { _loadSites() async {
//TODO: This can throw, we need to show an error dialog //TODO: This can throw, we need to show an error dialog
Map<String, dynamic> rawSites = jsonDecode(await platform.invokeMethod('listSites')); Map<String, dynamic> rawSites = jsonDecode(await platform.invokeMethod('listSites'));
@ -322,7 +323,6 @@ class _MainScreenState extends State<MainScreen> {
} }
}); });
sites!.add(site); sites!.add(site);
} catch (err) { } catch (err) {
//TODO: handle error //TODO: handle error

View File

@ -86,13 +86,14 @@ class _SettingsScreenState extends State<SettingsScreen> {
)), )),
)); ));
final dnIcon = Theme.of(context).brightness == Brightness.dark ? 'images/dn-logo-dark.svg' : 'images/dn-logo-light.svg'; final dnIcon =
Theme.of(context).brightness == Brightness.dark ? 'images/dn-logo-dark.svg' : 'images/dn-logo-light.svg';
items.add(ConfigSection(children: [ items.add(ConfigSection(children: [
ConfigPageItem( ConfigPageItem(
label: Text('Enroll with Managed Nebula'), label: Text('Enroll with Managed Nebula'),
labelWidth: 200, labelWidth: 200,
onPressed: () => Utils.openPage(context, (context) => EnrollmentScreen(stream: widget.stream, allowCodeEntry: true)) onPressed: () =>
) Utils.openPage(context, (context) => EnrollmentScreen(stream: widget.stream, allowCodeEntry: true)))
])); ]));
items.add(ConfigSection(children: [ items.add(ConfigSection(children: [

View File

@ -79,11 +79,12 @@ class _SiteDetailScreenState extends State<SiteDetailScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final dnIcon = Theme.of(context).brightness == Brightness.dark ? 'images/dn-logo-dark.svg' : 'images/dn-logo-light.svg'; final dnIcon =
Theme.of(context).brightness == Brightness.dark ? 'images/dn-logo-dark.svg' : 'images/dn-logo-light.svg';
final title = Row(children: [ final title = Row(children: [
site.managed ? site.managed
Padding(padding: EdgeInsets.only(right: 10), child: SvgPicture.asset(dnIcon, width: 12)) : ? Padding(padding: EdgeInsets.only(right: 10), child: SvgPicture.asset(dnIcon, width: 12))
Container(), : Container(),
Expanded(child: Text(site.name, style: TextStyle(fontWeight: FontWeight.bold))) Expanded(child: Text(site.name, style: TextStyle(fontWeight: FontWeight.bold)))
]); ]);

View File

@ -40,11 +40,12 @@ class _SiteLogsScreenState extends State<SiteLogsScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final dnIcon = Theme.of(context).brightness == Brightness.dark ? 'images/dn-logo-dark.svg' : 'images/dn-logo-light.svg'; final dnIcon =
Theme.of(context).brightness == Brightness.dark ? 'images/dn-logo-dark.svg' : 'images/dn-logo-light.svg';
final title = Row(children: [ final title = Row(children: [
widget.site.managed ? widget.site.managed
Padding(padding: EdgeInsets.only(right: 10), child: SvgPicture.asset(dnIcon, width: 12)) : ? Padding(padding: EdgeInsets.only(right: 10), child: SvgPicture.asset(dnIcon, width: 12))
Container(), : Container(),
Expanded(child: Text(widget.site.name, style: TextStyle(fontWeight: FontWeight.bold))) Expanded(child: Text(widget.site.name, style: TextStyle(fontWeight: FontWeight.bold)))
]); ]);
@ -83,9 +84,7 @@ class _SiteLogsScreenState extends State<SiteLogsScreen> {
border: Border(top: borderSide), border: Border(top: borderSide),
), ),
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ child: Row(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
Expanded( Expanded(child: Builder(builder: (BuildContext context) {
child: Builder(
builder: (BuildContext context) {
return PlatformIconButton( return PlatformIconButton(
padding: padding, padding: padding,
icon: Icon(context.platformIcons.share, size: 30), icon: Icon(context.platformIcons.share, size: 30),
@ -96,8 +95,7 @@ class _SiteLogsScreenState extends State<SiteLogsScreen> {
filename: '${widget.site.name}.log'); filename: '${widget.site.name}.log');
}, },
); );
} })),
)),
Expanded( Expanded(
child: PlatformIconButton( child: PlatformIconButton(
padding: padding, padding: padding,

View File

@ -17,8 +17,7 @@ class SiteTunnelsScreen extends StatefulWidget {
required this.pending, required this.pending,
required this.onChanged, required this.onChanged,
required this.supportsQRScanning, required this.supportsQRScanning,
}) }) : super(key: key);
: super(key: key);
final Site site; final Site site;
final List<HostInfo> tunnels; final List<HostInfo> tunnels;

View File

@ -98,9 +98,7 @@ class _AddCertificateScreenState extends State<AddCertificateScreen> {
content: Text('Share Public Key'), content: Text('Share Public Key'),
onPressed: () async { onPressed: () async {
await Share.share(context, await Share.share(context,
title: 'Please sign and return a certificate', title: 'Please sign and return a certificate', text: pubKey, filename: 'device.pub');
text: pubKey,
filename: 'device.pub');
}, },
); );
}, },

View File

@ -86,9 +86,9 @@ class _AdvancedScreenState extends State<AdvancedScreen> {
label: Text("Lighthouse interval"), label: Text("Lighthouse interval"),
labelWidth: 200, labelWidth: 200,
//TODO: Auto select on focus? //TODO: Auto select on focus?
content: widget.site.managed ? content: widget.site.managed
Text(settings.lhDuration.toString() + " seconds", textAlign: TextAlign.right) : ? Text(settings.lhDuration.toString() + " seconds", textAlign: TextAlign.right)
PlatformTextFormField( : PlatformTextFormField(
initialValue: settings.lhDuration.toString(), initialValue: settings.lhDuration.toString(),
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
suffix: Text("seconds"), suffix: Text("seconds"),
@ -107,9 +107,9 @@ class _AdvancedScreenState extends State<AdvancedScreen> {
label: Text("Listen port"), label: Text("Listen port"),
labelWidth: 150, labelWidth: 150,
//TODO: Auto select on focus? //TODO: Auto select on focus?
content: widget.site.managed ? content: widget.site.managed
Text(settings.port.toString(), textAlign: TextAlign.right) : ? Text(settings.port.toString(), textAlign: TextAlign.right)
PlatformTextFormField( : PlatformTextFormField(
initialValue: settings.port.toString(), initialValue: settings.port.toString(),
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
textAlign: TextAlign.right, textAlign: TextAlign.right,
@ -126,9 +126,9 @@ class _AdvancedScreenState extends State<AdvancedScreen> {
ConfigItem( ConfigItem(
label: Text("MTU"), label: Text("MTU"),
labelWidth: 150, labelWidth: 150,
content: widget.site.managed ? content: widget.site.managed
Text(settings.mtu.toString(), textAlign: TextAlign.right) : ? Text(settings.mtu.toString(), textAlign: TextAlign.right)
PlatformTextFormField( : PlatformTextFormField(
initialValue: settings.mtu.toString(), initialValue: settings.mtu.toString(),
keyboardType: TextInputType.number, keyboardType: TextInputType.number,
textAlign: TextAlign.right, textAlign: TextAlign.right,
@ -184,7 +184,9 @@ class _AdvancedScreenState extends State<AdvancedScreen> {
Utils.openPage(context, (context) { Utils.openPage(context, (context) {
return UnsafeRoutesScreen( return UnsafeRoutesScreen(
unsafeRoutes: settings.unsafeRoutes, unsafeRoutes: settings.unsafeRoutes,
onSave: widget.site.managed ? null : (routes) { onSave: widget.site.managed
? null
: (routes) {
setState(() { setState(() {
settings.unsafeRoutes = routes; settings.unsafeRoutes = routes;
changed = true; changed = true;

View File

@ -86,7 +86,9 @@ class _CAListScreenState extends State<CAListScreen> {
Utils.openPage(context, (context) { Utils.openPage(context, (context) {
return CertificateDetailsScreen( return CertificateDetailsScreen(
certInfo: ca, certInfo: ca,
onDelete: widget.onSave == null ? null : () { onDelete: widget.onSave == null
? null
: () {
setState(() { setState(() {
changed = true; changed = true;
cas.remove(key); cas.remove(key);

View File

@ -19,17 +19,13 @@ class RenderedConfigScreen extends StatelessWidget {
title: Text('Rendered Site Config'), title: Text('Rendered Site Config'),
scrollable: SimpleScrollable.both, scrollable: SimpleScrollable.both,
trailingActions: <Widget>[ trailingActions: <Widget>[
Builder( Builder(builder: (BuildContext context) {
builder: (BuildContext context) {
return PlatformIconButton( return PlatformIconButton(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
icon: Icon(context.platformIcons.share, size: 28.0), icon: Icon(context.platformIcons.share, size: 28.0),
onPressed: () => onPressed: () => Share.share(context, title: '$name.yaml', text: config, filename: '$name.yaml'),
Share.share(context,
title: '$name.yaml', text: config, filename: '$name.yaml'),
); );
} }),
),
], ],
child: Container( child: Container(
padding: EdgeInsets.all(5), padding: EdgeInsets.all(5),

View File

@ -139,17 +139,17 @@ class _SiteConfigScreenState extends State<SiteConfigScreen> {
lastUpdate = formatter.format(site.lastManagedUpdate!.toLocal()); lastUpdate = formatter.format(site.lastManagedUpdate!.toLocal());
} }
return site.managed ? ConfigSection( return site.managed
label: "MANAGED CONFIG", ? ConfigSection(label: "MANAGED CONFIG", children: <Widget>[
children: <Widget>[
ConfigItem( ConfigItem(
label: Text("Last Update"), label: Text("Last Update"),
content: Wrap(alignment: WrapAlignment.end, crossAxisAlignment: WrapCrossAlignment.center, children: <Widget>[ content:
Wrap(alignment: WrapAlignment.end, crossAxisAlignment: WrapCrossAlignment.center, children: <Widget>[
Text(lastUpdate), Text(lastUpdate),
]), ]),
) )
] ])
) : Container(); : Container();
} }
Widget _keys() { Widget _keys() {
@ -186,7 +186,9 @@ class _SiteConfigScreenState extends State<SiteConfigScreen> {
certInfo: site.certInfo!, certInfo: site.certInfo!,
pubKey: pubKey, pubKey: pubKey,
privKey: privKey, privKey: privKey,
onReplace: site.managed ? null : (result) { onReplace: site.managed
? null
: (result) {
setState(() { setState(() {
changed = true; changed = true;
site.certInfo = result.certInfo; site.certInfo = result.certInfo;
@ -227,7 +229,9 @@ class _SiteConfigScreenState extends State<SiteConfigScreen> {
Utils.openPage(context, (context) { Utils.openPage(context, (context) {
return CAListScreen( return CAListScreen(
cas: site.ca, cas: site.ca,
onSave: site.managed ? null : (ca) { onSave: site.managed
? null
: (ca) {
setState(() { setState(() {
changed = true; changed = true;
site.ca = ca; site.ca = ca;
@ -261,7 +265,9 @@ class _SiteConfigScreenState extends State<SiteConfigScreen> {
Utils.openPage(context, (context) { Utils.openPage(context, (context) {
return StaticHostsScreen( return StaticHostsScreen(
hostmap: site.staticHostmap, hostmap: site.staticHostmap,
onSave: site.managed ? null : (map) { onSave: site.managed
? null
: (map) {
setState(() { setState(() {
changed = true; changed = true;
site.staticHostmap = map; site.staticHostmap = map;

View File

@ -66,7 +66,11 @@ class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return FormPage( return FormPage(
title: widget.onDelete == null ? widget.onSave == null ? 'View Static Host' : 'New Static Host' : 'Edit Static Host', title: widget.onDelete == null
? widget.onSave == null
? 'View Static Host'
: 'New Static Host'
: 'Edit Static Host',
changed: changed, changed: changed,
onSave: _onSave, onSave: _onSave,
child: Column(children: [ child: Column(children: [
@ -74,9 +78,9 @@ class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
ConfigItem( ConfigItem(
label: Text('Nebula IP'), label: Text('Nebula IP'),
labelWidth: 200, labelWidth: 200,
content: widget.onSave == null ? content: widget.onSave == null
Text(_nebulaIp, textAlign: TextAlign.end) : ? Text(_nebulaIp, textAlign: TextAlign.end)
IPFormField( : IPFormField(
help: "Required", help: "Required",
initialValue: _nebulaIp, initialValue: _nebulaIp,
ipOnly: true, ipOnly: true,
@ -96,7 +100,9 @@ class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
child: Switch.adaptive( child: Switch.adaptive(
value: _lighthouse, value: _lighthouse,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap, materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
onChanged: widget.onSave == null ? null : (v) { onChanged: widget.onSave == null
? null
: (v) {
setState(() { setState(() {
changed = true; changed = true;
_lighthouse = v; _lighthouse = v;
@ -128,8 +134,7 @@ class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
_onSave() { _onSave() {
Navigator.pop(context); Navigator.pop(context);
if (widget.onSave != null) { if (widget.onSave != null) {
var map = Hostmap( var map = Hostmap(nebulaIp: _nebulaIp, destinations: [], lighthouse: _lighthouse);
nebulaIp: _nebulaIp, destinations: [], lighthouse: _lighthouse);
_destinations.forEach((_, dest) { _destinations.forEach((_, dest) {
map.destinations.add(dest.destination); map.destinations.add(dest.destination);
@ -147,7 +152,9 @@ class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
key: key, key: key,
label: Align( label: Align(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: widget.onSave == null ? Container() : PlatformIconButton( child: widget.onSave == null
? Container()
: PlatformIconButton(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
icon: Icon(Icons.remove_circle, color: CupertinoColors.systemRed.resolveFrom(context)), icon: Icon(Icons.remove_circle, color: CupertinoColors.systemRed.resolveFrom(context)),
onPressed: () => setState(() { onPressed: () => setState(() {
@ -157,9 +164,9 @@ class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
labelWidth: 70, labelWidth: 70,
content: Row(children: <Widget>[ content: Row(children: <Widget>[
Expanded( Expanded(
child: widget.onSave == null ? child: widget.onSave == null
Text(dest.destination.toString(), textAlign: TextAlign.end) : ? Text(dest.destination.toString(), textAlign: TextAlign.end)
IPAndPortFormField( : IPAndPortFormField(
ipHelp: 'public ip or name', ipHelp: 'public ip or name',
ipTextAlign: TextAlign.end, ipTextAlign: TextAlign.end,
enableIPV6: true, enableIPV6: true,
@ -178,8 +185,7 @@ class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
if (widget.onSave != null) { if (widget.onSave != null) {
items.add(ConfigButtonItem( items.add(ConfigButtonItem(
content: Text('Add another'), content: Text('Add another'),
onPressed: () => onPressed: () => setState(() {
setState(() {
_addDestination(); _addDestination();
_dismissKeyboard(); _dismissKeyboard();
}))); })));

View File

@ -70,8 +70,7 @@ class _StaticHostsScreenState extends State<StaticHostsScreen> {
if (widget.onSave != null) { if (widget.onSave != null) {
Map<String, StaticHost> map = {}; Map<String, StaticHost> map = {};
_hostmap.forEach((_, host) { _hostmap.forEach((_, host) {
map[host.nebulaIp] = StaticHost( map[host.nebulaIp] = StaticHost(destinations: host.destinations, lighthouse: host.lighthouse);
destinations: host.destinations, lighthouse: host.lighthouse);
}); });
widget.onSave!(map); widget.onSave!(map);
@ -98,7 +97,9 @@ class _StaticHostsScreenState extends State<StaticHostsScreen> {
nebulaIp: host.nebulaIp, nebulaIp: host.nebulaIp,
destinations: host.destinations, destinations: host.destinations,
lighthouse: host.lighthouse, lighthouse: host.lighthouse,
onSave: widget.onSave == null ? null :(map) { onSave: widget.onSave == null
? null
: (map) {
setState(() { setState(() {
changed = true; changed = true;
host.nebulaIp = map.nebulaIp; host.nebulaIp = map.nebulaIp;
@ -106,7 +107,9 @@ class _StaticHostsScreenState extends State<StaticHostsScreen> {
host.lighthouse = map.lighthouse; host.lighthouse = map.lighthouse;
}); });
}, },
onDelete: widget.onSave == null ? null : () { onDelete: widget.onSave == null
? null
: () {
setState(() { setState(() {
changed = true; changed = true;
_hostmap.remove(key); _hostmap.remove(key);

View File

@ -41,9 +41,7 @@ class Share {
/// - filePath: Path to the file to share /// - filePath: Path to the file to share
/// - filename: An optional filename to override the existing file /// - filename: An optional filename to override the existing file
static Future<bool> shareFile(BuildContext context, static Future<bool> shareFile(BuildContext context,
{required String title, {required String title, required String filePath, String? filename}) async {
required String filePath,
String? filename}) async {
assert(title.isNotEmpty); assert(title.isNotEmpty);
assert(filePath.isNotEmpty); assert(filePath.isNotEmpty);
@ -54,8 +52,7 @@ class Share {
// and then delete it // and then delete it
final xFile = sp.XFile(filePath, name: filename); final xFile = sp.XFile(filePath, name: filename);
final result = await sp.Share.shareXFiles([xFile], final result = await sp.Share.shareXFiles([xFile],
subject: title, subject: title, sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size);
sharePositionOrigin: box!.localToGlobal(Offset.zero) & box.size);
return result.status == sp.ShareResultStatus.success; return result.status == sp.ShareResultStatus.success;
} }
} }