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) {
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(
decoration:
@ -39,9 +40,9 @@ class SiteItem extends StatelessWidget {
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
site.managed ?
Padding(padding: EdgeInsets.only(right: 10), child: SvgPicture.asset(dnIcon, width: 12)) :
Container(),
site.managed
? Padding(padding: EdgeInsets.only(right: 10), child: SvgPicture.asset(dnIcon, width: 12))
: Container(),
Expanded(child: Text(site.name, style: TextStyle(fontWeight: FontWeight.bold))),
Padding(padding: EdgeInsets.only(right: 10)),
Icon(CupertinoIcons.forward, color: CupertinoColors.placeholderText.resolveFrom(context), size: 18)

View File

@ -52,7 +52,9 @@ class ConfigPageItem extends StatelessWidget {
children: <Widget>[
label != null ? Container(width: labelWidth, child: label) : Container(),
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

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

View File

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

View File

@ -91,37 +91,38 @@ class _EnrollmentScreenState extends State<EnrollmentScreen> {
} else {
// No code, show the error
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.',
textAlign: TextAlign.center,
)),
padding: EdgeInsets.only(top: 20)
);
padding: EdgeInsets.only(top: 20));
}
} else if (this.error != null) {
// Error while enrolling, display it
child = Center(child: Column(
child = Center(
child: Column(
children: [
Padding(
child: SelectableText('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: [
TextSpan(text: 'If the problem persists, please let us know at '),
TextSpan(
text: 'support@defined.net',
style: bodyTextStyle.apply(color: colorScheme.primary),
recognizer: TapGestureRecognizer()
..onTap = () async {
if (await canLaunchUrl(contactUri)) {
print(await launchUrl(contactUri));
}
},
),
TextSpan(text: ' and provide the following error:'),
])), padding: EdgeInsets.only(bottom: 10)),
child: SelectableText(
'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: [
TextSpan(text: 'If the problem persists, please let us know at '),
TextSpan(
text: 'support@defined.net',
style: bodyTextStyle.apply(color: colorScheme.primary),
recognizer: TapGestureRecognizer()
..onTap = () async {
if (await canLaunchUrl(contactUri)) {
print(await launchUrl(contactUri));
}
},
),
TextSpan(text: ' and provide the following error:'),
])),
padding: EdgeInsets.only(bottom: 10)),
Container(
child: Padding(child: SelectableText(this.error!), padding: EdgeInsets.all(10)),
color: Theme.of(context).colorScheme.errorContainer,
@ -130,47 +131,43 @@ class _EnrollmentScreenState extends State<EnrollmentScreen> {
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
));
} else if (this.enrolled) {
// Enrollment complete!
child = Padding(
child: Center(child: Text(
child: Center(
child: Text(
'Enrollment complete! 🎉',
textAlign: TextAlign.center,
)),
padding: EdgeInsets.only(top: 20)
);
padding: EdgeInsets.only(top: 20));
} else {
// Have a code and actively enrolling
alignment = Alignment.center;
child = Center(child: Column(
children: [
Padding(child: Text('Contacting DN for enrollment'), padding: EdgeInsets.only(bottom: 25)),
PlatformCircularProgressIndicator(cupertino: (_, __) {
return CupertinoProgressIndicatorData(radius: 50);
})
]
));
child = Center(
child: Column(children: [
Padding(child: Text('Contacting DN for enrollment'), padding: EdgeInsets.only(bottom: 25)),
PlatformCircularProgressIndicator(cupertino: (_, __) {
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(
title: Text('Enroll with Managed Nebula', style: TextStyle(fontWeight: FontWeight.bold)),
child: Padding(child: child, padding: EdgeInsets.symmetric(horizontal: 10)),
alignment: alignment
);
title: Text('Enroll with Managed Nebula', style: TextStyle(fontWeight: FontWeight.bold)),
child: Padding(child: child, padding: EdgeInsets.symmetric(horizontal: 10)),
alignment: alignment);
}
Widget _codeEntry() {
return Column(children: [
Padding(
padding: EdgeInsets.only(top: 20),
child: PlatformTextField(
hintText: 'defined.net enrollment code or link',
controller: enrollInput,
)
),
padding: EdgeInsets.only(top: 20),
child: PlatformTextField(
hintText: 'defined.net enrollment code or link',
controller: enrollInput,
)),
PlatformTextButton(
child: Text('Submit'),
onPressed: () {

View File

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

View File

@ -128,9 +128,9 @@ class _MainScreenState extends State<MainScreen> {
// Determine whether the device supports QR scanning. For example, some
// Chromebooks do not have camera support.
if (Platform.isAndroid) {
platform.invokeMethod("android.deviceHasCamera").then(
(hasCamera) => setState(() => supportsQRScanning = hasCamera)
);
platform
.invokeMethod("android.deviceHasCamera")
.then((hasCamera) => setState(() => supportsQRScanning = hasCamera));
} else {
supportsQRScanning = true;
}
@ -143,9 +143,11 @@ class _MainScreenState extends State<MainScreen> {
padding: EdgeInsets.zero,
icon: Icon(Icons.add, size: 28.0),
onPressed: () => Utils.openPage(context, (context) {
return SiteConfigScreen(onSave: (_) {
_loadSites();
}, supportsQRScanning: supportsQRScanning);
return SiteConfigScreen(
onSave: (_) {
_loadSites();
},
supportsQRScanning: supportsQRScanning);
}),
),
refreshController: refreshController,
@ -210,9 +212,9 @@ class _MainScreenState extends State<MainScreen> {
onPressed: () {
Utils.openPage(context, (context) {
return SiteDetailScreen(
site: site,
onChanged: () => _loadSites(),
supportsQRScanning: supportsQRScanning,
site: site,
onChanged: () => _loadSites(),
supportsQRScanning: supportsQRScanning,
);
});
}));
@ -289,16 +291,15 @@ class _MainScreenState extends State<MainScreen> {
);
}
Widget _debugClearKeys() {
Widget _debugClearKeys() {
return CupertinoButton(
child: Text("Clear Keys"),
onPressed: () async {
await platform.invokeMethod("debug.clearKeys", null);
},
await platform.invokeMethod("debug.clearKeys", null);
},
);
}
_loadSites() async {
//TODO: This can throw, we need to show an error dialog
Map<String, dynamic> rawSites = jsonDecode(await platform.invokeMethod('listSites'));
@ -322,7 +323,6 @@ class _MainScreenState extends State<MainScreen> {
}
});
sites!.add(site);
} catch (err) {
//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: [
ConfigPageItem(
label: Text('Enroll with Managed Nebula'),
labelWidth: 200,
onPressed: () => Utils.openPage(context, (context) => EnrollmentScreen(stream: widget.stream, allowCodeEntry: true))
)
label: Text('Enroll with Managed Nebula'),
labelWidth: 200,
onPressed: () =>
Utils.openPage(context, (context) => EnrollmentScreen(stream: widget.stream, allowCodeEntry: true)))
]));
items.add(ConfigSection(children: [

View File

@ -79,11 +79,12 @@ class _SiteDetailScreenState extends State<SiteDetailScreen> {
@override
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: [
site.managed ?
Padding(padding: EdgeInsets.only(right: 10), child: SvgPicture.asset(dnIcon, width: 12)) :
Container(),
site.managed
? Padding(padding: EdgeInsets.only(right: 10), child: SvgPicture.asset(dnIcon, width: 12))
: Container(),
Expanded(child: Text(site.name, style: TextStyle(fontWeight: FontWeight.bold)))
]);
@ -192,16 +193,16 @@ class _SiteDetailScreenState extends State<SiteDetailScreen> {
Utils.openPage(
context,
(context) => SiteTunnelsScreen(
pending: false,
tunnels: activeHosts!,
site: site,
onChanged: (hosts) {
setState(() {
activeHosts = hosts;
});
},
supportsQRScanning: widget.supportsQRScanning,
));
pending: false,
tunnels: activeHosts!,
site: site,
onChanged: (hosts) {
setState(() {
activeHosts = hosts;
});
},
supportsQRScanning: widget.supportsQRScanning,
));
},
label: Text("Active"),
content: Container(alignment: Alignment.centerRight, child: active)),
@ -212,16 +213,16 @@ class _SiteDetailScreenState extends State<SiteDetailScreen> {
Utils.openPage(
context,
(context) => SiteTunnelsScreen(
pending: true,
tunnels: pendingHosts!,
site: site,
onChanged: (hosts) {
setState(() {
pendingHosts = hosts;
});
},
supportsQRScanning: widget.supportsQRScanning,
));
pending: true,
tunnels: pendingHosts!,
site: site,
onChanged: (hosts) {
setState(() {
pendingHosts = hosts;
});
},
supportsQRScanning: widget.supportsQRScanning,
));
},
label: Text("Pending"),
content: Container(alignment: Alignment.centerRight, child: pending))
@ -237,11 +238,11 @@ class _SiteDetailScreenState extends State<SiteDetailScreen> {
onPressed: () {
Utils.openPage(context, (context) {
return SiteConfigScreen(
site: widget.site,
onSave: (site) async {
changed = true;
setState(() {});
},
site: widget.site,
onSave: (site) async {
changed = true;
setState(() {});
},
supportsQRScanning: widget.supportsQRScanning,
);
});

View File

@ -40,11 +40,12 @@ class _SiteLogsScreenState extends State<SiteLogsScreen> {
@override
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: [
widget.site.managed ?
Padding(padding: EdgeInsets.only(right: 10), child: SvgPicture.asset(dnIcon, width: 12)) :
Container(),
widget.site.managed
? Padding(padding: EdgeInsets.only(right: 10), child: SvgPicture.asset(dnIcon, width: 12))
: Container(),
Expanded(child: Text(widget.site.name, style: TextStyle(fontWeight: FontWeight.bold)))
]);
@ -83,29 +84,26 @@ class _SiteLogsScreenState extends State<SiteLogsScreen> {
border: Border(top: borderSide),
),
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
Expanded(
child: Builder(
builder: (BuildContext context) {
return PlatformIconButton(
padding: padding,
icon: Icon(context.platformIcons.share, size: 30),
onPressed: () {
Share.shareFile(context,
title: '${widget.site.name} logs',
filePath: widget.site.logFile,
filename: '${widget.site.name}.log');
},
);
}
)),
Expanded(child: Builder(builder: (BuildContext context) {
return PlatformIconButton(
padding: padding,
icon: Icon(context.platformIcons.share, size: 30),
onPressed: () {
Share.shareFile(context,
title: '${widget.site.name} logs',
filePath: widget.site.logFile,
filename: '${widget.site.name}.log');
},
);
})),
Expanded(
child: PlatformIconButton(
padding: padding,
icon: Icon(context.platformIcons.downArrow, size: 30),
onPressed: () async {
controller.animateTo(controller.position.maxScrollExtent,
duration: const Duration(milliseconds: 500), curve: Curves.linearToEaseOut);
},
padding: padding,
icon: Icon(context.platformIcons.downArrow, size: 30),
onPressed: () async {
controller.animateTo(controller.position.maxScrollExtent,
duration: const Duration(milliseconds: 500), curve: Curves.linearToEaseOut);
},
)),
]));
}

View File

@ -17,8 +17,7 @@ class SiteTunnelsScreen extends StatefulWidget {
required this.pending,
required this.onChanged,
required this.supportsQRScanning,
})
: super(key: key);
}) : super(key: key);
final Site site;
final List<HostInfo> tunnels;
@ -67,17 +66,17 @@ class _SiteTunnelsScreenState extends State<SiteTunnelsScreen> {
children.add(ConfigPageItem(
onPressed: () => Utils.openPage(
context,
(context) => HostInfoScreen(
isLighthouse: isLh,
hostInfo: hostInfo,
pending: widget.pending,
site: widget.site,
onChanged: () {
_listHostmap();
},
supportsQRScanning: widget.supportsQRScanning,
),
context,
(context) => HostInfoScreen(
isLighthouse: isLh,
hostInfo: hostInfo,
pending: widget.pending,
site: widget.site,
onChanged: () {
_listHostmap();
},
supportsQRScanning: widget.supportsQRScanning,
),
),
label: Row(children: <Widget>[Padding(child: icon, padding: EdgeInsets.only(right: 10)), Text(hostInfo.vpnIp)]),
labelWidth: ipWidth,

View File

@ -98,12 +98,10 @@ class _AddCertificateScreenState extends State<AddCertificateScreen> {
content: Text('Share Public Key'),
onPressed: () async {
await Share.share(context,
title: 'Please sign and return a certificate',
text: pubKey,
filename: 'device.pub');
title: 'Please sign and return a certificate', text: pubKey, filename: 'device.pub');
},
);
},
},
),
])
];
@ -269,12 +267,12 @@ class _AddCertificateScreenState extends State<AddCertificateScreen> {
// We have a cert, pop the details screen where they can hit save
Utils.openPage(context, (context) {
return CertificateDetailsScreen(
certInfo: tryCertInfo,
onSave: () {
Navigator.pop(context);
widget.onSave!(CertificateResult(certInfo: tryCertInfo, key: keyController.text));
},
supportsQRScanning: widget.supportsQRScanning,
certInfo: tryCertInfo,
onSave: () {
Navigator.pop(context);
widget.onSave!(CertificateResult(certInfo: tryCertInfo, key: keyController.text));
},
supportsQRScanning: widget.supportsQRScanning,
);
});
}

View File

@ -86,62 +86,62 @@ class _AdvancedScreenState extends State<AdvancedScreen> {
label: Text("Lighthouse interval"),
labelWidth: 200,
//TODO: Auto select on focus?
content: widget.site.managed ?
Text(settings.lhDuration.toString() + " seconds", textAlign: TextAlign.right) :
PlatformTextFormField(
initialValue: settings.lhDuration.toString(),
keyboardType: TextInputType.number,
suffix: Text("seconds"),
textAlign: TextAlign.right,
maxLength: 5,
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
onSaved: (val) {
setState(() {
if (val != null) {
settings.lhDuration = int.parse(val);
}
});
},
)),
content: widget.site.managed
? Text(settings.lhDuration.toString() + " seconds", textAlign: TextAlign.right)
: PlatformTextFormField(
initialValue: settings.lhDuration.toString(),
keyboardType: TextInputType.number,
suffix: Text("seconds"),
textAlign: TextAlign.right,
maxLength: 5,
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
onSaved: (val) {
setState(() {
if (val != null) {
settings.lhDuration = int.parse(val);
}
});
},
)),
ConfigItem(
label: Text("Listen port"),
labelWidth: 150,
//TODO: Auto select on focus?
content: widget.site.managed ?
Text(settings.port.toString(), textAlign: TextAlign.right) :
PlatformTextFormField(
initialValue: settings.port.toString(),
keyboardType: TextInputType.number,
textAlign: TextAlign.right,
maxLength: 5,
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
onSaved: (val) {
setState(() {
if (val != null) {
settings.port = int.parse(val);
}
});
},
)),
content: widget.site.managed
? Text(settings.port.toString(), textAlign: TextAlign.right)
: PlatformTextFormField(
initialValue: settings.port.toString(),
keyboardType: TextInputType.number,
textAlign: TextAlign.right,
maxLength: 5,
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
onSaved: (val) {
setState(() {
if (val != null) {
settings.port = int.parse(val);
}
});
},
)),
ConfigItem(
label: Text("MTU"),
labelWidth: 150,
content: widget.site.managed ?
Text(settings.mtu.toString(), textAlign: TextAlign.right) :
PlatformTextFormField(
initialValue: settings.mtu.toString(),
keyboardType: TextInputType.number,
textAlign: TextAlign.right,
maxLength: 5,
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
onSaved: (val) {
setState(() {
if (val != null) {
settings.mtu = int.parse(val);
}
});
},
)),
content: widget.site.managed
? Text(settings.mtu.toString(), textAlign: TextAlign.right)
: PlatformTextFormField(
initialValue: settings.mtu.toString(),
keyboardType: TextInputType.number,
textAlign: TextAlign.right,
maxLength: 5,
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
onSaved: (val) {
setState(() {
if (val != null) {
settings.mtu = int.parse(val);
}
});
},
)),
ConfigPageItem(
disabled: widget.site.managed,
label: Text('Cipher'),
@ -184,12 +184,14 @@ class _AdvancedScreenState extends State<AdvancedScreen> {
Utils.openPage(context, (context) {
return UnsafeRoutesScreen(
unsafeRoutes: settings.unsafeRoutes,
onSave: widget.site.managed ? null : (routes) {
setState(() {
settings.unsafeRoutes = routes;
changed = true;
});
});
onSave: widget.site.managed
? null
: (routes) {
setState(() {
settings.unsafeRoutes = routes;
changed = true;
});
});
});
},
)

View File

@ -64,18 +64,18 @@ class _CAListScreenState extends State<CAListScreen> {
}
return FormPage(
title: 'Certificate Authorities',
changed: changed,
onSave: () {
if (widget.onSave != null) {
Navigator.pop(context);
widget.onSave!(cas.values.map((ca) {
return ca;
}).toList());
}
},
child: Column(children: items));
}
title: 'Certificate Authorities',
changed: changed,
onSave: () {
if (widget.onSave != null) {
Navigator.pop(context);
widget.onSave!(cas.values.map((ca) {
return ca;
}).toList());
}
},
child: Column(children: items));
}
List<Widget> _buildCAs() {
List<Widget> items = [];
@ -85,14 +85,16 @@ class _CAListScreenState extends State<CAListScreen> {
onPressed: () {
Utils.openPage(context, (context) {
return CertificateDetailsScreen(
certInfo: ca,
onDelete: widget.onSave == null ? null : () {
setState(() {
changed = true;
cas.remove(key);
});
},
supportsQRScanning: widget.supportsQRScanning,
certInfo: ca,
onDelete: widget.onSave == null
? null
: () {
setState(() {
changed = true;
cas.remove(key);
});
},
supportsQRScanning: widget.supportsQRScanning,
);
});
},

View File

@ -170,19 +170,19 @@ class _CertificateDetailsScreenState extends State<CertificateDetailsScreen> {
onPressed: () {
Utils.openPage(context, (context) {
return AddCertificateScreen(
onReplace: (result) {
setState(() {
changed = true;
certResult = result;
certInfo = result.certInfo;
});
// Slam the page back to the top
controller.animateTo(0,
duration: const Duration(milliseconds: 10), curve: Curves.linearToEaseOut);
},
pubKey: widget.pubKey!,
privKey: widget.privKey!,
supportsQRScanning: widget.supportsQRScanning,
onReplace: (result) {
setState(() {
changed = true;
certResult = result;
certInfo = result.certInfo;
});
// Slam the page back to the top
controller.animateTo(0,
duration: const Duration(milliseconds: 10), curve: Curves.linearToEaseOut);
},
pubKey: widget.pubKey!,
privKey: widget.privKey!,
supportsQRScanning: widget.supportsQRScanning,
);
});
})));

View File

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

View File

@ -139,17 +139,17 @@ class _SiteConfigScreenState extends State<SiteConfigScreen> {
lastUpdate = formatter.format(site.lastManagedUpdate!.toLocal());
}
return site.managed ? ConfigSection(
label: "MANAGED CONFIG",
children: <Widget>[
ConfigItem(
label: Text("Last Update"),
content: Wrap(alignment: WrapAlignment.end, crossAxisAlignment: WrapCrossAlignment.center, children: <Widget>[
Text(lastUpdate),
]),
)
]
) : Container();
return site.managed
? ConfigSection(label: "MANAGED CONFIG", children: <Widget>[
ConfigItem(
label: Text("Last Update"),
content:
Wrap(alignment: WrapAlignment.end, crossAxisAlignment: WrapCrossAlignment.center, children: <Widget>[
Text(lastUpdate),
]),
)
])
: Container();
}
Widget _keys() {
@ -183,30 +183,32 @@ class _SiteConfigScreenState extends State<SiteConfigScreen> {
Utils.openPage(context, (context) {
if (site.certInfo != null) {
return CertificateDetailsScreen(
certInfo: site.certInfo!,
pubKey: pubKey,
privKey: privKey,
onReplace: site.managed ? null : (result) {
setState(() {
changed = true;
site.certInfo = result.certInfo;
site.key = result.key;
});
},
supportsQRScanning: widget.supportsQRScanning,
certInfo: site.certInfo!,
pubKey: pubKey,
privKey: privKey,
onReplace: site.managed
? null
: (result) {
setState(() {
changed = true;
site.certInfo = result.certInfo;
site.key = result.key;
});
},
supportsQRScanning: widget.supportsQRScanning,
);
}
return AddCertificateScreen(
pubKey: pubKey!,
privKey: privKey!,
onSave: (result) {
setState(() {
changed = true;
site.certInfo = result.certInfo;
site.key = result.key;
});
},
pubKey: pubKey!,
privKey: privKey!,
onSave: (result) {
setState(() {
changed = true;
site.certInfo = result.certInfo;
site.key = result.key;
});
},
supportsQRScanning: widget.supportsQRScanning,
);
});
@ -226,14 +228,16 @@ class _SiteConfigScreenState extends State<SiteConfigScreen> {
onPressed: () {
Utils.openPage(context, (context) {
return CAListScreen(
cas: site.ca,
onSave: site.managed ? null : (ca) {
setState(() {
changed = true;
site.ca = ca;
});
},
supportsQRScanning: widget.supportsQRScanning,
cas: site.ca,
onSave: site.managed
? null
: (ca) {
setState(() {
changed = true;
site.ca = ca;
});
},
supportsQRScanning: widget.supportsQRScanning,
);
});
})
@ -261,12 +265,14 @@ class _SiteConfigScreenState extends State<SiteConfigScreen> {
Utils.openPage(context, (context) {
return StaticHostsScreen(
hostmap: site.staticHostmap,
onSave: site.managed ? null : (map) {
setState(() {
changed = true;
site.staticHostmap = map;
});
});
onSave: site.managed
? null
: (map) {
setState(() {
changed = true;
site.staticHostmap = map;
});
});
});
},
),

View File

@ -66,7 +66,11 @@ class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
@override
Widget build(BuildContext context) {
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,
onSave: _onSave,
child: Column(children: [
@ -74,20 +78,20 @@ class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
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;
}
})),
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,
@ -96,12 +100,14 @@ class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
child: Switch.adaptive(
value: _lighthouse,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
onChanged: widget.onSave == null ? null : (v) {
setState(() {
changed = true;
_lighthouse = v;
});
})),
onChanged: widget.onSave == null
? null
: (v) {
setState(() {
changed = true;
_lighthouse = v;
});
})),
),
]),
ConfigSection(
@ -128,8 +134,7 @@ class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
_onSave() {
Navigator.pop(context);
if (widget.onSave != null) {
var map = Hostmap(
nebulaIp: _nebulaIp, destinations: [], lighthouse: _lighthouse);
var map = Hostmap(nebulaIp: _nebulaIp, destinations: [], lighthouse: _lighthouse);
_destinations.forEach((_, dest) {
map.destinations.add(dest.destination);
@ -147,30 +152,32 @@ class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
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();
}))),
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;
}
},
)),
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;
}
},
)),
]),
));
});
@ -178,8 +185,7 @@ class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
if (widget.onSave != null) {
items.add(ConfigButtonItem(
content: Text('Add another'),
onPressed: () =>
setState(() {
onPressed: () => setState(() {
_addDestination();
_dismissKeyboard();
})));

View File

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

View File

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