Format code
This commit is contained in:
parent
b598aa338f
commit
35fbf86c8c
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
],
|
||||
)),
|
||||
);
|
||||
|
|
|
@ -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),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -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"]),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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: () {
|
||||
|
|
|
@ -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(),
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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: [
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
},
|
||||
)),
|
||||
]));
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
)
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
});
|
||||
},
|
||||
|
|
|
@ -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,
|
||||
);
|
||||
});
|
||||
})));
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
),
|
||||
|
|
|
@ -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();
|
||||
})));
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue