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:
parent
f576aa0c50
commit
64d45f66c7
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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'
|
|
@ -21,6 +21,6 @@
|
|||
<key>CFBundleVersion</key>
|
||||
<string>1.0</string>
|
||||
<key>MinimumOSVersion</key>
|
||||
<string>11.0</string>
|
||||
<string>12.0</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 = (
|
||||
);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Scheme
|
||||
LastUpgradeVersion = "1300"
|
||||
LastUpgradeVersion = "1510"
|
||||
version = "1.7">
|
||||
<BuildAction
|
||||
parallelizeBuildables = "YES"
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -64,5 +64,7 @@
|
|||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
],
|
||||
)),
|
||||
);
|
||||
|
|
|
@ -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> {
|
|||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"]),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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: () {
|
||||
|
|
|
@ -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(),
|
||||
]);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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: [
|
||||
|
|
|
@ -79,11 +79,12 @@ class _SiteDetailScreenState extends State<SiteDetailScreen> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final dnIcon = Theme.of(context).brightness == Brightness.dark ? 'images/dn-logo-dark.svg' : 'images/dn-logo-light.svg';
|
||||
final dnIcon =
|
||||
Theme.of(context).brightness == Brightness.dark ? 'images/dn-logo-dark.svg' : 'images/dn-logo-light.svg';
|
||||
final title = Row(children: [
|
||||
site.managed ?
|
||||
Padding(padding: EdgeInsets.only(right: 10), child: SvgPicture.asset(dnIcon, width: 12)) :
|
||||
Container(),
|
||||
site.managed
|
||||
? Padding(padding: EdgeInsets.only(right: 10), child: SvgPicture.asset(dnIcon, width: 12))
|
||||
: Container(),
|
||||
Expanded(child: Text(site.name, style: TextStyle(fontWeight: FontWeight.bold)))
|
||||
]);
|
||||
|
||||
|
@ -192,16 +193,16 @@ class _SiteDetailScreenState extends State<SiteDetailScreen> {
|
|||
Utils.openPage(
|
||||
context,
|
||||
(context) => SiteTunnelsScreen(
|
||||
pending: false,
|
||||
tunnels: activeHosts!,
|
||||
site: site,
|
||||
onChanged: (hosts) {
|
||||
setState(() {
|
||||
activeHosts = hosts;
|
||||
});
|
||||
},
|
||||
supportsQRScanning: widget.supportsQRScanning,
|
||||
));
|
||||
pending: false,
|
||||
tunnels: activeHosts!,
|
||||
site: site,
|
||||
onChanged: (hosts) {
|
||||
setState(() {
|
||||
activeHosts = hosts;
|
||||
});
|
||||
},
|
||||
supportsQRScanning: widget.supportsQRScanning,
|
||||
));
|
||||
},
|
||||
label: Text("Active"),
|
||||
content: Container(alignment: Alignment.centerRight, child: active)),
|
||||
|
@ -212,16 +213,16 @@ class _SiteDetailScreenState extends State<SiteDetailScreen> {
|
|||
Utils.openPage(
|
||||
context,
|
||||
(context) => SiteTunnelsScreen(
|
||||
pending: true,
|
||||
tunnels: pendingHosts!,
|
||||
site: site,
|
||||
onChanged: (hosts) {
|
||||
setState(() {
|
||||
pendingHosts = hosts;
|
||||
});
|
||||
},
|
||||
supportsQRScanning: widget.supportsQRScanning,
|
||||
));
|
||||
pending: true,
|
||||
tunnels: pendingHosts!,
|
||||
site: site,
|
||||
onChanged: (hosts) {
|
||||
setState(() {
|
||||
pendingHosts = hosts;
|
||||
});
|
||||
},
|
||||
supportsQRScanning: widget.supportsQRScanning,
|
||||
));
|
||||
},
|
||||
label: Text("Pending"),
|
||||
content: Container(alignment: Alignment.centerRight, child: pending))
|
||||
|
@ -237,11 +238,11 @@ class _SiteDetailScreenState extends State<SiteDetailScreen> {
|
|||
onPressed: () {
|
||||
Utils.openPage(context, (context) {
|
||||
return SiteConfigScreen(
|
||||
site: widget.site,
|
||||
onSave: (site) async {
|
||||
changed = true;
|
||||
setState(() {});
|
||||
},
|
||||
site: widget.site,
|
||||
onSave: (site) async {
|
||||
changed = true;
|
||||
setState(() {});
|
||||
},
|
||||
supportsQRScanning: widget.supportsQRScanning,
|
||||
);
|
||||
});
|
||||
|
|
|
@ -40,11 +40,12 @@ class _SiteLogsScreenState extends State<SiteLogsScreen> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final dnIcon = Theme.of(context).brightness == Brightness.dark ? 'images/dn-logo-dark.svg' : 'images/dn-logo-light.svg';
|
||||
final dnIcon =
|
||||
Theme.of(context).brightness == Brightness.dark ? 'images/dn-logo-dark.svg' : 'images/dn-logo-light.svg';
|
||||
final title = Row(children: [
|
||||
widget.site.managed ?
|
||||
Padding(padding: EdgeInsets.only(right: 10), child: SvgPicture.asset(dnIcon, width: 12)) :
|
||||
Container(),
|
||||
widget.site.managed
|
||||
? Padding(padding: EdgeInsets.only(right: 10), child: SvgPicture.asset(dnIcon, width: 12))
|
||||
: Container(),
|
||||
Expanded(child: Text(widget.site.name, style: TextStyle(fontWeight: FontWeight.bold)))
|
||||
]);
|
||||
|
||||
|
@ -83,29 +84,26 @@ class _SiteLogsScreenState extends State<SiteLogsScreen> {
|
|||
border: Border(top: borderSide),
|
||||
),
|
||||
child: Row(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[
|
||||
Expanded(
|
||||
child: Builder(
|
||||
builder: (BuildContext context) {
|
||||
return PlatformIconButton(
|
||||
padding: padding,
|
||||
icon: Icon(context.platformIcons.share, size: 30),
|
||||
onPressed: () {
|
||||
Share.shareFile(context,
|
||||
title: '${widget.site.name} logs',
|
||||
filePath: widget.site.logFile,
|
||||
filename: '${widget.site.name}.log');
|
||||
},
|
||||
);
|
||||
}
|
||||
)),
|
||||
Expanded(child: Builder(builder: (BuildContext context) {
|
||||
return PlatformIconButton(
|
||||
padding: padding,
|
||||
icon: Icon(context.platformIcons.share, size: 30),
|
||||
onPressed: () {
|
||||
Share.shareFile(context,
|
||||
title: '${widget.site.name} logs',
|
||||
filePath: widget.site.logFile,
|
||||
filename: '${widget.site.name}.log');
|
||||
},
|
||||
);
|
||||
})),
|
||||
Expanded(
|
||||
child: PlatformIconButton(
|
||||
padding: padding,
|
||||
icon: Icon(context.platformIcons.downArrow, size: 30),
|
||||
onPressed: () async {
|
||||
controller.animateTo(controller.position.maxScrollExtent,
|
||||
duration: const Duration(milliseconds: 500), curve: Curves.linearToEaseOut);
|
||||
},
|
||||
padding: padding,
|
||||
icon: Icon(context.platformIcons.downArrow, size: 30),
|
||||
onPressed: () async {
|
||||
controller.animateTo(controller.position.maxScrollExtent,
|
||||
duration: const Duration(milliseconds: 500), curve: Curves.linearToEaseOut);
|
||||
},
|
||||
)),
|
||||
]));
|
||||
}
|
||||
|
|
|
@ -17,8 +17,7 @@ class SiteTunnelsScreen extends StatefulWidget {
|
|||
required this.pending,
|
||||
required this.onChanged,
|
||||
required this.supportsQRScanning,
|
||||
})
|
||||
: super(key: key);
|
||||
}) : super(key: key);
|
||||
|
||||
final Site site;
|
||||
final List<HostInfo> tunnels;
|
||||
|
@ -67,17 +66,17 @@ class _SiteTunnelsScreenState extends State<SiteTunnelsScreen> {
|
|||
|
||||
children.add(ConfigPageItem(
|
||||
onPressed: () => Utils.openPage(
|
||||
context,
|
||||
(context) => HostInfoScreen(
|
||||
isLighthouse: isLh,
|
||||
hostInfo: hostInfo,
|
||||
pending: widget.pending,
|
||||
site: widget.site,
|
||||
onChanged: () {
|
||||
_listHostmap();
|
||||
},
|
||||
supportsQRScanning: widget.supportsQRScanning,
|
||||
),
|
||||
context,
|
||||
(context) => HostInfoScreen(
|
||||
isLighthouse: isLh,
|
||||
hostInfo: hostInfo,
|
||||
pending: widget.pending,
|
||||
site: widget.site,
|
||||
onChanged: () {
|
||||
_listHostmap();
|
||||
},
|
||||
supportsQRScanning: widget.supportsQRScanning,
|
||||
),
|
||||
),
|
||||
label: Row(children: <Widget>[Padding(child: icon, padding: EdgeInsets.only(right: 10)), Text(hostInfo.vpnIp)]),
|
||||
labelWidth: ipWidth,
|
||||
|
|
|
@ -98,12 +98,10 @@ class _AddCertificateScreenState extends State<AddCertificateScreen> {
|
|||
content: Text('Share Public Key'),
|
||||
onPressed: () async {
|
||||
await Share.share(context,
|
||||
title: 'Please sign and return a certificate',
|
||||
text: pubKey,
|
||||
filename: 'device.pub');
|
||||
title: 'Please sign and return a certificate', text: pubKey, filename: 'device.pub');
|
||||
},
|
||||
);
|
||||
},
|
||||
},
|
||||
),
|
||||
])
|
||||
];
|
||||
|
@ -269,12 +267,12 @@ class _AddCertificateScreenState extends State<AddCertificateScreen> {
|
|||
// We have a cert, pop the details screen where they can hit save
|
||||
Utils.openPage(context, (context) {
|
||||
return CertificateDetailsScreen(
|
||||
certInfo: tryCertInfo,
|
||||
onSave: () {
|
||||
Navigator.pop(context);
|
||||
widget.onSave!(CertificateResult(certInfo: tryCertInfo, key: keyController.text));
|
||||
},
|
||||
supportsQRScanning: widget.supportsQRScanning,
|
||||
certInfo: tryCertInfo,
|
||||
onSave: () {
|
||||
Navigator.pop(context);
|
||||
widget.onSave!(CertificateResult(certInfo: tryCertInfo, key: keyController.text));
|
||||
},
|
||||
supportsQRScanning: widget.supportsQRScanning,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -86,62 +86,62 @@ class _AdvancedScreenState extends State<AdvancedScreen> {
|
|||
label: Text("Lighthouse interval"),
|
||||
labelWidth: 200,
|
||||
//TODO: Auto select on focus?
|
||||
content: widget.site.managed ?
|
||||
Text(settings.lhDuration.toString() + " seconds", textAlign: TextAlign.right) :
|
||||
PlatformTextFormField(
|
||||
initialValue: settings.lhDuration.toString(),
|
||||
keyboardType: TextInputType.number,
|
||||
suffix: Text("seconds"),
|
||||
textAlign: TextAlign.right,
|
||||
maxLength: 5,
|
||||
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||
onSaved: (val) {
|
||||
setState(() {
|
||||
if (val != null) {
|
||||
settings.lhDuration = int.parse(val);
|
||||
}
|
||||
});
|
||||
},
|
||||
)),
|
||||
content: widget.site.managed
|
||||
? Text(settings.lhDuration.toString() + " seconds", textAlign: TextAlign.right)
|
||||
: PlatformTextFormField(
|
||||
initialValue: settings.lhDuration.toString(),
|
||||
keyboardType: TextInputType.number,
|
||||
suffix: Text("seconds"),
|
||||
textAlign: TextAlign.right,
|
||||
maxLength: 5,
|
||||
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||
onSaved: (val) {
|
||||
setState(() {
|
||||
if (val != null) {
|
||||
settings.lhDuration = int.parse(val);
|
||||
}
|
||||
});
|
||||
},
|
||||
)),
|
||||
ConfigItem(
|
||||
label: Text("Listen port"),
|
||||
labelWidth: 150,
|
||||
//TODO: Auto select on focus?
|
||||
content: widget.site.managed ?
|
||||
Text(settings.port.toString(), textAlign: TextAlign.right) :
|
||||
PlatformTextFormField(
|
||||
initialValue: settings.port.toString(),
|
||||
keyboardType: TextInputType.number,
|
||||
textAlign: TextAlign.right,
|
||||
maxLength: 5,
|
||||
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||
onSaved: (val) {
|
||||
setState(() {
|
||||
if (val != null) {
|
||||
settings.port = int.parse(val);
|
||||
}
|
||||
});
|
||||
},
|
||||
)),
|
||||
content: widget.site.managed
|
||||
? Text(settings.port.toString(), textAlign: TextAlign.right)
|
||||
: PlatformTextFormField(
|
||||
initialValue: settings.port.toString(),
|
||||
keyboardType: TextInputType.number,
|
||||
textAlign: TextAlign.right,
|
||||
maxLength: 5,
|
||||
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||
onSaved: (val) {
|
||||
setState(() {
|
||||
if (val != null) {
|
||||
settings.port = int.parse(val);
|
||||
}
|
||||
});
|
||||
},
|
||||
)),
|
||||
ConfigItem(
|
||||
label: Text("MTU"),
|
||||
labelWidth: 150,
|
||||
content: widget.site.managed ?
|
||||
Text(settings.mtu.toString(), textAlign: TextAlign.right) :
|
||||
PlatformTextFormField(
|
||||
initialValue: settings.mtu.toString(),
|
||||
keyboardType: TextInputType.number,
|
||||
textAlign: TextAlign.right,
|
||||
maxLength: 5,
|
||||
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||
onSaved: (val) {
|
||||
setState(() {
|
||||
if (val != null) {
|
||||
settings.mtu = int.parse(val);
|
||||
}
|
||||
});
|
||||
},
|
||||
)),
|
||||
content: widget.site.managed
|
||||
? Text(settings.mtu.toString(), textAlign: TextAlign.right)
|
||||
: PlatformTextFormField(
|
||||
initialValue: settings.mtu.toString(),
|
||||
keyboardType: TextInputType.number,
|
||||
textAlign: TextAlign.right,
|
||||
maxLength: 5,
|
||||
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||
onSaved: (val) {
|
||||
setState(() {
|
||||
if (val != null) {
|
||||
settings.mtu = int.parse(val);
|
||||
}
|
||||
});
|
||||
},
|
||||
)),
|
||||
ConfigPageItem(
|
||||
disabled: widget.site.managed,
|
||||
label: Text('Cipher'),
|
||||
|
@ -184,12 +184,14 @@ class _AdvancedScreenState extends State<AdvancedScreen> {
|
|||
Utils.openPage(context, (context) {
|
||||
return UnsafeRoutesScreen(
|
||||
unsafeRoutes: settings.unsafeRoutes,
|
||||
onSave: widget.site.managed ? null : (routes) {
|
||||
setState(() {
|
||||
settings.unsafeRoutes = routes;
|
||||
changed = true;
|
||||
});
|
||||
});
|
||||
onSave: widget.site.managed
|
||||
? null
|
||||
: (routes) {
|
||||
setState(() {
|
||||
settings.unsafeRoutes = routes;
|
||||
changed = true;
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
)
|
||||
|
|
|
@ -64,18 +64,18 @@ class _CAListScreenState extends State<CAListScreen> {
|
|||
}
|
||||
|
||||
return FormPage(
|
||||
title: 'Certificate Authorities',
|
||||
changed: changed,
|
||||
onSave: () {
|
||||
if (widget.onSave != null) {
|
||||
Navigator.pop(context);
|
||||
widget.onSave!(cas.values.map((ca) {
|
||||
return ca;
|
||||
}).toList());
|
||||
}
|
||||
},
|
||||
child: Column(children: items));
|
||||
}
|
||||
title: 'Certificate Authorities',
|
||||
changed: changed,
|
||||
onSave: () {
|
||||
if (widget.onSave != null) {
|
||||
Navigator.pop(context);
|
||||
widget.onSave!(cas.values.map((ca) {
|
||||
return ca;
|
||||
}).toList());
|
||||
}
|
||||
},
|
||||
child: Column(children: items));
|
||||
}
|
||||
|
||||
List<Widget> _buildCAs() {
|
||||
List<Widget> items = [];
|
||||
|
@ -85,14 +85,16 @@ class _CAListScreenState extends State<CAListScreen> {
|
|||
onPressed: () {
|
||||
Utils.openPage(context, (context) {
|
||||
return CertificateDetailsScreen(
|
||||
certInfo: ca,
|
||||
onDelete: widget.onSave == null ? null : () {
|
||||
setState(() {
|
||||
changed = true;
|
||||
cas.remove(key);
|
||||
});
|
||||
},
|
||||
supportsQRScanning: widget.supportsQRScanning,
|
||||
certInfo: ca,
|
||||
onDelete: widget.onSave == null
|
||||
? null
|
||||
: () {
|
||||
setState(() {
|
||||
changed = true;
|
||||
cas.remove(key);
|
||||
});
|
||||
},
|
||||
supportsQRScanning: widget.supportsQRScanning,
|
||||
);
|
||||
});
|
||||
},
|
||||
|
|
|
@ -170,19 +170,19 @@ class _CertificateDetailsScreenState extends State<CertificateDetailsScreen> {
|
|||
onPressed: () {
|
||||
Utils.openPage(context, (context) {
|
||||
return AddCertificateScreen(
|
||||
onReplace: (result) {
|
||||
setState(() {
|
||||
changed = true;
|
||||
certResult = result;
|
||||
certInfo = result.certInfo;
|
||||
});
|
||||
// Slam the page back to the top
|
||||
controller.animateTo(0,
|
||||
duration: const Duration(milliseconds: 10), curve: Curves.linearToEaseOut);
|
||||
},
|
||||
pubKey: widget.pubKey!,
|
||||
privKey: widget.privKey!,
|
||||
supportsQRScanning: widget.supportsQRScanning,
|
||||
onReplace: (result) {
|
||||
setState(() {
|
||||
changed = true;
|
||||
certResult = result;
|
||||
certInfo = result.certInfo;
|
||||
});
|
||||
// Slam the page back to the top
|
||||
controller.animateTo(0,
|
||||
duration: const Duration(milliseconds: 10), curve: Curves.linearToEaseOut);
|
||||
},
|
||||
pubKey: widget.pubKey!,
|
||||
privKey: widget.privKey!,
|
||||
supportsQRScanning: widget.supportsQRScanning,
|
||||
);
|
||||
});
|
||||
})));
|
||||
|
|
|
@ -19,17 +19,13 @@ class RenderedConfigScreen extends StatelessWidget {
|
|||
title: Text('Rendered Site Config'),
|
||||
scrollable: SimpleScrollable.both,
|
||||
trailingActions: <Widget>[
|
||||
Builder(
|
||||
builder: (BuildContext context) {
|
||||
return PlatformIconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
icon: Icon(context.platformIcons.share, size: 28.0),
|
||||
onPressed: () =>
|
||||
Share.share(context,
|
||||
title: '$name.yaml', text: config, filename: '$name.yaml'),
|
||||
);
|
||||
}
|
||||
),
|
||||
Builder(builder: (BuildContext context) {
|
||||
return PlatformIconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
icon: Icon(context.platformIcons.share, size: 28.0),
|
||||
onPressed: () => Share.share(context, title: '$name.yaml', text: config, filename: '$name.yaml'),
|
||||
);
|
||||
}),
|
||||
],
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(5),
|
||||
|
|
|
@ -139,17 +139,17 @@ class _SiteConfigScreenState extends State<SiteConfigScreen> {
|
|||
lastUpdate = formatter.format(site.lastManagedUpdate!.toLocal());
|
||||
}
|
||||
|
||||
return site.managed ? ConfigSection(
|
||||
label: "MANAGED CONFIG",
|
||||
children: <Widget>[
|
||||
ConfigItem(
|
||||
label: Text("Last Update"),
|
||||
content: Wrap(alignment: WrapAlignment.end, crossAxisAlignment: WrapCrossAlignment.center, children: <Widget>[
|
||||
Text(lastUpdate),
|
||||
]),
|
||||
)
|
||||
]
|
||||
) : Container();
|
||||
return site.managed
|
||||
? ConfigSection(label: "MANAGED CONFIG", children: <Widget>[
|
||||
ConfigItem(
|
||||
label: Text("Last Update"),
|
||||
content:
|
||||
Wrap(alignment: WrapAlignment.end, crossAxisAlignment: WrapCrossAlignment.center, children: <Widget>[
|
||||
Text(lastUpdate),
|
||||
]),
|
||||
)
|
||||
])
|
||||
: Container();
|
||||
}
|
||||
|
||||
Widget _keys() {
|
||||
|
@ -183,30 +183,32 @@ class _SiteConfigScreenState extends State<SiteConfigScreen> {
|
|||
Utils.openPage(context, (context) {
|
||||
if (site.certInfo != null) {
|
||||
return CertificateDetailsScreen(
|
||||
certInfo: site.certInfo!,
|
||||
pubKey: pubKey,
|
||||
privKey: privKey,
|
||||
onReplace: site.managed ? null : (result) {
|
||||
setState(() {
|
||||
changed = true;
|
||||
site.certInfo = result.certInfo;
|
||||
site.key = result.key;
|
||||
});
|
||||
},
|
||||
supportsQRScanning: widget.supportsQRScanning,
|
||||
certInfo: site.certInfo!,
|
||||
pubKey: pubKey,
|
||||
privKey: privKey,
|
||||
onReplace: site.managed
|
||||
? null
|
||||
: (result) {
|
||||
setState(() {
|
||||
changed = true;
|
||||
site.certInfo = result.certInfo;
|
||||
site.key = result.key;
|
||||
});
|
||||
},
|
||||
supportsQRScanning: widget.supportsQRScanning,
|
||||
);
|
||||
}
|
||||
|
||||
return AddCertificateScreen(
|
||||
pubKey: pubKey!,
|
||||
privKey: privKey!,
|
||||
onSave: (result) {
|
||||
setState(() {
|
||||
changed = true;
|
||||
site.certInfo = result.certInfo;
|
||||
site.key = result.key;
|
||||
});
|
||||
},
|
||||
pubKey: pubKey!,
|
||||
privKey: privKey!,
|
||||
onSave: (result) {
|
||||
setState(() {
|
||||
changed = true;
|
||||
site.certInfo = result.certInfo;
|
||||
site.key = result.key;
|
||||
});
|
||||
},
|
||||
supportsQRScanning: widget.supportsQRScanning,
|
||||
);
|
||||
});
|
||||
|
@ -226,14 +228,16 @@ class _SiteConfigScreenState extends State<SiteConfigScreen> {
|
|||
onPressed: () {
|
||||
Utils.openPage(context, (context) {
|
||||
return CAListScreen(
|
||||
cas: site.ca,
|
||||
onSave: site.managed ? null : (ca) {
|
||||
setState(() {
|
||||
changed = true;
|
||||
site.ca = ca;
|
||||
});
|
||||
},
|
||||
supportsQRScanning: widget.supportsQRScanning,
|
||||
cas: site.ca,
|
||||
onSave: site.managed
|
||||
? null
|
||||
: (ca) {
|
||||
setState(() {
|
||||
changed = true;
|
||||
site.ca = ca;
|
||||
});
|
||||
},
|
||||
supportsQRScanning: widget.supportsQRScanning,
|
||||
);
|
||||
});
|
||||
})
|
||||
|
@ -261,12 +265,14 @@ class _SiteConfigScreenState extends State<SiteConfigScreen> {
|
|||
Utils.openPage(context, (context) {
|
||||
return StaticHostsScreen(
|
||||
hostmap: site.staticHostmap,
|
||||
onSave: site.managed ? null : (map) {
|
||||
setState(() {
|
||||
changed = true;
|
||||
site.staticHostmap = map;
|
||||
});
|
||||
});
|
||||
onSave: site.managed
|
||||
? null
|
||||
: (map) {
|
||||
setState(() {
|
||||
changed = true;
|
||||
site.staticHostmap = map;
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
),
|
||||
|
|
|
@ -66,7 +66,11 @@ class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FormPage(
|
||||
title: widget.onDelete == null ? widget.onSave == null ? 'View Static Host' : 'New Static Host' : 'Edit Static Host',
|
||||
title: widget.onDelete == null
|
||||
? widget.onSave == null
|
||||
? 'View Static Host'
|
||||
: 'New Static Host'
|
||||
: 'Edit Static Host',
|
||||
changed: changed,
|
||||
onSave: _onSave,
|
||||
child: Column(children: [
|
||||
|
@ -74,20 +78,20 @@ class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
|
|||
ConfigItem(
|
||||
label: Text('Nebula IP'),
|
||||
labelWidth: 200,
|
||||
content: widget.onSave == null ?
|
||||
Text(_nebulaIp, textAlign: TextAlign.end) :
|
||||
IPFormField(
|
||||
help: "Required",
|
||||
initialValue: _nebulaIp,
|
||||
ipOnly: true,
|
||||
textAlign: TextAlign.end,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
textInputAction: TextInputAction.next,
|
||||
onSaved: (v) {
|
||||
if (v != null) {
|
||||
_nebulaIp = v;
|
||||
}
|
||||
})),
|
||||
content: widget.onSave == null
|
||||
? Text(_nebulaIp, textAlign: TextAlign.end)
|
||||
: IPFormField(
|
||||
help: "Required",
|
||||
initialValue: _nebulaIp,
|
||||
ipOnly: true,
|
||||
textAlign: TextAlign.end,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
textInputAction: TextInputAction.next,
|
||||
onSaved: (v) {
|
||||
if (v != null) {
|
||||
_nebulaIp = v;
|
||||
}
|
||||
})),
|
||||
ConfigItem(
|
||||
label: Text('Lighthouse'),
|
||||
labelWidth: 200,
|
||||
|
@ -96,12 +100,14 @@ class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
|
|||
child: Switch.adaptive(
|
||||
value: _lighthouse,
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
onChanged: widget.onSave == null ? null : (v) {
|
||||
setState(() {
|
||||
changed = true;
|
||||
_lighthouse = v;
|
||||
});
|
||||
})),
|
||||
onChanged: widget.onSave == null
|
||||
? null
|
||||
: (v) {
|
||||
setState(() {
|
||||
changed = true;
|
||||
_lighthouse = v;
|
||||
});
|
||||
})),
|
||||
),
|
||||
]),
|
||||
ConfigSection(
|
||||
|
@ -128,8 +134,7 @@ class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
|
|||
_onSave() {
|
||||
Navigator.pop(context);
|
||||
if (widget.onSave != null) {
|
||||
var map = Hostmap(
|
||||
nebulaIp: _nebulaIp, destinations: [], lighthouse: _lighthouse);
|
||||
var map = Hostmap(nebulaIp: _nebulaIp, destinations: [], lighthouse: _lighthouse);
|
||||
|
||||
_destinations.forEach((_, dest) {
|
||||
map.destinations.add(dest.destination);
|
||||
|
@ -147,30 +152,32 @@ class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
|
|||
key: key,
|
||||
label: Align(
|
||||
alignment: Alignment.centerLeft,
|
||||
child: widget.onSave == null ? Container() : PlatformIconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
icon: Icon(Icons.remove_circle, color: CupertinoColors.systemRed.resolveFrom(context)),
|
||||
onPressed: () => setState(() {
|
||||
_removeDestination(key);
|
||||
_dismissKeyboard();
|
||||
}))),
|
||||
child: widget.onSave == null
|
||||
? Container()
|
||||
: PlatformIconButton(
|
||||
padding: EdgeInsets.zero,
|
||||
icon: Icon(Icons.remove_circle, color: CupertinoColors.systemRed.resolveFrom(context)),
|
||||
onPressed: () => setState(() {
|
||||
_removeDestination(key);
|
||||
_dismissKeyboard();
|
||||
}))),
|
||||
labelWidth: 70,
|
||||
content: Row(children: <Widget>[
|
||||
Expanded(
|
||||
child: widget.onSave == null ?
|
||||
Text(dest.destination.toString(), textAlign: TextAlign.end) :
|
||||
IPAndPortFormField(
|
||||
ipHelp: 'public ip or name',
|
||||
ipTextAlign: TextAlign.end,
|
||||
enableIPV6: true,
|
||||
noBorder: true,
|
||||
initialValue: dest.destination,
|
||||
onSaved: (v) {
|
||||
if (v != null) {
|
||||
dest.destination = v;
|
||||
}
|
||||
},
|
||||
)),
|
||||
child: widget.onSave == null
|
||||
? Text(dest.destination.toString(), textAlign: TextAlign.end)
|
||||
: IPAndPortFormField(
|
||||
ipHelp: 'public ip or name',
|
||||
ipTextAlign: TextAlign.end,
|
||||
enableIPV6: true,
|
||||
noBorder: true,
|
||||
initialValue: dest.destination,
|
||||
onSaved: (v) {
|
||||
if (v != null) {
|
||||
dest.destination = v;
|
||||
}
|
||||
},
|
||||
)),
|
||||
]),
|
||||
));
|
||||
});
|
||||
|
@ -178,8 +185,7 @@ class _StaticHostmapScreenState extends State<StaticHostmapScreen> {
|
|||
if (widget.onSave != null) {
|
||||
items.add(ConfigButtonItem(
|
||||
content: Text('Add another'),
|
||||
onPressed: () =>
|
||||
setState(() {
|
||||
onPressed: () => setState(() {
|
||||
_addDestination();
|
||||
_dismissKeyboard();
|
||||
})));
|
||||
|
|
|
@ -70,8 +70,7 @@ class _StaticHostsScreenState extends State<StaticHostsScreen> {
|
|||
if (widget.onSave != null) {
|
||||
Map<String, StaticHost> map = {};
|
||||
_hostmap.forEach((_, host) {
|
||||
map[host.nebulaIp] = StaticHost(
|
||||
destinations: host.destinations, lighthouse: host.lighthouse);
|
||||
map[host.nebulaIp] = StaticHost(destinations: host.destinations, lighthouse: host.lighthouse);
|
||||
});
|
||||
|
||||
widget.onSave!(map);
|
||||
|
@ -98,20 +97,24 @@ class _StaticHostsScreenState extends State<StaticHostsScreen> {
|
|||
nebulaIp: host.nebulaIp,
|
||||
destinations: host.destinations,
|
||||
lighthouse: host.lighthouse,
|
||||
onSave: widget.onSave == null ? null :(map) {
|
||||
setState(() {
|
||||
changed = true;
|
||||
host.nebulaIp = map.nebulaIp;
|
||||
host.destinations = map.destinations;
|
||||
host.lighthouse = map.lighthouse;
|
||||
});
|
||||
},
|
||||
onDelete: widget.onSave == null ? null : () {
|
||||
setState(() {
|
||||
changed = true;
|
||||
_hostmap.remove(key);
|
||||
});
|
||||
});
|
||||
onSave: widget.onSave == null
|
||||
? null
|
||||
: (map) {
|
||||
setState(() {
|
||||
changed = true;
|
||||
host.nebulaIp = map.nebulaIp;
|
||||
host.destinations = map.destinations;
|
||||
host.lighthouse = map.lighthouse;
|
||||
});
|
||||
},
|
||||
onDelete: widget.onSave == null
|
||||
? null
|
||||
: () {
|
||||
setState(() {
|
||||
changed = true;
|
||||
_hostmap.remove(key);
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
));
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ bool ipValidator(String? str, bool enableIPV6) {
|
|||
{
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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=
|
||||
|
|
392
pubspec.lock
392
pubspec.lock
|
@ -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"
|
||||
|
|
16
pubspec.yaml
16
pubspec.yaml
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue