Format code
This commit is contained in:
parent
b598aa338f
commit
35fbf86c8c
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
],
|
],
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
|
|
|
@ -110,11 +110,9 @@ class _AppState extends State<App> {
|
||||||
if (uri.path == EnrollmentScreen.routeName) {
|
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
|
// 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
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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"]),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,37 +91,38 @@ 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(
|
||||||
TextSpan(text: 'If the problem persists, please let us know at '),
|
child: SelectableText.rich(TextSpan(children: [
|
||||||
TextSpan(
|
TextSpan(text: 'If the problem persists, please let us know at '),
|
||||||
text: 'support@defined.net',
|
TextSpan(
|
||||||
style: bodyTextStyle.apply(color: colorScheme.primary),
|
text: 'support@defined.net',
|
||||||
recognizer: TapGestureRecognizer()
|
style: bodyTextStyle.apply(color: colorScheme.primary),
|
||||||
..onTap = () async {
|
recognizer: TapGestureRecognizer()
|
||||||
if (await canLaunchUrl(contactUri)) {
|
..onTap = () async {
|
||||||
print(await launchUrl(contactUri));
|
if (await canLaunchUrl(contactUri)) {
|
||||||
}
|
print(await launchUrl(contactUri));
|
||||||
},
|
}
|
||||||
),
|
},
|
||||||
TextSpan(text: ' and provide the following error:'),
|
),
|
||||||
])), padding: EdgeInsets.only(bottom: 10)),
|
TextSpan(text: ' and provide the following error:'),
|
||||||
|
])),
|
||||||
|
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,47 +131,43 @@ 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() {
|
||||||
return Column(children: [
|
return Column(children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(top: 20),
|
padding: EdgeInsets.only(top: 20),
|
||||||
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: () {
|
||||||
|
|
|
@ -75,10 +75,11 @@ 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,
|
||||||
certInfo: CertificateInfo(cert: hostInfo.cert!),
|
(context) => CertificateDetailsScreen(
|
||||||
supportsQRScanning: widget.supportsQRScanning,
|
certInfo: CertificateInfo(cert: hostInfo.cert!),
|
||||||
)))
|
supportsQRScanning: widget.supportsQRScanning,
|
||||||
|
)))
|
||||||
: Container(),
|
: Container(),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(
|
||||||
_loadSites();
|
onSave: (_) {
|
||||||
}, supportsQRScanning: supportsQRScanning);
|
_loadSites();
|
||||||
|
},
|
||||||
|
supportsQRScanning: supportsQRScanning);
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
refreshController: refreshController,
|
refreshController: refreshController,
|
||||||
|
@ -210,9 +212,9 @@ class _MainScreenState extends State<MainScreen> {
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Utils.openPage(context, (context) {
|
Utils.openPage(context, (context) {
|
||||||
return SiteDetailScreen(
|
return SiteDetailScreen(
|
||||||
site: site,
|
site: site,
|
||||||
onChanged: () => _loadSites(),
|
onChanged: () => _loadSites(),
|
||||||
supportsQRScanning: supportsQRScanning,
|
supportsQRScanning: supportsQRScanning,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
@ -289,16 +291,15 @@ class _MainScreenState extends State<MainScreen> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _debugClearKeys() {
|
Widget _debugClearKeys() {
|
||||||
return CupertinoButton(
|
return CupertinoButton(
|
||||||
child: Text("Clear Keys"),
|
child: Text("Clear Keys"),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await platform.invokeMethod("debug.clearKeys", null);
|
await platform.invokeMethod("debug.clearKeys", null);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_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
|
||||||
|
|
|
@ -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: [
|
||||||
|
|
|
@ -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)))
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
@ -192,16 +193,16 @@ class _SiteDetailScreenState extends State<SiteDetailScreen> {
|
||||||
Utils.openPage(
|
Utils.openPage(
|
||||||
context,
|
context,
|
||||||
(context) => SiteTunnelsScreen(
|
(context) => SiteTunnelsScreen(
|
||||||
pending: false,
|
pending: false,
|
||||||
tunnels: activeHosts!,
|
tunnels: activeHosts!,
|
||||||
site: site,
|
site: site,
|
||||||
onChanged: (hosts) {
|
onChanged: (hosts) {
|
||||||
setState(() {
|
setState(() {
|
||||||
activeHosts = hosts;
|
activeHosts = hosts;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
supportsQRScanning: widget.supportsQRScanning,
|
supportsQRScanning: widget.supportsQRScanning,
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
label: Text("Active"),
|
label: Text("Active"),
|
||||||
content: Container(alignment: Alignment.centerRight, child: active)),
|
content: Container(alignment: Alignment.centerRight, child: active)),
|
||||||
|
@ -212,16 +213,16 @@ class _SiteDetailScreenState extends State<SiteDetailScreen> {
|
||||||
Utils.openPage(
|
Utils.openPage(
|
||||||
context,
|
context,
|
||||||
(context) => SiteTunnelsScreen(
|
(context) => SiteTunnelsScreen(
|
||||||
pending: true,
|
pending: true,
|
||||||
tunnels: pendingHosts!,
|
tunnels: pendingHosts!,
|
||||||
site: site,
|
site: site,
|
||||||
onChanged: (hosts) {
|
onChanged: (hosts) {
|
||||||
setState(() {
|
setState(() {
|
||||||
pendingHosts = hosts;
|
pendingHosts = hosts;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
supportsQRScanning: widget.supportsQRScanning,
|
supportsQRScanning: widget.supportsQRScanning,
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
label: Text("Pending"),
|
label: Text("Pending"),
|
||||||
content: Container(alignment: Alignment.centerRight, child: pending))
|
content: Container(alignment: Alignment.centerRight, child: pending))
|
||||||
|
@ -237,11 +238,11 @@ class _SiteDetailScreenState extends State<SiteDetailScreen> {
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Utils.openPage(context, (context) {
|
Utils.openPage(context, (context) {
|
||||||
return SiteConfigScreen(
|
return SiteConfigScreen(
|
||||||
site: widget.site,
|
site: widget.site,
|
||||||
onSave: (site) async {
|
onSave: (site) async {
|
||||||
changed = true;
|
changed = true;
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
supportsQRScanning: widget.supportsQRScanning,
|
supportsQRScanning: widget.supportsQRScanning,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
|
@ -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,29 +84,26 @@ 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(
|
return PlatformIconButton(
|
||||||
builder: (BuildContext context) {
|
padding: padding,
|
||||||
return PlatformIconButton(
|
icon: Icon(context.platformIcons.share, size: 30),
|
||||||
padding: padding,
|
onPressed: () {
|
||||||
icon: Icon(context.platformIcons.share, size: 30),
|
Share.shareFile(context,
|
||||||
onPressed: () {
|
title: '${widget.site.name} logs',
|
||||||
Share.shareFile(context,
|
filePath: widget.site.logFile,
|
||||||
title: '${widget.site.name} logs',
|
filename: '${widget.site.name}.log');
|
||||||
filePath: widget.site.logFile,
|
},
|
||||||
filename: '${widget.site.name}.log');
|
);
|
||||||
},
|
})),
|
||||||
);
|
|
||||||
}
|
|
||||||
)),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: PlatformIconButton(
|
child: PlatformIconButton(
|
||||||
padding: padding,
|
padding: padding,
|
||||||
icon: Icon(context.platformIcons.downArrow, size: 30),
|
icon: Icon(context.platformIcons.downArrow, size: 30),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
controller.animateTo(controller.position.maxScrollExtent,
|
controller.animateTo(controller.position.maxScrollExtent,
|
||||||
duration: const Duration(milliseconds: 500), curve: Curves.linearToEaseOut);
|
duration: const Duration(milliseconds: 500), curve: Curves.linearToEaseOut);
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -67,17 +66,17 @@ class _SiteTunnelsScreenState extends State<SiteTunnelsScreen> {
|
||||||
|
|
||||||
children.add(ConfigPageItem(
|
children.add(ConfigPageItem(
|
||||||
onPressed: () => Utils.openPage(
|
onPressed: () => Utils.openPage(
|
||||||
context,
|
context,
|
||||||
(context) => HostInfoScreen(
|
(context) => HostInfoScreen(
|
||||||
isLighthouse: isLh,
|
isLighthouse: isLh,
|
||||||
hostInfo: hostInfo,
|
hostInfo: hostInfo,
|
||||||
pending: widget.pending,
|
pending: widget.pending,
|
||||||
site: widget.site,
|
site: widget.site,
|
||||||
onChanged: () {
|
onChanged: () {
|
||||||
_listHostmap();
|
_listHostmap();
|
||||||
},
|
},
|
||||||
supportsQRScanning: widget.supportsQRScanning,
|
supportsQRScanning: widget.supportsQRScanning,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
label: Row(children: <Widget>[Padding(child: icon, padding: EdgeInsets.only(right: 10)), Text(hostInfo.vpnIp)]),
|
label: Row(children: <Widget>[Padding(child: icon, padding: EdgeInsets.only(right: 10)), Text(hostInfo.vpnIp)]),
|
||||||
labelWidth: ipWidth,
|
labelWidth: ipWidth,
|
||||||
|
|
|
@ -98,12 +98,10 @@ 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');
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
])
|
])
|
||||||
];
|
];
|
||||||
|
@ -269,12 +267,12 @@ class _AddCertificateScreenState extends State<AddCertificateScreen> {
|
||||||
// We have a cert, pop the details screen where they can hit save
|
// We have a cert, pop the details screen where they can hit save
|
||||||
Utils.openPage(context, (context) {
|
Utils.openPage(context, (context) {
|
||||||
return CertificateDetailsScreen(
|
return CertificateDetailsScreen(
|
||||||
certInfo: tryCertInfo,
|
certInfo: tryCertInfo,
|
||||||
onSave: () {
|
onSave: () {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
widget.onSave!(CertificateResult(certInfo: tryCertInfo, key: keyController.text));
|
widget.onSave!(CertificateResult(certInfo: tryCertInfo, key: keyController.text));
|
||||||
},
|
},
|
||||||
supportsQRScanning: widget.supportsQRScanning,
|
supportsQRScanning: widget.supportsQRScanning,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,62 +86,62 @@ 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"),
|
||||||
textAlign: TextAlign.right,
|
textAlign: TextAlign.right,
|
||||||
maxLength: 5,
|
maxLength: 5,
|
||||||
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||||
onSaved: (val) {
|
onSaved: (val) {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (val != null) {
|
if (val != null) {
|
||||||
settings.lhDuration = int.parse(val);
|
settings.lhDuration = int.parse(val);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
ConfigItem(
|
ConfigItem(
|
||||||
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,
|
||||||
maxLength: 5,
|
maxLength: 5,
|
||||||
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||||
onSaved: (val) {
|
onSaved: (val) {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (val != null) {
|
if (val != null) {
|
||||||
settings.port = int.parse(val);
|
settings.port = int.parse(val);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
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,
|
||||||
maxLength: 5,
|
maxLength: 5,
|
||||||
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||||
onSaved: (val) {
|
onSaved: (val) {
|
||||||
setState(() {
|
setState(() {
|
||||||
if (val != null) {
|
if (val != null) {
|
||||||
settings.mtu = int.parse(val);
|
settings.mtu = int.parse(val);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
ConfigPageItem(
|
ConfigPageItem(
|
||||||
disabled: widget.site.managed,
|
disabled: widget.site.managed,
|
||||||
label: Text('Cipher'),
|
label: Text('Cipher'),
|
||||||
|
@ -184,12 +184,14 @@ 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
|
||||||
setState(() {
|
? null
|
||||||
settings.unsafeRoutes = routes;
|
: (routes) {
|
||||||
changed = true;
|
setState(() {
|
||||||
});
|
settings.unsafeRoutes = routes;
|
||||||
});
|
changed = true;
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
@ -64,18 +64,18 @@ class _CAListScreenState extends State<CAListScreen> {
|
||||||
}
|
}
|
||||||
|
|
||||||
return FormPage(
|
return FormPage(
|
||||||
title: 'Certificate Authorities',
|
title: 'Certificate Authorities',
|
||||||
changed: changed,
|
changed: changed,
|
||||||
onSave: () {
|
onSave: () {
|
||||||
if (widget.onSave != null) {
|
if (widget.onSave != null) {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
widget.onSave!(cas.values.map((ca) {
|
widget.onSave!(cas.values.map((ca) {
|
||||||
return ca;
|
return ca;
|
||||||
}).toList());
|
}).toList());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Column(children: items));
|
child: Column(children: items));
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> _buildCAs() {
|
List<Widget> _buildCAs() {
|
||||||
List<Widget> items = [];
|
List<Widget> items = [];
|
||||||
|
@ -85,14 +85,16 @@ class _CAListScreenState extends State<CAListScreen> {
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
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
|
||||||
setState(() {
|
? null
|
||||||
changed = true;
|
: () {
|
||||||
cas.remove(key);
|
setState(() {
|
||||||
});
|
changed = true;
|
||||||
},
|
cas.remove(key);
|
||||||
supportsQRScanning: widget.supportsQRScanning,
|
});
|
||||||
|
},
|
||||||
|
supportsQRScanning: widget.supportsQRScanning,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -170,19 +170,19 @@ class _CertificateDetailsScreenState extends State<CertificateDetailsScreen> {
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Utils.openPage(context, (context) {
|
Utils.openPage(context, (context) {
|
||||||
return AddCertificateScreen(
|
return AddCertificateScreen(
|
||||||
onReplace: (result) {
|
onReplace: (result) {
|
||||||
setState(() {
|
setState(() {
|
||||||
changed = true;
|
changed = true;
|
||||||
certResult = result;
|
certResult = result;
|
||||||
certInfo = result.certInfo;
|
certInfo = result.certInfo;
|
||||||
});
|
});
|
||||||
// Slam the page back to the top
|
// Slam the page back to the top
|
||||||
controller.animateTo(0,
|
controller.animateTo(0,
|
||||||
duration: const Duration(milliseconds: 10), curve: Curves.linearToEaseOut);
|
duration: const Duration(milliseconds: 10), curve: Curves.linearToEaseOut);
|
||||||
},
|
},
|
||||||
pubKey: widget.pubKey!,
|
pubKey: widget.pubKey!,
|
||||||
privKey: widget.privKey!,
|
privKey: widget.privKey!,
|
||||||
supportsQRScanning: widget.supportsQRScanning,
|
supportsQRScanning: widget.supportsQRScanning,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
})));
|
})));
|
||||||
|
|
|
@ -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: () => Share.share(context, title: '$name.yaml', text: config, filename: '$name.yaml'),
|
||||||
onPressed: () =>
|
);
|
||||||
Share.share(context,
|
}),
|
||||||
title: '$name.yaml', text: config, filename: '$name.yaml'),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: EdgeInsets.all(5),
|
padding: EdgeInsets.all(5),
|
||||||
|
|
|
@ -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:
|
||||||
content: Wrap(alignment: WrapAlignment.end, crossAxisAlignment: WrapCrossAlignment.center, children: <Widget>[
|
Wrap(alignment: WrapAlignment.end, crossAxisAlignment: WrapCrossAlignment.center, children: <Widget>[
|
||||||
Text(lastUpdate),
|
Text(lastUpdate),
|
||||||
]),
|
]),
|
||||||
)
|
)
|
||||||
]
|
])
|
||||||
) : Container();
|
: Container();
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _keys() {
|
Widget _keys() {
|
||||||
|
@ -183,30 +183,32 @@ class _SiteConfigScreenState extends State<SiteConfigScreen> {
|
||||||
Utils.openPage(context, (context) {
|
Utils.openPage(context, (context) {
|
||||||
if (site.certInfo != null) {
|
if (site.certInfo != null) {
|
||||||
return CertificateDetailsScreen(
|
return CertificateDetailsScreen(
|
||||||
certInfo: site.certInfo!,
|
certInfo: site.certInfo!,
|
||||||
pubKey: pubKey,
|
pubKey: pubKey,
|
||||||
privKey: privKey,
|
privKey: privKey,
|
||||||
onReplace: site.managed ? null : (result) {
|
onReplace: site.managed
|
||||||
setState(() {
|
? null
|
||||||
changed = true;
|
: (result) {
|
||||||
site.certInfo = result.certInfo;
|
setState(() {
|
||||||
site.key = result.key;
|
changed = true;
|
||||||
});
|
site.certInfo = result.certInfo;
|
||||||
},
|
site.key = result.key;
|
||||||
supportsQRScanning: widget.supportsQRScanning,
|
});
|
||||||
|
},
|
||||||
|
supportsQRScanning: widget.supportsQRScanning,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return AddCertificateScreen(
|
return AddCertificateScreen(
|
||||||
pubKey: pubKey!,
|
pubKey: pubKey!,
|
||||||
privKey: privKey!,
|
privKey: privKey!,
|
||||||
onSave: (result) {
|
onSave: (result) {
|
||||||
setState(() {
|
setState(() {
|
||||||
changed = true;
|
changed = true;
|
||||||
site.certInfo = result.certInfo;
|
site.certInfo = result.certInfo;
|
||||||
site.key = result.key;
|
site.key = result.key;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
supportsQRScanning: widget.supportsQRScanning,
|
supportsQRScanning: widget.supportsQRScanning,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -226,14 +228,16 @@ class _SiteConfigScreenState extends State<SiteConfigScreen> {
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
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
|
||||||
setState(() {
|
? null
|
||||||
changed = true;
|
: (ca) {
|
||||||
site.ca = ca;
|
setState(() {
|
||||||
});
|
changed = true;
|
||||||
},
|
site.ca = ca;
|
||||||
supportsQRScanning: widget.supportsQRScanning,
|
});
|
||||||
|
},
|
||||||
|
supportsQRScanning: widget.supportsQRScanning,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
@ -261,12 +265,14 @@ 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
|
||||||
setState(() {
|
? null
|
||||||
changed = true;
|
: (map) {
|
||||||
site.staticHostmap = map;
|
setState(() {
|
||||||
});
|
changed = true;
|
||||||
});
|
site.staticHostmap = map;
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|
|
@ -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,20 +78,20 @@ 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,
|
||||||
textAlign: TextAlign.end,
|
textAlign: TextAlign.end,
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
onSaved: (v) {
|
onSaved: (v) {
|
||||||
if (v != null) {
|
if (v != null) {
|
||||||
_nebulaIp = v;
|
_nebulaIp = v;
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
ConfigItem(
|
ConfigItem(
|
||||||
label: Text('Lighthouse'),
|
label: Text('Lighthouse'),
|
||||||
labelWidth: 200,
|
labelWidth: 200,
|
||||||
|
@ -96,12 +100,14 @@ 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
|
||||||
setState(() {
|
? null
|
||||||
changed = true;
|
: (v) {
|
||||||
_lighthouse = v;
|
setState(() {
|
||||||
});
|
changed = true;
|
||||||
})),
|
_lighthouse = v;
|
||||||
|
});
|
||||||
|
})),
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
ConfigSection(
|
ConfigSection(
|
||||||
|
@ -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,30 +152,32 @@ 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
|
||||||
padding: EdgeInsets.zero,
|
? Container()
|
||||||
icon: Icon(Icons.remove_circle, color: CupertinoColors.systemRed.resolveFrom(context)),
|
: PlatformIconButton(
|
||||||
onPressed: () => setState(() {
|
padding: EdgeInsets.zero,
|
||||||
_removeDestination(key);
|
icon: Icon(Icons.remove_circle, color: CupertinoColors.systemRed.resolveFrom(context)),
|
||||||
_dismissKeyboard();
|
onPressed: () => setState(() {
|
||||||
}))),
|
_removeDestination(key);
|
||||||
|
_dismissKeyboard();
|
||||||
|
}))),
|
||||||
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,
|
||||||
noBorder: true,
|
noBorder: true,
|
||||||
initialValue: dest.destination,
|
initialValue: dest.destination,
|
||||||
onSaved: (v) {
|
onSaved: (v) {
|
||||||
if (v != null) {
|
if (v != null) {
|
||||||
dest.destination = v;
|
dest.destination = v;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)),
|
)),
|
||||||
]),
|
]),
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
|
@ -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();
|
||||||
})));
|
})));
|
||||||
|
|
|
@ -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,20 +97,24 @@ 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
|
||||||
setState(() {
|
? null
|
||||||
changed = true;
|
: (map) {
|
||||||
host.nebulaIp = map.nebulaIp;
|
setState(() {
|
||||||
host.destinations = map.destinations;
|
changed = true;
|
||||||
host.lighthouse = map.lighthouse;
|
host.nebulaIp = map.nebulaIp;
|
||||||
});
|
host.destinations = map.destinations;
|
||||||
},
|
host.lighthouse = map.lighthouse;
|
||||||
onDelete: widget.onSave == null ? null : () {
|
});
|
||||||
setState(() {
|
},
|
||||||
changed = true;
|
onDelete: widget.onSave == null
|
||||||
_hostmap.remove(key);
|
? null
|
||||||
});
|
: () {
|
||||||
});
|
setState(() {
|
||||||
|
changed = true;
|
||||||
|
_hostmap.remove(key);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
));
|
));
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue