mirror of
https://github.com/DefinedNet/mobile_nebula.git
synced 2025-09-07 19:46:06 +00:00
Compare commits
11 commits
c8dcc70632
...
e6f0929e2e
Author | SHA1 | Date | |
---|---|---|---|
|
e6f0929e2e | ||
|
2d0ba84590 | ||
|
1b13646e14 | ||
|
e6c1f19ed7 | ||
|
89974a5958 | ||
|
581c2f3cc6 | ||
|
45f0b38984 | ||
|
67e8896ec5 | ||
|
99e3b4ab17 | ||
|
cbcf435fb9 | ||
|
f58b37468d |
24 changed files with 79 additions and 61 deletions
|
@ -1,12 +1,11 @@
|
||||||
name: Flutter format
|
name: Flutter check
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- '.github/workflows/flutterfmt.yml'
|
- '.github/workflows/fluttercheck.yml'
|
||||||
- '.github/workflows/flutterfmt.sh'
|
|
||||||
- '**.dart'
|
- '**.dart'
|
||||||
jobs:
|
jobs:
|
||||||
flutterfmt:
|
flutterfmt:
|
||||||
|
@ -25,3 +24,19 @@ jobs:
|
||||||
|
|
||||||
- name: Check formating
|
- name: Check formating
|
||||||
run: dart format -l120 lib/ --set-exit-if-changed --suppress-analytics --output none
|
run: dart format -l120 lib/ --set-exit-if-changed --suppress-analytics --output none
|
||||||
|
flutterlint:
|
||||||
|
name: Run flutter lint
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Install flutter
|
||||||
|
uses: subosito/flutter-action@v2
|
||||||
|
with:
|
||||||
|
flutter-version: '3.29.0'
|
||||||
|
|
||||||
|
- name: Check out code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
show-progress: false
|
||||||
|
|
||||||
|
- name: Check linting
|
||||||
|
run: dart fix --dry-run
|
|
@ -111,10 +111,7 @@ class _IPAndPortFormField extends FormFieldState<IPAndPort> {
|
||||||
@override
|
@override
|
||||||
void didUpdateWidget(IPAndPortFormField oldWidget) {
|
void didUpdateWidget(IPAndPortFormField oldWidget) {
|
||||||
super.didUpdateWidget(oldWidget);
|
super.didUpdateWidget(oldWidget);
|
||||||
var update = IPAndPort(
|
var update = IPAndPort(ip: widget.ipController?.text, port: int.tryParse(widget.portController?.text ?? ""));
|
||||||
ip: widget.ipController?.text,
|
|
||||||
port: int.tryParse(widget.portController?.text ?? ""),
|
|
||||||
);
|
|
||||||
bool shouldUpdate = false;
|
bool shouldUpdate = false;
|
||||||
|
|
||||||
if (widget.ipController != oldWidget.ipController) {
|
if (widget.ipController != oldWidget.ipController) {
|
||||||
|
|
|
@ -106,8 +106,9 @@ class _IPFormField extends FormFieldState<String> {
|
||||||
oldWidget.controller?.removeListener(_handleControllerChanged);
|
oldWidget.controller?.removeListener(_handleControllerChanged);
|
||||||
widget.controller?.addListener(_handleControllerChanged);
|
widget.controller?.addListener(_handleControllerChanged);
|
||||||
|
|
||||||
if (oldWidget.controller != null && widget.controller == null)
|
if (oldWidget.controller != null && widget.controller == null) {
|
||||||
_controller = TextEditingController.fromValue(oldWidget.controller!.value);
|
_controller = TextEditingController.fromValue(oldWidget.controller!.value);
|
||||||
|
}
|
||||||
if (widget.controller != null) {
|
if (widget.controller != null) {
|
||||||
setValue(widget.controller!.text);
|
setValue(widget.controller!.text);
|
||||||
if (oldWidget.controller == null) _controller = null;
|
if (oldWidget.controller == null) _controller = null;
|
||||||
|
|
|
@ -115,8 +115,9 @@ class _PlatformTextFormFieldState extends FormFieldState<String> {
|
||||||
oldWidget.controller?.removeListener(_handleControllerChanged);
|
oldWidget.controller?.removeListener(_handleControllerChanged);
|
||||||
widget.controller?.addListener(_handleControllerChanged);
|
widget.controller?.addListener(_handleControllerChanged);
|
||||||
|
|
||||||
if (oldWidget.controller != null && widget.controller == null)
|
if (oldWidget.controller != null && widget.controller == null) {
|
||||||
_controller = TextEditingController.fromValue(oldWidget.controller!.value);
|
_controller = TextEditingController.fromValue(oldWidget.controller!.value);
|
||||||
|
}
|
||||||
if (widget.controller != null) {
|
if (widget.controller != null) {
|
||||||
setValue(widget.controller!.text);
|
setValue(widget.controller!.text);
|
||||||
if (oldWidget.controller == null) _controller = null;
|
if (oldWidget.controller == null) _controller = null;
|
||||||
|
|
|
@ -15,18 +15,18 @@ class ConfigSection extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final border = BorderSide(color: borderColor ?? Utils.configSectionBorder(context));
|
final border = BorderSide(color: borderColor ?? Utils.configSectionBorder(context));
|
||||||
|
|
||||||
List<Widget> _children = [];
|
List<Widget> mappedChildren = [];
|
||||||
final len = children.length;
|
final len = children.length;
|
||||||
|
|
||||||
for (var i = 0; i < len; i++) {
|
for (var i = 0; i < len; i++) {
|
||||||
_children.add(children[i]);
|
mappedChildren.add(children[i]);
|
||||||
|
|
||||||
if (i < len - 1) {
|
if (i < len - 1) {
|
||||||
double pad = 15;
|
double pad = 15;
|
||||||
if (children[i + 1].runtimeType.toString() == 'ConfigButtonItem') {
|
if (children[i + 1].runtimeType.toString() == 'ConfigButtonItem') {
|
||||||
pad = 0;
|
pad = 0;
|
||||||
}
|
}
|
||||||
_children.add(
|
mappedChildren.add(
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsets.only(left: pad),
|
padding: EdgeInsets.only(left: pad),
|
||||||
child: Divider(height: 1, color: Utils.configSectionBorder(context)),
|
child: Divider(height: 1, color: Utils.configSectionBorder(context)),
|
||||||
|
@ -44,7 +44,7 @@ class ConfigSection extends StatelessWidget {
|
||||||
border: Border(top: border, bottom: border),
|
border: Border(top: border, bottom: border),
|
||||||
color: Utils.configItemBackground(context),
|
color: Utils.configItemBackground(context),
|
||||||
),
|
),
|
||||||
child: Column(children: _children),
|
child: Column(children: mappedChildren),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|
|
@ -12,8 +12,10 @@ import 'package:mobile_nebula/services/settings.dart';
|
||||||
import 'package:mobile_nebula/services/theme.dart';
|
import 'package:mobile_nebula/services/theme.dart';
|
||||||
import 'package:mobile_nebula/services/utils.dart';
|
import 'package:mobile_nebula/services/utils.dart';
|
||||||
import 'package:sentry_flutter/sentry_flutter.dart';
|
import 'package:sentry_flutter/sentry_flutter.dart';
|
||||||
|
import 'package:flutter_web_plugins/url_strategy.dart';
|
||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
|
usePathUrlStrategy();
|
||||||
var settings = Settings();
|
var settings = Settings();
|
||||||
if (settings.trackErrors) {
|
if (settings.trackErrors) {
|
||||||
await SentryFlutter.init((options) {
|
await SentryFlutter.init((options) {
|
||||||
|
@ -106,6 +108,7 @@ class _AppState extends State<App> {
|
||||||
},
|
},
|
||||||
cupertino: (_, __) => CupertinoAppData(theme: CupertinoThemeData(brightness: brightness)),
|
cupertino: (_, __) => CupertinoAppData(theme: CupertinoThemeData(brightness: brightness)),
|
||||||
onGenerateRoute: (settings) {
|
onGenerateRoute: (settings) {
|
||||||
|
print(settings);
|
||||||
if (settings.name == '/') {
|
if (settings.name == '/') {
|
||||||
return platformPageRoute(context: context, builder: (context) => MainScreen(dnEnrolled));
|
return platformPageRoute(context: context, builder: (context) => MainScreen(dnEnrolled));
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,9 +3,7 @@ class CertificateInfo {
|
||||||
String? rawCert;
|
String? rawCert;
|
||||||
CertificateValidity? validity;
|
CertificateValidity? validity;
|
||||||
|
|
||||||
CertificateInfo.debug({this.rawCert = ""})
|
CertificateInfo.debug({this.rawCert = ""}) : cert = Certificate.debug(), validity = CertificateValidity.debug();
|
||||||
: cert = Certificate.debug(),
|
|
||||||
validity = CertificateValidity.debug();
|
|
||||||
|
|
||||||
CertificateInfo.fromJson(Map<String, dynamic> json)
|
CertificateInfo.fromJson(Map<String, dynamic> json)
|
||||||
: cert = Certificate.fromJson(json['Cert']),
|
: cert = Certificate.fromJson(json['Cert']),
|
||||||
|
|
|
@ -15,7 +15,7 @@ class Site {
|
||||||
late EventChannel _updates;
|
late EventChannel _updates;
|
||||||
|
|
||||||
/// Signals that something about this site has changed. onError is called with an error string if there was an error
|
/// Signals that something about this site has changed. onError is called with an error string if there was an error
|
||||||
StreamController _change = StreamController.broadcast();
|
final StreamController _change = StreamController.broadcast();
|
||||||
|
|
||||||
// Identifiers
|
// Identifiers
|
||||||
late String name;
|
late String name;
|
||||||
|
@ -169,15 +169,15 @@ class Site {
|
||||||
|
|
||||||
List<dynamic> rawUnsafeRoutes = json['unsafeRoutes'];
|
List<dynamic> rawUnsafeRoutes = json['unsafeRoutes'];
|
||||||
List<UnsafeRoute> unsafeRoutes = [];
|
List<UnsafeRoute> unsafeRoutes = [];
|
||||||
rawUnsafeRoutes.forEach((val) {
|
for (var val in rawUnsafeRoutes) {
|
||||||
unsafeRoutes.add(UnsafeRoute.fromJson(val));
|
unsafeRoutes.add(UnsafeRoute.fromJson(val));
|
||||||
});
|
}
|
||||||
|
|
||||||
List<dynamic> rawCA = json['ca'];
|
List<dynamic> rawCA = json['ca'];
|
||||||
List<CertificateInfo> ca = [];
|
List<CertificateInfo> ca = [];
|
||||||
rawCA.forEach((val) {
|
for (var val in rawCA) {
|
||||||
ca.add(CertificateInfo.fromJson(val));
|
ca.add(CertificateInfo.fromJson(val));
|
||||||
});
|
}
|
||||||
|
|
||||||
CertificateInfo? certInfo;
|
CertificateInfo? certInfo;
|
||||||
if (json['cert'] != null) {
|
if (json['cert'] != null) {
|
||||||
|
@ -186,9 +186,9 @@ class Site {
|
||||||
|
|
||||||
List<dynamic> rawErrors = json["errors"];
|
List<dynamic> rawErrors = json["errors"];
|
||||||
List<String> errors = [];
|
List<String> errors = [];
|
||||||
rawErrors.forEach((error) {
|
for (var error in rawErrors) {
|
||||||
errors.add(error);
|
errors.add(error);
|
||||||
});
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"name": json["name"],
|
"name": json["name"],
|
||||||
|
@ -295,9 +295,9 @@ class Site {
|
||||||
|
|
||||||
List<dynamic> f = jsonDecode(ret);
|
List<dynamic> f = jsonDecode(ret);
|
||||||
List<HostInfo> hosts = [];
|
List<HostInfo> hosts = [];
|
||||||
f.forEach((v) {
|
for (var v in f) {
|
||||||
hosts.add(HostInfo.fromJson(v));
|
hosts.add(HostInfo.fromJson(v));
|
||||||
});
|
}
|
||||||
|
|
||||||
return hosts;
|
return hosts;
|
||||||
} on PlatformException catch (err) {
|
} on PlatformException catch (err) {
|
||||||
|
@ -317,9 +317,9 @@ class Site {
|
||||||
|
|
||||||
List<dynamic> f = jsonDecode(ret);
|
List<dynamic> f = jsonDecode(ret);
|
||||||
List<HostInfo> hosts = [];
|
List<HostInfo> hosts = [];
|
||||||
f.forEach((v) {
|
for (var v in f) {
|
||||||
hosts.add(HostInfo.fromJson(v));
|
hosts.add(HostInfo.fromJson(v));
|
||||||
});
|
}
|
||||||
|
|
||||||
return hosts;
|
return hosts;
|
||||||
} on PlatformException catch (err) {
|
} on PlatformException catch (err) {
|
||||||
|
|
|
@ -10,9 +10,9 @@ class StaticHost {
|
||||||
var list = json['destinations'] as List<dynamic>;
|
var list = json['destinations'] as List<dynamic>;
|
||||||
var result = <IPAndPort>[];
|
var result = <IPAndPort>[];
|
||||||
|
|
||||||
list.forEach((item) {
|
for (var item in list) {
|
||||||
result.add(IPAndPort.fromString(item));
|
result.add(IPAndPort.fromString(item));
|
||||||
});
|
}
|
||||||
|
|
||||||
return StaticHost(lighthouse: json['lighthouse'], destinations: result);
|
return StaticHost(lighthouse: json['lighthouse'], destinations: result);
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,7 @@ class _EnrollmentScreenState extends State<EnrollmentScreen> {
|
||||||
|
|
||||||
static const platform = MethodChannel('net.defined.mobileNebula/NebulaVpnService');
|
static const platform = MethodChannel('net.defined.mobileNebula/NebulaVpnService');
|
||||||
|
|
||||||
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
code = widget.code;
|
code = widget.code;
|
||||||
super.initState();
|
super.initState();
|
||||||
|
@ -172,7 +173,7 @@ class _EnrollmentScreenState extends State<EnrollmentScreen> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _codeEntry() {
|
Widget _codeEntry() {
|
||||||
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
|
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
String? validator(String? value) {
|
String? validator(String? value) {
|
||||||
if (value == null || value.isEmpty) {
|
if (value == null || value.isEmpty) {
|
||||||
|
@ -182,7 +183,7 @@ class _EnrollmentScreenState extends State<EnrollmentScreen> {
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> onSubmit() async {
|
Future<void> onSubmit() async {
|
||||||
final bool isValid = _formKey.currentState?.validate() ?? false;
|
final bool isValid = formKey.currentState?.validate() ?? false;
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -205,7 +206,7 @@ class _EnrollmentScreenState extends State<EnrollmentScreen> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
final form = Form(key: _formKey, child: Platform.isAndroid ? input : ConfigSection(children: [input]));
|
final form = Form(key: formKey, child: Platform.isAndroid ? input : ConfigSection(children: [input]));
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
|
|
|
@ -124,7 +124,7 @@ class _HostInfoScreenState extends State<HostInfoScreen> {
|
||||||
final double ipWidth =
|
final double ipWidth =
|
||||||
Utils.textSize("000.000.000.000:000000", CupertinoTheme.of(context).textTheme.textStyle).width;
|
Utils.textSize("000.000.000.000:000000", CupertinoTheme.of(context).textTheme.textStyle).width;
|
||||||
|
|
||||||
hostInfo.remoteAddresses.forEach((remoteObj) {
|
for (var remoteObj in hostInfo.remoteAddresses) {
|
||||||
String remote = remoteObj.toString();
|
String remote = remoteObj.toString();
|
||||||
items.add(
|
items.add(
|
||||||
ConfigCheckboxItem(
|
ConfigCheckboxItem(
|
||||||
|
@ -148,7 +148,7 @@ class _HostInfoScreenState extends State<HostInfoScreen> {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
|
|
||||||
return ConfigSection(label: items.isNotEmpty ? 'Tap to change the active address' : null, children: items);
|
return ConfigSection(label: items.isNotEmpty ? 'Tap to change the active address' : null, children: items);
|
||||||
}
|
}
|
||||||
|
@ -159,7 +159,7 @@ class _HostInfoScreenState extends State<HostInfoScreen> {
|
||||||
final double ipWidth =
|
final double ipWidth =
|
||||||
Utils.textSize("000.000.000.000:000000", CupertinoTheme.of(context).textTheme.textStyle).width;
|
Utils.textSize("000.000.000.000:000000", CupertinoTheme.of(context).textTheme.textStyle).width;
|
||||||
|
|
||||||
hostInfo.remoteAddresses.forEach((remoteObj) {
|
for (var remoteObj in hostInfo.remoteAddresses) {
|
||||||
String remote = remoteObj.toString();
|
String remote = remoteObj.toString();
|
||||||
items.add(
|
items.add(
|
||||||
ConfigCheckboxItem(
|
ConfigCheckboxItem(
|
||||||
|
@ -169,7 +169,7 @@ class _HostInfoScreenState extends State<HostInfoScreen> {
|
||||||
checked: currentRemote == remote,
|
checked: currentRemote == remote,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
|
|
||||||
return ConfigSection(label: items.isNotEmpty ? 'REMOTES' : null, children: items);
|
return ConfigSection(label: items.isNotEmpty ? 'REMOTES' : null, children: items);
|
||||||
}
|
}
|
||||||
|
|
|
@ -207,7 +207,7 @@ class _MainScreenState extends State<MainScreen> {
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> items = [];
|
List<Widget> items = [];
|
||||||
sites!.forEach((site) {
|
for (var site in sites!) {
|
||||||
items.add(
|
items.add(
|
||||||
SiteItem(
|
SiteItem(
|
||||||
key: Key(site.id),
|
key: Key(site.id),
|
||||||
|
@ -223,7 +223,7 @@ class _MainScreenState extends State<MainScreen> {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
|
|
||||||
Widget child = ReorderableListView(
|
Widget child = ReorderableListView(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
|
|
|
@ -117,14 +117,14 @@ class _SiteDetailScreenState extends State<SiteDetailScreen> {
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Widget> items = [];
|
List<Widget> items = [];
|
||||||
site.errors.forEach((error) {
|
for (var error in site.errors) {
|
||||||
items.add(
|
items.add(
|
||||||
ConfigItem(
|
ConfigItem(
|
||||||
labelWidth: 0,
|
labelWidth: 0,
|
||||||
content: Padding(padding: EdgeInsets.symmetric(vertical: 10), child: SelectableText(error)),
|
content: Padding(padding: EdgeInsets.symmetric(vertical: 10), child: SelectableText(error)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
|
|
||||||
return ConfigSection(
|
return ConfigSection(
|
||||||
label: 'ERRORS',
|
label: 'ERRORS',
|
||||||
|
|
|
@ -85,7 +85,7 @@ class _AdvancedScreenState extends State<AdvancedScreen> {
|
||||||
//TODO: Auto select on focus?
|
//TODO: Auto select on focus?
|
||||||
content:
|
content:
|
||||||
widget.site.managed
|
widget.site.managed
|
||||||
? Text(settings.lhDuration.toString() + " seconds", textAlign: TextAlign.right)
|
? Text("${settings.lhDuration} seconds", textAlign: TextAlign.right)
|
||||||
: PlatformTextFormField(
|
: PlatformTextFormField(
|
||||||
initialValue: settings.lhDuration.toString(),
|
initialValue: settings.lhDuration.toString(),
|
||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
|
|
|
@ -39,9 +39,9 @@ class _CAListScreenState extends State<CAListScreen> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
widget.cas.forEach((ca) {
|
for (var ca in widget.cas) {
|
||||||
cas[ca.cert.fingerprint] = ca;
|
cas[ca.cert.fingerprint] = ca;
|
||||||
});
|
}
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
@ -115,14 +115,14 @@ class _CAListScreenState extends State<CAListScreen> {
|
||||||
var ignored = 0;
|
var ignored = 0;
|
||||||
|
|
||||||
List<dynamic> certs = jsonDecode(rawCerts);
|
List<dynamic> certs = jsonDecode(rawCerts);
|
||||||
certs.forEach((rawCert) {
|
for (var rawCert in certs) {
|
||||||
final info = CertificateInfo.fromJson(rawCert);
|
final info = CertificateInfo.fromJson(rawCert);
|
||||||
if (!info.cert.details.isCa) {
|
if (!info.cert.details.isCa) {
|
||||||
ignored++;
|
ignored++;
|
||||||
return;
|
continue;
|
||||||
}
|
}
|
||||||
cas[info.cert.fingerprint] = info;
|
cas[info.cert.fingerprint] = info;
|
||||||
});
|
}
|
||||||
|
|
||||||
if (ignored > 0) {
|
if (ignored > 0) {
|
||||||
error = 'One or more certificates were ignored because they were not certificate authorities.';
|
error = 'One or more certificates were ignored because they were not certificate authorities.';
|
||||||
|
|
|
@ -7,7 +7,7 @@ class RenderedConfigScreen extends StatelessWidget {
|
||||||
final String config;
|
final String config;
|
||||||
final String name;
|
final String name;
|
||||||
|
|
||||||
RenderedConfigScreen({super.key, required this.config, required this.name});
|
const RenderedConfigScreen({super.key, required this.config, required this.name});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
|
|
@ -163,11 +163,11 @@ class _SiteConfigScreenState extends State<SiteConfigScreen> {
|
||||||
if (!site.managed) {
|
if (!site.managed) {
|
||||||
caError = site.ca.isEmpty;
|
caError = site.ca.isEmpty;
|
||||||
if (!caError) {
|
if (!caError) {
|
||||||
site.ca.forEach((ca) {
|
for (var ca in site.ca) {
|
||||||
if (ca.validity == null || !ca.validity!.valid) {
|
if (ca.validity == null || !ca.validity!.valid) {
|
||||||
caError = true;
|
caError = true;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,9 +50,9 @@ class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
|
||||||
_nebulaIp = widget.nebulaIp;
|
_nebulaIp = widget.nebulaIp;
|
||||||
_lighthouse = widget.lighthouse;
|
_lighthouse = widget.lighthouse;
|
||||||
_destinations = {};
|
_destinations = {};
|
||||||
widget.destinations.forEach((dest) {
|
for (var dest in widget.destinations) {
|
||||||
_destinations[UniqueKey()] = _IPAndPort(focusNode: FocusNode(), destination: dest);
|
_destinations[UniqueKey()] = _IPAndPort(focusNode: FocusNode(), destination: dest);
|
||||||
});
|
}
|
||||||
|
|
||||||
if (_destinations.isEmpty) {
|
if (_destinations.isEmpty) {
|
||||||
_addDestination();
|
_addDestination();
|
||||||
|
|
|
@ -32,7 +32,7 @@ class StaticHostsScreen extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _StaticHostsScreenState extends State<StaticHostsScreen> {
|
class _StaticHostsScreenState extends State<StaticHostsScreen> {
|
||||||
Map<Key, _Hostmap> _hostmap = {};
|
final Map<Key, _Hostmap> _hostmap = {};
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -90,7 +90,7 @@ class _StaticHostsScreenState extends State<StaticHostsScreen> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
labelWidth: ipWidth,
|
labelWidth: ipWidth,
|
||||||
content: Text(host.destinations.length.toString() + ' items', textAlign: TextAlign.end),
|
content: Text('${host.destinations.length} items', textAlign: TextAlign.end),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Utils.openPage(context, (context) {
|
Utils.openPage(context, (context) {
|
||||||
return StaticHostmapScreen(
|
return StaticHostmapScreen(
|
||||||
|
|
|
@ -24,9 +24,9 @@ class _UnsafeRoutesScreenState extends State<UnsafeRoutesScreen> {
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
unsafeRoutes = {};
|
unsafeRoutes = {};
|
||||||
widget.unsafeRoutes.forEach((route) {
|
for (var route in widget.unsafeRoutes) {
|
||||||
unsafeRoutes[UniqueKey()] = route;
|
unsafeRoutes[UniqueKey()] = route;
|
||||||
});
|
}
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,8 +10,8 @@ bool DEFAULT_TRACK_ERRORS = true;
|
||||||
|
|
||||||
class Settings {
|
class Settings {
|
||||||
final _storage = Storage();
|
final _storage = Storage();
|
||||||
StreamController _change = StreamController.broadcast();
|
final StreamController _change = StreamController.broadcast();
|
||||||
var _settings = Map<String, dynamic>();
|
var _settings = <String, dynamic>{};
|
||||||
|
|
||||||
bool get useSystemColors {
|
bool get useSystemColors {
|
||||||
return _getBool('systemDarkMode', true);
|
return _getBool('systemDarkMode', true);
|
||||||
|
|
|
@ -39,12 +39,12 @@ class Utils {
|
||||||
Navigator.push(context, platformPageRoute(context: context, builder: pageToDisplayBuilder));
|
Navigator.push(context, platformPageRoute(context: context, builder: pageToDisplayBuilder));
|
||||||
}
|
}
|
||||||
|
|
||||||
static String itemCountFormat(int items, {singleSuffix = "item", multiSuffix = "items"}) {
|
static String itemCountFormat(int items, {String singleSuffix = "item", String multiSuffix = "items"}) {
|
||||||
if (items == 1) {
|
if (items == 1) {
|
||||||
return items.toString() + " " + singleSuffix;
|
return "$items $singleSuffix";
|
||||||
}
|
}
|
||||||
|
|
||||||
return items.toString() + " " + multiSuffix;
|
return "$items $multiSuffix";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builds a simple leading widget that pops the current screen.
|
/// Builds a simple leading widget that pops the current screen.
|
||||||
|
|
|
@ -188,7 +188,7 @@ packages:
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
flutter_web_plugins:
|
flutter_web_plugins:
|
||||||
dependency: transitive
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
|
|
@ -19,6 +19,8 @@ environment:
|
||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
|
flutter_web_plugins:
|
||||||
|
sdk: flutter
|
||||||
|
|
||||||
# The following adds the Cupertino Icons font to your application.
|
# The following adds the Cupertino Icons font to your application.
|
||||||
# Use with the CupertinoIcons class for iOS style icons.
|
# Use with the CupertinoIcons class for iOS style icons.
|
||||||
|
|
Loading…
Add table
Reference in a new issue