Update Flutter, target android SDK 34 (#160)

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.
This commit is contained in:
Ian VanSchooten 2024-09-20 14:19:23 -04:00 committed by GitHub
parent f576aa0c50
commit 64d45f66c7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
45 changed files with 760 additions and 618 deletions

View File

@ -18,7 +18,7 @@ jobs:
- name: Install flutter
uses: subosito/flutter-action@v2
with:
flutter-version: '3.3.5'
flutter-version: '3.24.1'
- name: Check out code
uses: actions/checkout@v3

View File

@ -24,7 +24,7 @@ jobs:
- name: Install flutter
uses: subosito/flutter-action@v2
with:
flutter-version: '3.3.5'
flutter-version: '3.24.1'
- uses: nttld/setup-ndk@v1
id: setup-ndk

View File

@ -8,7 +8,7 @@ Install all of the following things:
- [`xcode`](https://apps.apple.com/us/app/xcode/)
- [`android-studio`](https://developer.android.com/studio)
- [`flutter` 3.3.5](https://docs.flutter.dev/get-started/install)
- [`flutter` 3.24.1](https://docs.flutter.dev/get-started/install)
- [`gomobile`](https://pkg.go.dev/golang.org/x/mobile/cmd/gomobile)
- [Flutter Android Studio Extension](https://docs.flutter.dev/get-started/editor?tab=androidstudio)

View File

@ -1,3 +1,9 @@
plugins {
id "com.android.application"
id "kotlin-android"
id "dev.flutter.flutter-gradle-plugin"
}
def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
@ -6,10 +12,6 @@ if (localPropertiesFile.exists()) {
}
}
def flutterRoot = localProperties.getProperty('flutter.sdk')
if (flutterRoot == null) {
throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.")
}
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')
if (flutterVersionCode == null) {
@ -21,15 +23,10 @@ if (flutterVersionName == null) {
flutterVersionName = '1.0'
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
namespace "net.defined.mobile_nebula"
compileSdkVersion 33
ndkVersion flutter.ndkVersion
compileSdkVersion 34
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
@ -37,7 +34,7 @@ android {
}
kotlinOptions {
jvmTarget = '1.8'
jvmTarget = JavaVersion.VERSION_1_8
}
sourceSets {
@ -47,7 +44,7 @@ android {
defaultConfig {
applicationId "net.defined.mobile_nebula"
minSdkVersion 26 //flutter.minSdkVersion
targetSdkVersion 33 //flutter.targetSdkVersion
targetSdkVersion 34 //flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
}
@ -80,7 +77,7 @@ flutter {
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
def workVersion = "2.7.1"
implementation "androidx.security:security-crypto:1.0.0"
implementation "androidx.work:work-runtime-ktx:$workVersion"
implementation 'com.google.code.gson:gson:2.8.9'

View File

@ -1,20 +1,3 @@
buildscript {
ext {
workVersion = "2.7.1"
kotlinVersion = '1.7.20'
}
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.3.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
}
}
allprojects {
repositories {
google()

View File

@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip

View File

@ -1,11 +1,25 @@
include ':app', ':mobileNebula'
pluginManagement {
def flutterSdkPath = {
def properties = new Properties()
file("local.properties").withInputStream { properties.load(it) }
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
return flutterSdkPath
}()
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
def properties = new Properties()
includeBuild("$flutterSdkPath/packages/flutter_tools/gradle")
assert localPropertiesFile.exists()
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
repositories {
google()
mavenCentral()
gradlePluginPortal()
}
}
def flutterSdkPath = properties.getProperty("flutter.sdk")
assert flutterSdkPath != null, "flutter.sdk not set in local.properties"
apply from: "$flutterSdkPath/packages/flutter_tools/gradle/app_plugin_loader.gradle"
plugins {
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
id "com.android.application" version "7.4.2" apply false
id "org.jetbrains.kotlin.android" version "1.7.20" apply false
}
include ':app', ':mobileNebula'

View File

@ -21,6 +21,6 @@
<key>CFBundleVersion</key>
<string>1.0</string>
<key>MinimumOSVersion</key>
<string>11.0</string>
<string>12.0</string>
</dict>
</plist>

View File

@ -38,8 +38,9 @@ PODS:
- Flutter
- package_info (0.0.1):
- Flutter
- path_provider_ios (0.0.1):
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- SDWebImage (5.15.5):
- SDWebImage/Core (= 5.15.5)
- SDWebImage/Core (5.15.5)
@ -55,7 +56,7 @@ DEPENDENCIES:
- Flutter (from `Flutter`)
- flutter_barcode_scanner (from `.symlinks/plugins/flutter_barcode_scanner/ios`)
- package_info (from `.symlinks/plugins/package_info/ios`)
- path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
- SwiftyJSON (~> 5.0)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
@ -77,8 +78,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/flutter_barcode_scanner/ios"
package_info:
:path: ".symlinks/plugins/package_info/ios"
path_provider_ios:
:path: ".symlinks/plugins/path_provider_ios/ios"
path_provider_foundation:
:path: ".symlinks/plugins/path_provider_foundation/darwin"
share_plus:
:path: ".symlinks/plugins/share_plus/ios"
url_launcher_ios:
@ -87,17 +88,17 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
file_picker: 817ab1d8cd2da9d2da412a417162deee3500fc95
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
flutter_barcode_scanner: 7a1144744c28dc0c57a8de7218ffe5ec59a9e4bf
package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
path_provider_ios: 7d7ce634493af4477d156294792024ec3485acd5
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
SDWebImage: fd7e1a22f00303e058058278639bf6196ee431fe
share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
share_plus: 8875f4f2500512ea181eef553c3e27dba5135aad
SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f
SwiftyJSON: 2f33a42c6fbc52764d96f13368585094bfd8aa5e
url_launcher_ios: 02f1989d4e14e998335b02b67a7590fa34f971af
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
PODFILE CHECKSUM: b4b37a776e1b487bf31fc5e5014fa5a74f5a022a
COCOAPODS: 1.11.3
COCOAPODS: 1.15.2

View File

@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 52;
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
@ -266,9 +266,9 @@
97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
43AA89612444DA6500EDC39C /* Embed App Extensions */,
00C7A79AE88792090BDAC68B /* [CP] Embed Pods Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */,
);
buildRules = (
);
@ -287,7 +287,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1140;
LastUpgradeCheck = 1300;
LastUpgradeCheck = 1510;
ORGANIZATIONNAME = "The Chromium Authors";
TargetAttributes = {
43AA89532444DA6500EDC39C = {
@ -358,7 +358,7 @@
"${BUILT_PRODUCTS_DIR}/file_picker/file_picker.framework",
"${BUILT_PRODUCTS_DIR}/flutter_barcode_scanner/flutter_barcode_scanner.framework",
"${BUILT_PRODUCTS_DIR}/package_info/package_info.framework",
"${BUILT_PRODUCTS_DIR}/path_provider_ios/path_provider_ios.framework",
"${BUILT_PRODUCTS_DIR}/path_provider_foundation/path_provider_foundation.framework",
"${BUILT_PRODUCTS_DIR}/share_plus/share_plus.framework",
"${BUILT_PRODUCTS_DIR}/url_launcher_ios/url_launcher_ios.framework",
);
@ -372,7 +372,7 @@
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/file_picker.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_barcode_scanner.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider_ios.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider_foundation.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/share_plus.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher_ios.framework",
);
@ -405,10 +405,12 @@
};
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${TARGET_BUILD_DIR}/${INFOPLIST_PATH}",
);
name = "Thin Binary";
outputPaths = (
@ -419,6 +421,7 @@
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1300"
LastUpgradeVersion = "1510"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"

View File

@ -12,7 +12,7 @@ func MissingArgumentError(message: String, details: Any?) -> FlutterError {
return FlutterError(code: "missing_argument", message: message, details: details)
}
@UIApplicationMain
@main
@objc class AppDelegate: FlutterAppDelegate {
private let dnUpdater = DNUpdater()
private let apiClient = APIClient()

View File

@ -64,5 +64,7 @@
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
</dict>
</plist>

View File

@ -1,5 +1,3 @@
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/widgets.dart';
import 'package:mobile_nebula/components/SimplePage.dart';
@ -40,19 +38,17 @@ class _FormPageState extends State<FormPage> {
Widget build(BuildContext context) {
changed = widget.changed || changed;
return WillPopScope(
onWillPop: () {
if (!changed) {
return Future.value(true);
return PopScope<Object?>(
canPop: false,
onPopInvokedWithResult: (bool didPop, Object? result) async {
if (didPop) {
return;
}
var completer = Completer<bool>();
final NavigatorState navigator = Navigator.of(context);
Utils.confirmDelete(context, 'Discard changes?', () {
completer.complete(true);
navigator.pop();
}, deleteLabel: 'Yes', cancelLabel: 'No');
return completer.future;
},
child: SimplePage(
leadingAction: _buildLeader(context),

View File

@ -28,7 +28,8 @@ class SiteItem extends StatelessWidget {
Widget _buildContent(BuildContext context) {
final border = BorderSide(color: Utils.configSectionBorder(context));
final dnIcon = Theme.of(context).brightness == Brightness.dark ? 'images/dn-logo-dark.svg' : 'images/dn-logo-light.svg';
final dnIcon =
Theme.of(context).brightness == Brightness.dark ? 'images/dn-logo-dark.svg' : 'images/dn-logo-light.svg';
return SpecialButton(
decoration:
@ -39,9 +40,9 @@ class SiteItem extends StatelessWidget {
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
site.managed ?
Padding(padding: EdgeInsets.only(right: 10), child: SvgPicture.asset(dnIcon, width: 12)) :
Container(),
site.managed
? Padding(padding: EdgeInsets.only(right: 10), child: SvgPicture.asset(dnIcon, width: 12))
: Container(),
Expanded(child: Text(site.name, style: TextStyle(fontWeight: FontWeight.bold))),
Padding(padding: EdgeInsets.only(right: 10)),
Icon(CupertinoIcons.forward, color: CupertinoColors.placeholderText.resolveFrom(context), size: 18)

View File

@ -28,7 +28,7 @@ class _SpecialButtonState extends State<SpecialButton> with SingleTickerProvider
Widget _buildAndroid() {
var textStyle;
if (widget.useButtonTheme) {
textStyle = Theme.of(context).textTheme.button;
textStyle = Theme.of(context).textTheme.labelLarge;
}
return Material(

View File

@ -90,7 +90,7 @@ class _SpecialTextFieldState extends State<SpecialTextField> {
autofocus: widget.autofocus,
focusNode: widget.focusNode,
onChanged: widget.onChanged,
enabled: widget.enabled,
enabled: widget.enabled ?? true,
onSubmitted: (_) {
if (widget.nextFocusNode != null) {
FocusScope.of(context).requestFocus(widget.nextFocusNode);

View File

@ -4,7 +4,7 @@ import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
TextStyle basicTextStyle(BuildContext context) =>
Platform.isIOS ? CupertinoTheme.of(context).textTheme.textStyle : Theme.of(context).textTheme.subtitle1!;
Platform.isIOS ? CupertinoTheme.of(context).textTheme.textStyle : Theme.of(context).textTheme.titleMedium!;
const double _headerFontSize = 13.0;

View File

@ -31,7 +31,7 @@ class ConfigPageItem extends StatelessWidget {
final origTheme = Theme.of(context);
theme = origTheme.copyWith(
textTheme: origTheme.textTheme
.copyWith(button: origTheme.textTheme.button!.copyWith(fontWeight: FontWeight.normal)));
.copyWith(labelLarge: origTheme.textTheme.labelLarge!.copyWith(fontWeight: FontWeight.normal)));
return Theme(data: theme, child: _buildContent(context));
} else {
final origTheme = CupertinoTheme.of(context);
@ -52,7 +52,9 @@ class ConfigPageItem extends StatelessWidget {
children: <Widget>[
label != null ? Container(width: labelWidth, child: label) : Container(),
Expanded(child: Container(child: content, padding: EdgeInsets.only(right: 10))),
this.disabled ? Container() : Icon(CupertinoIcons.forward, color: CupertinoColors.placeholderText.resolveFrom(context), size: 18)
this.disabled
? Container()
: Icon(CupertinoIcons.forward, color: CupertinoColors.placeholderText.resolveFrom(context), size: 18)
],
)),
);

View File

@ -2,7 +2,7 @@ import 'dart:async';
import 'package:flutter/cupertino.dart' show CupertinoThemeData, DefaultCupertinoLocalizations;
import 'package:flutter/material.dart'
show BottomSheetThemeData, Colors, DefaultMaterialLocalizations, Theme, ThemeData, ThemeMode;
show BottomSheetThemeData, Colors, DefaultMaterialLocalizations, ThemeData, ThemeMode, MaterialApp, Scaffold;
import 'package:flutter/scheduler.dart';
import 'package:flutter/services.dart';
import 'package:flutter/widgets.dart';
@ -32,7 +32,7 @@ class App extends StatefulWidget {
class _AppState extends State<App> {
final settings = Settings();
Brightness brightness = SchedulerBinding.instance.window.platformBrightness;
Brightness brightness = SchedulerBinding.instance.platformDispatcher.platformBrightness;
StreamController dnEnrolled = StreamController.broadcast();
@override
@ -58,12 +58,10 @@ class _AppState extends State<App> {
@override
Widget build(BuildContext context) {
final ThemeData lightTheme = ThemeData(
useMaterial3: false,
brightness: Brightness.light,
primarySwatch: Colors.blueGrey,
primaryColor: Colors.blueGrey[900],
primaryColorBrightness: Brightness.dark,
accentColor: Colors.cyan[600],
accentColorBrightness: Brightness.dark,
fontFamily: 'PublicSans',
//scaffoldBackgroundColor: Colors.grey[100],
scaffoldBackgroundColor: Colors.white,
@ -73,12 +71,10 @@ class _AppState extends State<App> {
);
final ThemeData darkTheme = ThemeData(
useMaterial3: false,
brightness: Brightness.dark,
primarySwatch: Colors.grey,
primaryColor: Colors.grey[900],
primaryColorBrightness: Brightness.dark,
accentColor: Colors.cyan[600],
accentColorBrightness: Brightness.dark,
fontFamily: 'PublicSans',
scaffoldBackgroundColor: Colors.grey[800],
bottomSheetTheme: BottomSheetThemeData(
@ -86,10 +82,10 @@ class _AppState extends State<App> {
),
);
// This theme is required since icons light/dark mode will look for it
return Theme(
data: brightness == Brightness.light ? lightTheme : darkTheme,
child: PlatformProvider(
return MaterialApp(
theme: brightness == Brightness.light ? lightTheme : darkTheme,
home: Scaffold(
body: PlatformProvider(
//initialPlatform: initialPlatform,
builder: (context) => PlatformApp(
debugShowCheckedModeBanner: false,
@ -116,11 +112,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),
);
}
@ -128,6 +122,7 @@ class _AppState extends State<App> {
},
),
),
),
);
}
}

View File

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

View File

@ -6,7 +6,7 @@ import 'package:mobile_nebula/components/config/ConfigPageItem.dart';
import 'package:mobile_nebula/components/config/ConfigSection.dart';
import 'package:mobile_nebula/gen.versions.dart';
import 'package:mobile_nebula/services/utils.dart';
import 'package:package_info/package_info.dart';
import 'package:package_info_plus/package_info_plus.dart';
class AboutScreen extends StatefulWidget {
const AboutScreen({Key? key}) : super(key: key);

View File

@ -4,7 +4,6 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:flutter_svg/svg.dart';
import 'package:mobile_nebula/components/SimplePage.dart';
import 'package:url_launcher/url_launcher.dart';
@ -91,37 +90,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 +130,41 @@ 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';
return SimplePage(
title: Text('Enroll with Managed Nebula', style: TextStyle(fontWeight: FontWeight.bold)),
child: Padding(child: child, padding: EdgeInsets.symmetric(horizontal: 10)),
alignment: alignment
);
title: Text('Enroll with Managed Nebula', style: TextStyle(fontWeight: FontWeight.bold)),
child: Padding(child: child, padding: EdgeInsets.symmetric(horizontal: 10)),
alignment: alignment);
}
Widget _codeEntry() {
return Column(children: [
Padding(
padding: EdgeInsets.only(top: 20),
child: PlatformTextField(
hintText: 'defined.net enrollment code or link',
controller: enrollInput,
)
),
padding: EdgeInsets.only(top: 20),
child: PlatformTextField(
hintText: 'defined.net enrollment code or link',
controller: enrollInput,
)),
PlatformTextButton(
child: Text('Submit'),
onPressed: () {

View File

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

View File

@ -14,7 +14,6 @@ import 'package:mobile_nebula/models/IPAndPort.dart';
import 'package:mobile_nebula/models/Site.dart';
import 'package:mobile_nebula/models/StaticHosts.dart';
import 'package:mobile_nebula/models/UnsafeRoute.dart';
import 'package:mobile_nebula/screens/EnrollmentScreen.dart';
import 'package:mobile_nebula/screens/SettingsScreen.dart';
import 'package:mobile_nebula/screens/SiteDetailScreen.dart';
import 'package:mobile_nebula/screens/siteConfig/SiteConfigScreen.dart';
@ -128,9 +127,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 +142,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 +211,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,28 +290,23 @@ 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'));
bool hasErrors = false;
sites = [];
rawSites.forEach((id, rawSite) {
try {
var site = Site.fromJson(rawSite);
if (site.errors.length > 0) {
hasErrors = true;
}
//TODO: we need to cancel change listeners when we rebuild
site.onChange().listen((_) {
@ -322,7 +318,6 @@ class _MainScreenState extends State<MainScreen> {
}
});
sites!.add(site);
} catch (err) {
//TODO: handle error

View File

@ -1,7 +1,6 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_svg/svg.dart';
import 'package:mobile_nebula/components/SimplePage.dart';
import 'package:mobile_nebula/components/config/ConfigItem.dart';
import 'package:mobile_nebula/components/config/ConfigPageItem.dart';
@ -86,13 +85,12 @@ class _SettingsScreenState extends State<SettingsScreen> {
)),
));
final dnIcon = Theme.of(context).brightness == Brightness.dark ? 'images/dn-logo-dark.svg' : 'images/dn-logo-light.svg';
items.add(ConfigSection(children: [
ConfigPageItem(
label: Text('Enroll with Managed Nebula'),
labelWidth: 200,
onPressed: () => Utils.openPage(context, (context) => EnrollmentScreen(stream: widget.stream, allowCodeEntry: true))
)
label: Text('Enroll with Managed Nebula'),
labelWidth: 200,
onPressed: () =>
Utils.openPage(context, (context) => EnrollmentScreen(stream: widget.stream, allowCodeEntry: true)))
]));
items.add(ConfigSection(children: [

View File

@ -79,11 +79,12 @@ class _SiteDetailScreenState extends State<SiteDetailScreen> {
@override
Widget build(BuildContext context) {
final dnIcon = Theme.of(context).brightness == Brightness.dark ? 'images/dn-logo-dark.svg' : 'images/dn-logo-light.svg';
final dnIcon =
Theme.of(context).brightness == Brightness.dark ? 'images/dn-logo-dark.svg' : 'images/dn-logo-light.svg';
final title = Row(children: [
site.managed ?
Padding(padding: EdgeInsets.only(right: 10), child: SvgPicture.asset(dnIcon, width: 12)) :
Container(),
site.managed
? Padding(padding: EdgeInsets.only(right: 10), child: SvgPicture.asset(dnIcon, width: 12))
: Container(),
Expanded(child: Text(site.name, style: TextStyle(fontWeight: FontWeight.bold)))
]);
@ -192,16 +193,16 @@ class _SiteDetailScreenState extends State<SiteDetailScreen> {
Utils.openPage(
context,
(context) => SiteTunnelsScreen(
pending: false,
tunnels: activeHosts!,
site: site,
onChanged: (hosts) {
setState(() {
activeHosts = hosts;
});
},
supportsQRScanning: widget.supportsQRScanning,
));
pending: false,
tunnels: activeHosts!,
site: site,
onChanged: (hosts) {
setState(() {
activeHosts = hosts;
});
},
supportsQRScanning: widget.supportsQRScanning,
));
},
label: Text("Active"),
content: Container(alignment: Alignment.centerRight, child: active)),
@ -212,16 +213,16 @@ class _SiteDetailScreenState extends State<SiteDetailScreen> {
Utils.openPage(
context,
(context) => SiteTunnelsScreen(
pending: true,
tunnels: pendingHosts!,
site: site,
onChanged: (hosts) {
setState(() {
pendingHosts = hosts;
});
},
supportsQRScanning: widget.supportsQRScanning,
));
pending: true,
tunnels: pendingHosts!,
site: site,
onChanged: (hosts) {
setState(() {
pendingHosts = hosts;
});
},
supportsQRScanning: widget.supportsQRScanning,
));
},
label: Text("Pending"),
content: Container(alignment: Alignment.centerRight, child: pending))
@ -237,11 +238,11 @@ class _SiteDetailScreenState extends State<SiteDetailScreen> {
onPressed: () {
Utils.openPage(context, (context) {
return SiteConfigScreen(
site: widget.site,
onSave: (site) async {
changed = true;
setState(() {});
},
site: widget.site,
onSave: (site) async {
changed = true;
setState(() {});
},
supportsQRScanning: widget.supportsQRScanning,
);
});

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -66,7 +66,11 @@ class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
@override
Widget build(BuildContext context) {
return FormPage(
title: widget.onDelete == null ? widget.onSave == null ? 'View Static Host' : 'New Static Host' : 'Edit Static Host',
title: widget.onDelete == null
? widget.onSave == null
? 'View Static Host'
: 'New Static Host'
: 'Edit Static Host',
changed: changed,
onSave: _onSave,
child: Column(children: [
@ -74,20 +78,20 @@ class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
ConfigItem(
label: Text('Nebula IP'),
labelWidth: 200,
content: widget.onSave == null ?
Text(_nebulaIp, textAlign: TextAlign.end) :
IPFormField(
help: "Required",
initialValue: _nebulaIp,
ipOnly: true,
textAlign: TextAlign.end,
crossAxisAlignment: CrossAxisAlignment.end,
textInputAction: TextInputAction.next,
onSaved: (v) {
if (v != null) {
_nebulaIp = v;
}
})),
content: widget.onSave == null
? Text(_nebulaIp, textAlign: TextAlign.end)
: IPFormField(
help: "Required",
initialValue: _nebulaIp,
ipOnly: true,
textAlign: TextAlign.end,
crossAxisAlignment: CrossAxisAlignment.end,
textInputAction: TextInputAction.next,
onSaved: (v) {
if (v != null) {
_nebulaIp = v;
}
})),
ConfigItem(
label: Text('Lighthouse'),
labelWidth: 200,
@ -96,12 +100,14 @@ class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
child: Switch.adaptive(
value: _lighthouse,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
onChanged: widget.onSave == null ? null : (v) {
setState(() {
changed = true;
_lighthouse = v;
});
})),
onChanged: widget.onSave == null
? null
: (v) {
setState(() {
changed = true;
_lighthouse = v;
});
})),
),
]),
ConfigSection(
@ -128,8 +134,7 @@ class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
_onSave() {
Navigator.pop(context);
if (widget.onSave != null) {
var map = Hostmap(
nebulaIp: _nebulaIp, destinations: [], lighthouse: _lighthouse);
var map = Hostmap(nebulaIp: _nebulaIp, destinations: [], lighthouse: _lighthouse);
_destinations.forEach((_, dest) {
map.destinations.add(dest.destination);
@ -147,30 +152,32 @@ class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
key: key,
label: Align(
alignment: Alignment.centerLeft,
child: widget.onSave == null ? Container() : PlatformIconButton(
padding: EdgeInsets.zero,
icon: Icon(Icons.remove_circle, color: CupertinoColors.systemRed.resolveFrom(context)),
onPressed: () => setState(() {
_removeDestination(key);
_dismissKeyboard();
}))),
child: widget.onSave == null
? Container()
: PlatformIconButton(
padding: EdgeInsets.zero,
icon: Icon(Icons.remove_circle, color: CupertinoColors.systemRed.resolveFrom(context)),
onPressed: () => setState(() {
_removeDestination(key);
_dismissKeyboard();
}))),
labelWidth: 70,
content: Row(children: <Widget>[
Expanded(
child: widget.onSave == null ?
Text(dest.destination.toString(), textAlign: TextAlign.end) :
IPAndPortFormField(
ipHelp: 'public ip or name',
ipTextAlign: TextAlign.end,
enableIPV6: true,
noBorder: true,
initialValue: dest.destination,
onSaved: (v) {
if (v != null) {
dest.destination = v;
}
},
)),
child: widget.onSave == null
? Text(dest.destination.toString(), textAlign: TextAlign.end)
: IPAndPortFormField(
ipHelp: 'public ip or name',
ipTextAlign: TextAlign.end,
enableIPV6: true,
noBorder: true,
initialValue: dest.destination,
onSaved: (v) {
if (v != null) {
dest.destination = v;
}
},
)),
]),
));
});
@ -178,8 +185,7 @@ class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
if (widget.onSave != null) {
items.add(ConfigButtonItem(
content: Text('Add another'),
onPressed: () =>
setState(() {
onPressed: () => setState(() {
_addDestination();
_dismissKeyboard();
})));

View File

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

View File

@ -22,7 +22,7 @@ class Settings {
}
bool get darkMode {
return _getBool('darkMode', SchedulerBinding.instance.window.platformBrightness == Brightness.dark);
return _getBool('darkMode', SchedulerBinding.instance.platformDispatcher.platformBrightness == Brightness.dark);
}
set darkMode(bool enabled) {

View File

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

View File

@ -4,7 +4,7 @@ import 'package:file_picker/file_picker.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:url_launcher/url_launcher_string.dart';
class Utils {
/// Minimum size (width or height) of a interactive component
@ -158,8 +158,8 @@ class Utils {
}
static launchUrl(String url, BuildContext context) async {
if (await canLaunch(url)) {
await launch(url);
if (await canLaunchUrlString(url)) {
await launchUrlString(url);
} else {
Utils.popError(context, 'Error', 'Could not launch web view');
}

View File

@ -23,7 +23,6 @@ bool ipValidator(String? str, bool enableIPV6) {
{
return true;
}
break;
}
return false;

View File

@ -10,7 +10,7 @@ require (
github.com/DefinedNet/dnapi v0.0.0-20240611201323-4589547bd270
github.com/sirupsen/logrus v1.9.3
github.com/slackhq/nebula v1.9.3
golang.org/x/crypto v0.24.0
golang.org/x/crypto v0.27.0
gopkg.in/yaml.v2 v2.4.0
)
@ -34,12 +34,12 @@ require (
github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8 // indirect
github.com/vishvananda/netlink v1.2.1-beta.2 // indirect
github.com/vishvananda/netns v0.0.4 // indirect
golang.org/x/mod v0.18.0 // indirect
golang.org/x/net v0.26.0 // indirect
golang.org/x/sync v0.7.0 // indirect
golang.org/x/sys v0.21.0 // indirect
golang.org/x/term v0.21.0 // indirect
golang.org/x/tools v0.22.0 // indirect
golang.org/x/mod v0.21.0 // indirect
golang.org/x/net v0.29.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/term v0.24.0 // indirect
golang.org/x/tools v0.25.0 // indirect
golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect
golang.zx2c4.com/wireguard v0.0.0-20231211153847-12269c276173 // indirect
golang.zx2c4.com/wireguard/windows v0.5.3 // indirect

View File

@ -145,14 +145,14 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0=
golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -163,8 +163,8 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo=
golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -172,8 +172,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -190,11 +190,11 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@ -203,8 +203,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
golang.org/x/tools v0.25.0 h1:oFU9pkj/iJgs+0DT+VMHrx+oBKs/LJMV+Uvg78sl+fE=
golang.org/x/tools v0.25.0/go.mod h1:/vtpO8WL1N9cQC3FN5zPqb//fRXskFHbLKk4OW1Q7rg=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@ -1,90 +1,118 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
args:
dependency: transitive
description:
name: args
sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
url: "https://pub.dev"
source: hosted
version: "2.5.0"
async:
dependency: transitive
description:
name: async
url: "https://pub.dartlang.org"
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
url: "https://pub.dev"
source: hosted
version: "2.9.0"
version: "2.11.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
url: "https://pub.dartlang.org"
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.1"
characters:
dependency: transitive
description:
name: characters
url: "https://pub.dartlang.org"
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
version: "1.3.0"
clock:
dependency: transitive
description:
name: clock
url: "https://pub.dartlang.org"
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
url: "https://pub.dev"
source: hosted
version: "1.1.1"
collection:
dependency: transitive
description:
name: collection
url: "https://pub.dartlang.org"
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
url: "https://pub.dev"
source: hosted
version: "1.16.0"
version: "1.18.0"
cross_file:
dependency: transitive
description:
name: cross_file
url: "https://pub.dartlang.org"
sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670"
url: "https://pub.dev"
source: hosted
version: "0.3.3+4"
version: "0.3.4+2"
crypto:
dependency: transitive
description:
name: crypto
url: "https://pub.dartlang.org"
sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
url: "https://pub.dev"
source: hosted
version: "3.0.2"
version: "3.0.3"
cupertino_icons:
dependency: "direct main"
description:
name: cupertino_icons
url: "https://pub.dartlang.org"
sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6
url: "https://pub.dev"
source: hosted
version: "1.0.5"
version: "1.0.8"
fake_async:
dependency: transitive
description:
name: fake_async
url: "https://pub.dartlang.org"
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
url: "https://pub.dev"
source: hosted
version: "1.3.1"
ffi:
dependency: transitive
description:
name: ffi
url: "https://pub.dartlang.org"
sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6"
url: "https://pub.dev"
source: hosted
version: "2.0.2"
version: "2.1.3"
file:
dependency: transitive
description:
name: file
url: "https://pub.dartlang.org"
sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d"
url: "https://pub.dev"
source: hosted
version: "6.1.4"
file_picker:
dependency: "direct main"
description:
name: file_picker
url: "https://pub.dartlang.org"
sha256: "167bb619cdddaa10ef2907609feb8a79c16dfa479d3afaf960f8e223f754bf12"
url: "https://pub.dev"
source: hosted
version: "5.2.10"
version: "8.1.2"
fixnum:
dependency: transitive
description:
name: fixnum
sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1"
url: "https://pub.dev"
source: hosted
version: "1.1.0"
flutter:
dependency: "direct main"
description: flutter
@ -94,30 +122,34 @@ packages:
dependency: "direct main"
description:
name: flutter_barcode_scanner
url: "https://pub.dartlang.org"
sha256: a4ba37daf9933f451a5e812c753ddd045d6354e4a3280342d895b07fecaab3fa
url: "https://pub.dev"
source: hosted
version: "2.0.0"
flutter_platform_widgets:
dependency: "direct main"
description:
name: flutter_platform_widgets
url: "https://pub.dartlang.org"
sha256: "84f39540cf433aa44b235b7fca6518d1bd30aa281d8196f00be60bc76cac96f4"
url: "https://pub.dev"
source: hosted
version: "2.2.6"
version: "7.0.1"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
url: "https://pub.dartlang.org"
sha256: "8cf40eebf5dec866a6d1956ad7b4f7016e6c0cc69847ab946833b7d43743809f"
url: "https://pub.dev"
source: hosted
version: "2.0.15"
version: "2.0.19"
flutter_svg:
dependency: "direct main"
description:
name: flutter_svg
url: "https://pub.dartlang.org"
sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2"
url: "https://pub.dev"
source: hosted
version: "1.1.6"
version: "2.0.10+1"
flutter_test:
dependency: "direct dev"
description: flutter
@ -128,160 +160,214 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
http:
dependency: transitive
description:
name: http
sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010
url: "https://pub.dev"
source: hosted
version: "1.2.2"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
url: "https://pub.dev"
source: hosted
version: "4.0.2"
intl:
dependency: "direct main"
description:
name: intl
url: "https://pub.dartlang.org"
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
url: "https://pub.dev"
source: hosted
version: "0.17.0"
js:
version: "0.19.0"
leak_tracker:
dependency: transitive
description:
name: js
url: "https://pub.dartlang.org"
name: leak_tracker
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05"
url: "https://pub.dev"
source: hosted
version: "0.6.4"
version: "10.0.5"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806"
url: "https://pub.dev"
source: hosted
version: "3.0.5"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
matcher:
dependency: transitive
description:
name: matcher
url: "https://pub.dartlang.org"
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
url: "https://pub.dev"
source: hosted
version: "0.12.12"
version: "0.12.16+1"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
url: "https://pub.dartlang.org"
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.dev"
source: hosted
version: "0.1.5"
version: "0.11.1"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
url: "https://pub.dev"
source: hosted
version: "1.8.0"
version: "1.15.0"
mime:
dependency: transitive
description:
name: mime
url: "https://pub.dartlang.org"
sha256: "801fd0b26f14a4a58ccb09d5892c3fbdeff209594300a542492cf13fba9d247a"
url: "https://pub.dev"
source: hosted
version: "1.0.4"
package_info:
version: "1.0.6"
package_info_plus:
dependency: "direct main"
description:
name: package_info
url: "https://pub.dartlang.org"
name: package_info_plus
sha256: a75164ade98cb7d24cfd0a13c6408927c6b217fa60dee5a7ff5c116a58f28918
url: "https://pub.dev"
source: hosted
version: "2.0.2"
version: "8.0.2"
package_info_plus_platform_interface:
dependency: transitive
description:
name: package_info_plus_platform_interface
sha256: ac1f4a4847f1ade8e6a87d1f39f5d7c67490738642e2542f559ec38c37489a66
url: "https://pub.dev"
source: hosted
version: "3.0.1"
path:
dependency: transitive
description:
name: path
url: "https://pub.dartlang.org"
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
url: "https://pub.dev"
source: hosted
version: "1.8.2"
path_drawing:
dependency: transitive
description:
name: path_drawing
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.1"
version: "1.9.0"
path_parsing:
dependency: transitive
description:
name: path_parsing
url: "https://pub.dartlang.org"
sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf
url: "https://pub.dev"
source: hosted
version: "1.0.1"
path_provider:
dependency: "direct main"
description:
name: path_provider
url: "https://pub.dartlang.org"
sha256: fec0d61223fba3154d87759e3cc27fe2c8dc498f6386c6d6fc80d1afdd1bf378
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.4"
path_provider_android:
dependency: transitive
description:
name: path_provider_android
url: "https://pub.dartlang.org"
sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.2.4"
path_provider_foundation:
dependency: transitive
description:
name: path_provider_foundation
url: "https://pub.dartlang.org"
sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
url: "https://pub.dev"
source: hosted
version: "2.3.0"
version: "2.4.0"
path_provider_linux:
dependency: transitive
description:
name: path_provider_linux
url: "https://pub.dartlang.org"
sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
url: "https://pub.dev"
source: hosted
version: "2.2.0"
version: "2.2.1"
path_provider_platform_interface:
dependency: transitive
description:
name: path_provider_platform_interface
url: "https://pub.dartlang.org"
sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.2"
path_provider_windows:
dependency: transitive
description:
name: path_provider_windows
url: "https://pub.dartlang.org"
sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7
url: "https://pub.dev"
source: hosted
version: "2.2.0"
version: "2.3.0"
petitparser:
dependency: transitive
description:
name: petitparser
url: "https://pub.dartlang.org"
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
url: "https://pub.dev"
source: hosted
version: "5.1.0"
version: "6.0.2"
platform:
dependency: transitive
description:
name: platform
url: "https://pub.dartlang.org"
sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
url: "https://pub.dev"
source: hosted
version: "3.1.1"
version: "3.1.5"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
url: "https://pub.dartlang.org"
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
url: "https://pub.dev"
source: hosted
version: "2.1.5"
version: "2.1.8"
pull_to_refresh:
dependency: "direct main"
description:
name: pull_to_refresh
url: "https://pub.dartlang.org"
sha256: bbadd5a931837b57739cf08736bea63167e284e71fb23b218c8c9a6e042aad12
url: "https://pub.dev"
source: hosted
version: "2.0.0"
share_plus:
dependency: "direct main"
description:
name: share_plus
url: "https://pub.dartlang.org"
sha256: "468c43f285207c84bcabf5737f33b914ceb8eb38398b91e5e3ad1698d1b72a52"
url: "https://pub.dev"
source: hosted
version: "6.3.4"
version: "10.0.2"
share_plus_platform_interface:
dependency: transitive
description:
name: share_plus_platform_interface
url: "https://pub.dartlang.org"
sha256: "6ababf341050edff57da8b6990f11f4e99eaba837865e2e6defe16d039619db5"
url: "https://pub.dev"
source: hosted
version: "3.3.1"
version: "5.0.0"
sky_engine:
dependency: transitive
description: flutter
@ -291,142 +377,210 @@ packages:
dependency: transitive
description:
name: source_span
url: "https://pub.dartlang.org"
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
source: hosted
version: "1.9.0"
version: "1.10.0"
sprintf:
dependency: transitive
description:
name: sprintf
sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23"
url: "https://pub.dev"
source: hosted
version: "7.0.0"
stack_trace:
dependency: transitive
description:
name: stack_trace
url: "https://pub.dartlang.org"
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
url: "https://pub.dev"
source: hosted
version: "1.10.0"
version: "1.11.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
url: "https://pub.dartlang.org"
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
url: "https://pub.dev"
source: hosted
version: "2.1.0"
version: "2.1.2"
string_scanner:
dependency: transitive
description:
name: string_scanner
url: "https://pub.dartlang.org"
sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
version: "1.2.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.dartlang.org"
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
url: "https://pub.dev"
source: hosted
version: "1.2.1"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb"
url: "https://pub.dev"
source: hosted
version: "0.4.12"
version: "0.7.2"
typed_data:
dependency: transitive
description:
name: typed_data
url: "https://pub.dartlang.org"
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
url: "https://pub.dev"
source: hosted
version: "1.3.2"
url_launcher:
dependency: "direct main"
description:
name: url_launcher
url: "https://pub.dartlang.org"
sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3"
url: "https://pub.dev"
source: hosted
version: "6.1.11"
version: "6.3.0"
url_launcher_android:
dependency: transitive
description:
name: url_launcher_android
url: "https://pub.dartlang.org"
sha256: "17cd5e205ea615e2c6ea7a77323a11712dffa0720a8a90540db57a01347f9ad9"
url: "https://pub.dev"
source: hosted
version: "6.0.38"
version: "6.3.2"
url_launcher_ios:
dependency: transitive
description:
name: url_launcher_ios
url: "https://pub.dartlang.org"
sha256: e43b677296fadce447e987a2f519dcf5f6d1e527dc35d01ffab4fff5b8a7063e
url: "https://pub.dev"
source: hosted
version: "6.1.4"
version: "6.3.1"
url_launcher_linux:
dependency: transitive
description:
name: url_launcher_linux
url: "https://pub.dartlang.org"
sha256: e2b9622b4007f97f504cd64c0128309dfb978ae66adbe944125ed9e1750f06af
url: "https://pub.dev"
source: hosted
version: "3.0.5"
version: "3.2.0"
url_launcher_macos:
dependency: transitive
description:
name: url_launcher_macos
url: "https://pub.dartlang.org"
sha256: "9a1a42d5d2d95400c795b2914c36fdcb525870c752569438e4ebb09a2b5d90de"
url: "https://pub.dev"
source: hosted
version: "3.0.6"
version: "3.2.0"
url_launcher_platform_interface:
dependency: transitive
description:
name: url_launcher_platform_interface
url: "https://pub.dartlang.org"
sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029"
url: "https://pub.dev"
source: hosted
version: "2.1.3"
version: "2.3.2"
url_launcher_web:
dependency: transitive
description:
name: url_launcher_web
url: "https://pub.dartlang.org"
sha256: "772638d3b34c779ede05ba3d38af34657a05ac55b06279ea6edd409e323dca8e"
url: "https://pub.dev"
source: hosted
version: "2.0.18"
version: "2.3.3"
url_launcher_windows:
dependency: transitive
description:
name: url_launcher_windows
url: "https://pub.dartlang.org"
sha256: "49c10f879746271804767cb45551ec5592cdab00ee105c06dddde1a98f73b185"
url: "https://pub.dev"
source: hosted
version: "3.0.7"
version: "3.1.2"
uuid:
dependency: "direct main"
description:
name: uuid
url: "https://pub.dartlang.org"
sha256: f33d6bb662f0e4f79dcd7ada2e6170f3b3a2530c28fc41f49a411ddedd576a77
url: "https://pub.dev"
source: hosted
version: "3.0.7"
version: "4.5.0"
vector_graphics:
dependency: transitive
description:
name: vector_graphics
sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3"
url: "https://pub.dev"
source: hosted
version: "1.1.11+1"
vector_graphics_codec:
dependency: transitive
description:
name: vector_graphics_codec
sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da
url: "https://pub.dev"
source: hosted
version: "1.1.11+1"
vector_graphics_compiler:
dependency: transitive
description:
name: vector_graphics_compiler
sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81"
url: "https://pub.dev"
source: hosted
version: "1.1.11+1"
vector_math:
dependency: transitive
description:
name: vector_math
url: "https://pub.dartlang.org"
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.4"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d"
url: "https://pub.dev"
source: hosted
version: "14.2.5"
web:
dependency: transitive
description:
name: web
sha256: d43c1d6b787bf0afad444700ae7f4db8827f701bc61c255ac8d328c6f4d52062
url: "https://pub.dev"
source: hosted
version: "1.0.0"
win32:
dependency: transitive
description:
name: win32
url: "https://pub.dartlang.org"
sha256: "68d1e89a91ed61ad9c370f9f8b6effed9ae5e0ede22a270bdfa6daf79fc2290a"
url: "https://pub.dev"
source: hosted
version: "3.1.4"
version: "5.5.4"
xdg_directories:
dependency: transitive
description:
name: xdg_directories
url: "https://pub.dartlang.org"
sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
url: "https://pub.dev"
source: hosted
version: "1.0.2"
version: "1.0.4"
xml:
dependency: transitive
description:
name: xml
url: "https://pub.dartlang.org"
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
url: "https://pub.dev"
source: hosted
version: "6.1.0"
version: "6.5.0"
sdks:
dart: ">=2.18.1 <3.0.0"
flutter: ">=3.3.0"
dart: ">=3.5.1 <4.0.0"
flutter: ">=3.22.0"

View File

@ -14,7 +14,7 @@ description: Mobile Nebula Client
version: 0.1.0+54
environment:
sdk: '>=2.18.1 <3.0.0'
sdk: ^3.5.1
dependencies:
flutter:
@ -23,17 +23,17 @@ dependencies:
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
flutter_platform_widgets: ^2.0.0
flutter_platform_widgets: ^7.0.1
path_provider: ^2.0.11
file_picker: ^5.0.1
uuid: ^3.0.4
package_info: ^2.0.0
file_picker: ^8.1.2
uuid: ^4.4.2
package_info_plus: ^8.0.2
url_launcher: ^6.1.6
pull_to_refresh: ^2.0.0
flutter_barcode_scanner: ^2.0.0
flutter_svg: ^1.1.5
intl: ^0.17.0
share_plus: ^6.3.0
flutter_svg: ^2.0.10+1
intl: ^0.19.0
share_plus: ^10.0.2
dev_dependencies:
flutter_test: