mirror of
https://github.com/DefinedNet/mobile_nebula.git
synced 2025-01-18 19:27:05 +00:00
64d45f66c7
This updates flutter to 3.24.1, the latest stable version, and also updates our flutter dependencies to latest. It targets the latest android sdk, 34, which is required if we want to publish a new version to the Google Play store. I also needed to make a few adjustments to handle deprecations. The biggest change is that I needed to wrap the main widget in MaterialApp to avoid problems with AdaptiveSwitch in iOS.
203 lines
7.1 KiB
Dart
203 lines
7.1 KiB
Dart
import 'package:flutter/cupertino.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
|
|
import 'package:mobile_nebula/components/SimplePage.dart';
|
|
import 'package:mobile_nebula/components/config/ConfigCheckboxItem.dart';
|
|
import 'package:mobile_nebula/components/config/ConfigItem.dart';
|
|
import 'package:mobile_nebula/components/config/ConfigPageItem.dart';
|
|
import 'package:mobile_nebula/components/config/ConfigSection.dart';
|
|
import 'package:mobile_nebula/models/Certificate.dart';
|
|
import 'package:mobile_nebula/models/HostInfo.dart';
|
|
import 'package:mobile_nebula/models/Site.dart';
|
|
import 'package:mobile_nebula/screens/siteConfig/CertificateDetailsScreen.dart';
|
|
import 'package:mobile_nebula/services/utils.dart';
|
|
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
|
|
|
class HostInfoScreen extends StatefulWidget {
|
|
const HostInfoScreen({
|
|
Key? key,
|
|
required this.hostInfo,
|
|
required this.isLighthouse,
|
|
required this.pending,
|
|
this.onChanged,
|
|
required this.site,
|
|
required this.supportsQRScanning,
|
|
}) : super(key: key);
|
|
|
|
final bool isLighthouse;
|
|
final bool pending;
|
|
final HostInfo hostInfo;
|
|
final Function? onChanged;
|
|
final Site site;
|
|
|
|
final bool supportsQRScanning;
|
|
|
|
@override
|
|
_HostInfoScreenState createState() => _HostInfoScreenState();
|
|
}
|
|
|
|
//TODO: have a config option to refresh hostmaps on a cadence (applies to 3 screens so far)
|
|
|
|
class _HostInfoScreenState extends State<HostInfoScreen> {
|
|
late HostInfo hostInfo;
|
|
RefreshController refreshController = RefreshController(initialRefresh: false);
|
|
|
|
@override
|
|
void initState() {
|
|
_setHostInfo(widget.hostInfo);
|
|
super.initState();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final title = widget.pending ? 'Pending' : 'Active';
|
|
|
|
return SimplePage(
|
|
title: Text('$title Host Info'),
|
|
refreshController: refreshController,
|
|
onRefresh: () async {
|
|
await _getHostInfo();
|
|
refreshController.refreshCompleted();
|
|
},
|
|
leadingAction: Utils.leadingBackWidget(context, onPressed: () {
|
|
Navigator.pop(context);
|
|
}),
|
|
child: Column(
|
|
children: [_buildMain(), _buildDetails(), _buildRemotes(), !widget.pending ? _buildClose() : Container()]));
|
|
}
|
|
|
|
Widget _buildMain() {
|
|
return ConfigSection(children: [
|
|
ConfigItem(label: Text('VPN IP'), labelWidth: 150, content: SelectableText(hostInfo.vpnIp)),
|
|
hostInfo.cert != null
|
|
? ConfigPageItem(
|
|
label: Text('Certificate'),
|
|
labelWidth: 150,
|
|
content: Text(hostInfo.cert!.details.name),
|
|
onPressed: () => Utils.openPage(
|
|
context,
|
|
(context) => CertificateDetailsScreen(
|
|
certInfo: CertificateInfo(cert: hostInfo.cert!),
|
|
supportsQRScanning: widget.supportsQRScanning,
|
|
)))
|
|
: Container(),
|
|
]);
|
|
}
|
|
|
|
Widget _buildDetails() {
|
|
return ConfigSection(children: <Widget>[
|
|
ConfigItem(
|
|
label: Text('Lighthouse'), labelWidth: 150, content: SelectableText(widget.isLighthouse ? 'Yes' : 'No')),
|
|
ConfigItem(label: Text('Local Index'), labelWidth: 150, content: SelectableText('${hostInfo.localIndex}')),
|
|
ConfigItem(label: Text('Remote Index'), labelWidth: 150, content: SelectableText('${hostInfo.remoteIndex}')),
|
|
ConfigItem(
|
|
label: Text('Message Counter'), labelWidth: 150, content: SelectableText('${hostInfo.messageCounter}')),
|
|
]);
|
|
}
|
|
|
|
Widget _buildRemotes() {
|
|
if (hostInfo.remoteAddresses.length == 0) {
|
|
return ConfigSection(
|
|
label: 'REMOTES', children: [ConfigItem(content: Text('No remote addresses yet'), labelWidth: 0)]);
|
|
}
|
|
|
|
return widget.pending ? _buildStaticRemotes() : _buildEditRemotes();
|
|
}
|
|
|
|
Widget _buildEditRemotes() {
|
|
List<Widget> items = [];
|
|
final currentRemote = hostInfo.currentRemote.toString();
|
|
final double ipWidth =
|
|
Utils.textSize("000.000.000.000:000000", CupertinoTheme.of(context).textTheme.textStyle).width;
|
|
|
|
hostInfo.remoteAddresses.forEach((remoteObj) {
|
|
String remote = remoteObj.toString();
|
|
items.add(ConfigCheckboxItem(
|
|
key: Key(remote),
|
|
label: Text(remote), //TODO: need to do something to adjust the font size in the event we have an ipv6 address
|
|
labelWidth: ipWidth,
|
|
checked: currentRemote == remote,
|
|
onChanged: () async {
|
|
if (remote == currentRemote) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
final h = await widget.site.setRemoteForTunnel(hostInfo.vpnIp, remote);
|
|
if (h != null) {
|
|
_setHostInfo(h);
|
|
}
|
|
} catch (err) {
|
|
Utils.popError(context, 'Error while changing the remote', err.toString());
|
|
}
|
|
},
|
|
));
|
|
});
|
|
|
|
return ConfigSection(label: items.length > 0 ? 'Tap to change the active address' : null, children: items);
|
|
}
|
|
|
|
Widget _buildStaticRemotes() {
|
|
List<Widget> items = [];
|
|
final currentRemote = hostInfo.currentRemote.toString();
|
|
final double ipWidth =
|
|
Utils.textSize("000.000.000.000:000000", CupertinoTheme.of(context).textTheme.textStyle).width;
|
|
|
|
hostInfo.remoteAddresses.forEach((remoteObj) {
|
|
String remote = remoteObj.toString();
|
|
items.add(ConfigCheckboxItem(
|
|
key: Key(remote),
|
|
label: Text(remote), //TODO: need to do something to adjust the font size in the event we have an ipv6 address
|
|
labelWidth: ipWidth,
|
|
checked: currentRemote == remote,
|
|
));
|
|
});
|
|
|
|
return ConfigSection(label: items.length > 0 ? 'REMOTES' : null, children: items);
|
|
}
|
|
|
|
Widget _buildClose() {
|
|
return Padding(
|
|
padding: EdgeInsets.only(top: 50, bottom: 10, left: 10, right: 10),
|
|
child: SizedBox(
|
|
width: double.infinity,
|
|
child: PlatformElevatedButton(
|
|
child: Text('Close Tunnel'),
|
|
color: CupertinoColors.systemRed.resolveFrom(context),
|
|
onPressed: () => Utils.confirmDelete(context, 'Close Tunnel?', () async {
|
|
try {
|
|
await widget.site.closeTunnel(hostInfo.vpnIp);
|
|
if (widget.onChanged != null) {
|
|
widget.onChanged!();
|
|
}
|
|
Navigator.pop(context);
|
|
} catch (err) {
|
|
Utils.popError(context, 'Error while trying to close the tunnel', err.toString());
|
|
}
|
|
}, deleteLabel: 'Close'))));
|
|
}
|
|
|
|
_getHostInfo() async {
|
|
try {
|
|
final h = await widget.site.getHostInfo(hostInfo.vpnIp, widget.pending);
|
|
if (h == null) {
|
|
return Utils.popError(context, '', 'The tunnel for this host no longer exists');
|
|
}
|
|
|
|
_setHostInfo(h);
|
|
} catch (err) {
|
|
Utils.popError(context, 'Failed to refresh host info', err.toString());
|
|
}
|
|
}
|
|
|
|
_setHostInfo(HostInfo h) {
|
|
h.remoteAddresses.sort((a, b) {
|
|
final diff = a.ip.compareTo(b.ip);
|
|
return diff == 0 ? a.port - b.port : diff;
|
|
});
|
|
|
|
setState(() {
|
|
hostInfo = h;
|
|
});
|
|
}
|
|
}
|