Upgrade to flutter 3 (#70)

Co-authored-by: John Maguire <contact@johnmaguire.me>
This commit is contained in:
Nate Brown 2022-09-21 15:27:35 -05:00 committed by GitHub
parent e3780bda1e
commit dbe67c2f81
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
71 changed files with 953 additions and 818 deletions

View File

@ -1,16 +1,30 @@
# Dependencies
## Setting up dev environment
- [`flutter`](https://flutter.dev/docs/get-started/install)
- [`gomobile`](https://godoc.org/golang.org/x/mobile/cmd/gomobile)
Install all of the following things:
- [`xcode`](https://apps.apple.com/us/app/xcode/)
- [`android-studio`](https://developer.android.com/studio)
- [Enable NDK](https://developer.android.com/studio/projects/install-ndk) Check local.properties for current NDK version
- [`flutter` 3.3.2](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)
Currently using flutter 2.0.5
Ensure your path is set up correctly to execute flutter
Copy env.sh.example to env.sh and update your PATH variable to expose both flutter and go bin directories
Run `flutter doctor` and fix everything it complains before proceeding
```export PATH="$PATH:/path/to/go/bin:/path/to/flutter/bin"```
*NOTE* on iOS, always open `Runner.xcworkspace` and NOT the `Runner.xccodeproj`
### Before first compile
- Copy `env.sh.example` and set it up for your machine
- Ensure you have run `gomobile init`
- In Android Studio, make sure you have the current ndk installed by going to Tools -> SDK Manager, go to the SDK Tools tab, check the `Show package details` box, expand the NDK section and select `21.1.6352462` version.
- Ensure you have downloaded an ndk via android studio, this is likely not the default one and you need to check the
`Show package details` box to select the correct version. The correct version comes from the error when you try and compile
- Make sure you have `gem` installed with `sudo gem install`
- If on MacOS arm, `sudo gem install ffi -- --enable-libffi-alloc`
If you are having issues with iOS pods, try blowing it all away! `cd ios && rm -rf Pods/ Podfile.lock && pod install --repo-update`
# Formatting
@ -21,7 +35,6 @@ Use:
flutter format lib/ test/ -l 120
```
# Release
Update `version` in `pubspec.yaml` to reflect this release, then

1
android/.gitignore vendored
View File

@ -6,3 +6,4 @@ gradle-wrapper.jar
/local.properties
GeneratedPluginRegistrant.java
/build/build-attribution/
/mobileNebula/mobileNebula.aar

View File

@ -32,23 +32,28 @@ if (keystorePropertiesFile.exists()) {
}
android {
compileSdkVersion 30
compileSdkVersion flutter.compileSdkVersion
ndkVersion flutter.ndkVersion
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
lintOptions {
disable 'InvalidPackage'
}
defaultConfig {
applicationId "net.defined.mobile_nebula"
minSdkVersion 29
targetSdkVersion 30
minSdkVersion 29 //flutter.minSdkVersion
targetSdkVersion 30 //flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
signingConfigs {
@ -62,17 +67,18 @@ android {
buildTypes {
release {
signingConfig signingConfigs.release
// We are disabling minification and proguard because it wrecks the crypto for storing keys
// Ideally we would turn these on. We had issues with gson as well but resolved those with proguardFiles
shrinkResources false
minifyEnabled false
useProguard false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
// signingConfig signingConfigs.release
//
// // We are disabling minification and proguard because it wrecks the crypto for storing keys
// // Ideally we would turn these on. We had issues with gson as well but resolved those with proguardFiles
// shrinkResources false
// minifyEnabled false
// useProguard false
// proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
//
resValue 'string', 'app_name', '"Nebula"'
}
debug {
resValue 'string', 'app_name', '"Nebula-DEBUG"'
applicationIdSuffix '.debug'
@ -84,26 +90,9 @@ flutter {
source '../..'
}
repositories {
flatDir {
dirs 'src/main/libs'
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation "androidx.security:security-crypto:1.0.0-rc02"
implementation "androidx.security:security-crypto:1.0.0"
implementation 'com.google.code.gson:gson:2.8.6'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
implementation (name:'mobileNebula', ext:'aar') {
exec {
workingDir '../../'
environment("ANDROID_NDK_HOME", android.ndkDirectory)
environment("ANDROID_HOME", android.sdkDirectory)
commandLine './gen-artifacts.sh', 'android'
}
}
}
implementation project(':mobileNebula')
}

View File

@ -9,11 +9,12 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-feature android:name="android.hardware.camera" android:required="false" />
<application
android:name="io.flutter.app.FlutterApplication"
android:name="${applicationName}"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher">
<service android:name=".NebulaVpnService"
android:permission="android.permission.BIND_VPN_SERVICE"
android:exported="false"
android:process=":nebulaVpnBg">
<intent-filter>
<action android:name="android.net.VpnService"/>
@ -21,6 +22,7 @@
</service>
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"

View File

@ -33,7 +33,7 @@ class Share {
} catch (err: Exception) {
Log.println(Log.ERROR, "", "Share: Error")
result.error(err.message, null, null)
result.error(err.message ?: "Unknown error", null, null)
}
}
@ -67,7 +67,7 @@ class Share {
} catch (err: Exception) {
Log.println(Log.ERROR, "", "Share: Error")
result.error(err.message, null, null)
result.error(err.message ?: "Unknown error", null, null)
}
}
@ -107,7 +107,7 @@ class Share {
} catch (err: Exception) {
Log.println(Log.ERROR, "", "Share: Error")
return result.error(err.message, null, null)
return result.error(err.message ?: "Unknown error", null, null)
}
result.success(true)

View File

@ -1,12 +1,12 @@
buildscript {
ext.kotlin_version = '1.3.61'
ext.kotlin_version = '1.6.10'
repositories {
google()
jcenter()
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.0.0'
classpath 'com.android.tools.build:gradle:7.1.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
@ -14,7 +14,7 @@ buildscript {
allprojects {
repositories {
google()
jcenter()
mavenCentral()
}
}

View File

@ -1,4 +1,3 @@
org.gradle.jvmargs=-Xmx1536M
android.enableR8=true
android.useAndroidX=true
android.enableJetifier=true

View File

@ -1,6 +1,5 @@
#Fri Jun 05 14:55:48 CDT 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-all.zip

View File

@ -0,0 +1,6 @@
configurations.maybeCreate("default")
exec {
workingDir '../../'
commandLine './gen-artifacts.sh', 'android'
}
artifacts.add("default", file('mobileNebula.aar'))

View File

@ -1,15 +1,11 @@
include ':app'
include ':app', ':mobileNebula'
def flutterProjectRoot = rootProject.projectDir.parentFile.toPath()
def localPropertiesFile = new File(rootProject.projectDir, "local.properties")
def properties = new Properties()
def plugins = new Properties()
def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins')
if (pluginsFile.exists()) {
pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) }
}
assert localPropertiesFile.exists()
localPropertiesFile.withReader("UTF-8") { reader -> properties.load(reader) }
plugins.each { name, path ->
def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile()
include ":$name"
project(":$name").projectDir = pluginDirectory
}
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"

View File

@ -1 +0,0 @@
include ':app'

View File

@ -16,9 +16,9 @@ if [ "$1" = "ios" ]; then
elif [ "$1" = "android" ]; then
# Build nebula for android
make mobileNebula.aar
mkdir -p ../android/app/src/main/libs
rm -rf ../android/app/src/main/libs/mobileNebula.aar
cp mobileNebula.aar ../android/app/src/main/libs/mobileNebula.aar
mkdir -p ../android/mobileNebula
rm -rf ../android/mobileNebula/mobileNebula.aar
cp mobileNebula.aar ../android/mobileNebula/mobileNebula.aar
else
echo "Error: unsupported target os $1"

View File

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

View File

@ -1,64 +1,57 @@
PODS:
- barcode_scan (0.0.1):
- Flutter
- MTBBarcodeScanner
- SwiftProtobuf
- DKImagePickerController/Core (4.3.0):
- DKImagePickerController/Core (4.3.4):
- DKImagePickerController/ImageDataManager
- DKImagePickerController/Resource
- DKImagePickerController/ImageDataManager (4.3.0)
- DKImagePickerController/PhotoGallery (4.3.0):
- DKImagePickerController/ImageDataManager (4.3.4)
- DKImagePickerController/PhotoGallery (4.3.4):
- DKImagePickerController/Core
- DKPhotoGallery
- DKImagePickerController/Resource (4.3.0)
- DKPhotoGallery (0.0.15):
- DKPhotoGallery/Core (= 0.0.15)
- DKPhotoGallery/Model (= 0.0.15)
- DKPhotoGallery/Preview (= 0.0.15)
- DKPhotoGallery/Resource (= 0.0.15)
- DKImagePickerController/Resource (4.3.4)
- DKPhotoGallery (0.0.17):
- DKPhotoGallery/Core (= 0.0.17)
- DKPhotoGallery/Model (= 0.0.17)
- DKPhotoGallery/Preview (= 0.0.17)
- DKPhotoGallery/Resource (= 0.0.17)
- SDWebImage
- SDWebImageFLPlugin
- DKPhotoGallery/Core (0.0.15):
- SwiftyGif
- DKPhotoGallery/Core (0.0.17):
- DKPhotoGallery/Model
- DKPhotoGallery/Preview
- SDWebImage
- SDWebImageFLPlugin
- DKPhotoGallery/Model (0.0.15):
- SwiftyGif
- DKPhotoGallery/Model (0.0.17):
- SDWebImage
- SDWebImageFLPlugin
- DKPhotoGallery/Preview (0.0.15):
- SwiftyGif
- DKPhotoGallery/Preview (0.0.17):
- DKPhotoGallery/Model
- DKPhotoGallery/Resource
- SDWebImage
- SDWebImageFLPlugin
- DKPhotoGallery/Resource (0.0.15):
- SwiftyGif
- DKPhotoGallery/Resource (0.0.17):
- SDWebImage
- SDWebImageFLPlugin
- SwiftyGif
- file_picker (0.0.1):
- DKImagePickerController/PhotoGallery
- Flutter
- FLAnimatedImage (1.0.12)
- Flutter (1.0.0)
- MTBBarcodeScanner (5.0.11)
- flutter_barcode_scanner (2.0.0):
- Flutter
- package_info (0.0.1):
- Flutter
- path_provider_ios (0.0.1):
- Flutter
- SDWebImage (5.8.0):
- SDWebImage/Core (= 5.8.0)
- SDWebImage/Core (5.8.0)
- SDWebImageFLPlugin (0.4.0):
- FLAnimatedImage (>= 1.0.11)
- SDWebImage/Core (~> 5.6)
- SwiftProtobuf (1.9.0)
- SDWebImage (5.13.3):
- SDWebImage/Core (= 5.13.3)
- SDWebImage/Core (5.13.3)
- SwiftyGif (5.4.3)
- SwiftyJSON (5.0.1)
- url_launcher_ios (0.0.1):
- Flutter
DEPENDENCIES:
- barcode_scan (from `.symlinks/plugins/barcode_scan/ios`)
- file_picker (from `.symlinks/plugins/file_picker/ios`)
- 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`)
- SwiftyJSON (~> 5.0)
@ -68,20 +61,17 @@ SPEC REPOS:
trunk:
- DKImagePickerController
- DKPhotoGallery
- FLAnimatedImage
- MTBBarcodeScanner
- SDWebImage
- SDWebImageFLPlugin
- SwiftProtobuf
- SwiftyGif
- SwiftyJSON
EXTERNAL SOURCES:
barcode_scan:
:path: ".symlinks/plugins/barcode_scan/ios"
file_picker:
:path: ".symlinks/plugins/file_picker/ios"
Flutter:
:path: Flutter
flutter_barcode_scanner:
:path: ".symlinks/plugins/flutter_barcode_scanner/ios"
package_info:
:path: ".symlinks/plugins/package_info/ios"
path_provider_ios:
@ -90,21 +80,18 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/url_launcher_ios/ios"
SPEC CHECKSUMS:
barcode_scan: a5c27959edfafaa0c771905bad0b29d6d39e4479
DKImagePickerController: 397702a3590d4958fad336e9a77079935c500ddb
DKPhotoGallery: e880aef16c108333240e1e7327896f2ea380f4f0
file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1
FLAnimatedImage: 4a0b56255d9b05f18b6dd7ee06871be5d3b89e31
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
file_picker: 817ab1d8cd2da9d2da412a417162deee3500fc95
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
flutter_barcode_scanner: 7a1144744c28dc0c57a8de7218ffe5ec59a9e4bf
package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
path_provider_ios: 7d7ce634493af4477d156294792024ec3485acd5
SDWebImage: 84000f962cbfa70c07f19d2234cbfcf5d779b5dc
SDWebImageFLPlugin: 6c2295fb1242d44467c6c87dc5db6b0a13228fd8
SwiftProtobuf: ecbec1be9036d15655f6b3443a1c4ea693c97932
SDWebImage: af5bbffef2cde09f148d826f9733dcde1a9414cd
SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780
SwiftyJSON: 2f33a42c6fbc52764d96f13368585094bfd8aa5e
url_launcher_ios: 02f1989d4e14e998335b02b67a7590fa34f971af
PODFILE CHECKSUM: 92e176614f91c6517d4254a0edec8b66f076c77e
COCOAPODS: 1.10.1
COCOAPODS: 1.11.3

View File

@ -339,14 +339,11 @@
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/DKImagePickerController/DKImagePickerController.framework",
"${BUILT_PRODUCTS_DIR}/DKPhotoGallery/DKPhotoGallery.framework",
"${BUILT_PRODUCTS_DIR}/FLAnimatedImage/FLAnimatedImage.framework",
"${BUILT_PRODUCTS_DIR}/MTBBarcodeScanner/MTBBarcodeScanner.framework",
"${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework",
"${BUILT_PRODUCTS_DIR}/SDWebImageFLPlugin/SDWebImageFLPlugin.framework",
"${BUILT_PRODUCTS_DIR}/SwiftProtobuf/SwiftProtobuf.framework",
"${BUILT_PRODUCTS_DIR}/SwiftyGif/SwiftyGif.framework",
"${BUILT_PRODUCTS_DIR}/SwiftyJSON/SwiftyJSON.framework",
"${BUILT_PRODUCTS_DIR}/barcode_scan/barcode_scan.framework",
"${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}/url_launcher_ios/url_launcher_ios.framework",
@ -355,14 +352,11 @@
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKImagePickerController.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DKPhotoGallery.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FLAnimatedImage.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MTBBarcodeScanner.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImageFLPlugin.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftProtobuf.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyGif.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftyJSON.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/barcode_scan.framework",
"${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}/url_launcher_ios.framework",
@ -558,7 +552,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 4;
DEVELOPMENT_TEAM = 576H3XS7FP;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
@ -596,7 +590,7 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = NebulaNetworkExtension/NebulaNetworkExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 4;
DEVELOPMENT_TEAM = 576H3XS7FP;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
@ -637,7 +631,7 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = NebulaNetworkExtension/NebulaNetworkExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 4;
DEVELOPMENT_TEAM = 576H3XS7FP;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
@ -675,7 +669,7 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = NebulaNetworkExtension/NebulaNetworkExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 4;
DEVELOPMENT_TEAM = 576H3XS7FP;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
@ -816,7 +810,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 4;
DEVELOPMENT_TEAM = 576H3XS7FP;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (
@ -852,7 +846,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CURRENT_PROJECT_VERSION = 1;
CURRENT_PROJECT_VERSION = 4;
DEVELOPMENT_TEAM = 576H3XS7FP;
ENABLE_BITCODE = NO;
FRAMEWORK_SEARCH_PATHS = (

View File

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

View File

@ -133,13 +133,13 @@ class SiteUpdater: NSObject, FlutterStreamHandler {
let connected = self.site.connected
self.site.status = statusString[self.site.manager!.connection.status]
self.site.connected = statusMap[self.site.manager!.connection.status]
// Check to see if we just moved to connected and if we have a start function to call when that happens
if self.site.connected! && connected != self.site.connected && self.startFunc != nil {
self.startFunc!()
self.startFunc = nil
}
let d: Dictionary<String, Any> = [
"connected": self.site.connected!,
"status": self.site.status!,

View File

@ -8,7 +8,7 @@ import 'IPField.dart';
//TODO: Support initialValue
class CIDRField extends StatefulWidget {
const CIDRField({
Key key,
Key? key,
this.ipHelp = "ip address",
this.autoFocus = false,
this.focusNode,
@ -21,12 +21,12 @@ class CIDRField extends StatefulWidget {
final String ipHelp;
final bool autoFocus;
final FocusNode focusNode;
final FocusNode nextFocusNode;
final ValueChanged<CIDR> onChanged;
final TextInputAction textInputAction;
final TextEditingController ipController;
final TextEditingController bitsController;
final FocusNode? focusNode;
final FocusNode? nextFocusNode;
final ValueChanged<CIDR>? onChanged;
final TextInputAction? textInputAction;
final TextEditingController? ipController;
final TextEditingController? bitsController;
@override
_CIDRFieldState createState() => _CIDRFieldState();
@ -44,7 +44,7 @@ class _CIDRFieldState extends State<CIDRField> {
void initState() {
//TODO: this won't track external controller changes appropriately
cidr.ip = widget.ipController?.text ?? "";
cidr.bits = int.tryParse(widget.bitsController?.text ?? "");
cidr.bits = int.tryParse(widget.bitsController?.text ?? "") ?? 0;
super.initState();
}
@ -66,8 +66,12 @@ class _CIDRFieldState extends State<CIDRField> {
focusNode: widget.focusNode,
nextFocusNode: bitsFocus,
onChanged: (val) {
if (widget.onChanged == null) {
return;
}
cidr.ip = val;
widget.onChanged(cidr);
widget.onChanged!(cidr);
},
controller: widget.ipController,
))),
@ -81,8 +85,12 @@ class _CIDRFieldState extends State<CIDRField> {
nextFocusNode: widget.nextFocusNode,
controller: widget.bitsController,
onChanged: (val) {
cidr.bits = int.tryParse(val ?? "");
widget.onChanged(cidr);
if (widget.onChanged == null) {
return;
}
cidr.bits = int.tryParse(val) ?? 0;
widget.onChanged!(cidr);
},
maxLength: 2,
inputFormatters: [FilteringTextInputFormatter.digitsOnly],

View File

@ -6,15 +6,15 @@ import 'package:mobile_nebula/validators/ipValidator.dart';
class CIDRFormField extends FormField<CIDR> {
//TODO: onSaved, validator, auto-validate, enabled?
CIDRFormField({
Key key,
Key? key,
autoFocus = false,
enableIPV6 = false,
focusNode,
nextFocusNode,
ValueChanged<CIDR> onChanged,
FormFieldSetter<CIDR> onSaved,
ValueChanged<CIDR>? onChanged,
FormFieldSetter<CIDR>? onSaved,
textInputAction,
CIDR initialValue,
CIDR? initialValue,
this.ipController,
this.bitsController,
}) : super(
@ -30,14 +30,14 @@ class CIDRFormField extends FormField<CIDR> {
return 'Please enter a valid ip address';
}
if (cidr.bits == null || cidr.bits > 32 || cidr.bits < 0) {
if (cidr.bits > 32 || cidr.bits < 0) {
return "Please enter a valid number of bits";
}
return null;
},
builder: (FormFieldState<CIDR> field) {
final _CIDRFormField state = field;
final _CIDRFormField state = field as _CIDRFormField;
void onChangedHandler(CIDR value) {
if (onChanged != null) {
@ -57,50 +57,50 @@ class CIDRFormField extends FormField<CIDR> {
bitsController: state._effectiveBitsController,
),
field.hasError
? Text(field.errorText,
? Text(field.errorText ?? "Unknown error",
style: TextStyle(color: CupertinoColors.systemRed.resolveFrom(field.context), fontSize: 13),
textAlign: TextAlign.end)
: Container(height: 0)
]);
});
final TextEditingController ipController;
final TextEditingController bitsController;
final TextEditingController? ipController;
final TextEditingController? bitsController;
@override
_CIDRFormField createState() => _CIDRFormField();
}
class _CIDRFormField extends FormFieldState<CIDR> {
TextEditingController _ipController;
TextEditingController _bitsController;
TextEditingController? _ipController = TextEditingController();
TextEditingController? _bitsController = TextEditingController();
TextEditingController get _effectiveIPController => widget.ipController ?? _ipController;
TextEditingController get _effectiveBitsController => widget.bitsController ?? _bitsController;
TextEditingController get _effectiveIPController => widget.ipController ?? _ipController!;
TextEditingController get _effectiveBitsController => widget.bitsController ?? _bitsController!;
@override
CIDRFormField get widget => super.widget;
CIDRFormField get widget => super.widget as CIDRFormField;
@override
void initState() {
super.initState();
if (widget.ipController == null) {
_ipController = TextEditingController(text: widget.initialValue.ip);
_ipController = TextEditingController(text: widget.initialValue?.ip);
} else {
widget.ipController.addListener(_handleControllerChanged);
widget.ipController!.addListener(_handleControllerChanged);
}
if (widget.bitsController == null) {
_bitsController = TextEditingController(text: widget.initialValue?.bits?.toString() ?? "");
} else {
widget.bitsController.addListener(_handleControllerChanged);
widget.bitsController!.addListener(_handleControllerChanged);
}
}
@override
void didUpdateWidget(CIDRFormField oldWidget) {
super.didUpdateWidget(oldWidget);
var update = CIDR(ip: widget.ipController?.text, bits: int.tryParse(widget.bitsController?.text ?? "") ?? null);
var update = CIDR(ip: widget.ipController?.text ?? "", bits: int.tryParse(widget.bitsController?.text ?? "") ?? 0);
bool shouldUpdate = false;
if (widget.ipController != oldWidget.ipController) {
@ -108,12 +108,12 @@ class _CIDRFormField extends FormFieldState<CIDR> {
widget.ipController?.addListener(_handleControllerChanged);
if (oldWidget.ipController != null && widget.ipController == null) {
_ipController = TextEditingController.fromValue(oldWidget.ipController.value);
_ipController = TextEditingController.fromValue(oldWidget.ipController!.value);
}
if (widget.ipController != null) {
shouldUpdate = true;
update.ip = widget.ipController.text;
update.ip = widget.ipController!.text;
if (oldWidget.ipController == null) _ipController = null;
}
}
@ -123,12 +123,12 @@ class _CIDRFormField extends FormFieldState<CIDR> {
widget.bitsController?.addListener(_handleControllerChanged);
if (oldWidget.bitsController != null && widget.bitsController == null) {
_bitsController = TextEditingController.fromValue(oldWidget.bitsController.value);
_bitsController = TextEditingController.fromValue(oldWidget.bitsController!.value);
}
if (widget.bitsController != null) {
shouldUpdate = true;
update.bits = int.parse(widget.bitsController.text);
update.bits = int.parse(widget.bitsController!.text);
if (oldWidget.bitsController == null) _bitsController = null;
}
}
@ -149,8 +149,8 @@ class _CIDRFormField extends FormFieldState<CIDR> {
void reset() {
super.reset();
setState(() {
_effectiveIPController.text = widget.initialValue.ip;
_effectiveBitsController.text = widget.initialValue.bits.toString();
_effectiveIPController.text = widget.initialValue?.ip ?? "";
_effectiveBitsController.text = widget.initialValue?.bits.toString() ?? "";
});
}
@ -163,7 +163,11 @@ class _CIDRFormField extends FormFieldState<CIDR> {
// example, the reset() method. In such cases, the FormField value will
// already have been set.
final effectiveBits = int.parse(_effectiveBitsController.text);
if (_effectiveIPController.text != value.ip || effectiveBits != value.bits) {
if (value == null) {
return;
}
if (_effectiveIPController.text != value!.ip || effectiveBits != value!.bits) {
didChange(CIDR(ip: _effectiveIPController.text, bits: effectiveBits));
}
}

View File

@ -8,11 +8,11 @@ import 'package:mobile_nebula/services/utils.dart';
/// SimplePage with a form and built in validation and confirmation to discard changes if any are made
class FormPage extends StatefulWidget {
const FormPage(
{Key key,
this.title,
@required this.child,
@required this.onSave,
@required this.changed,
{Key? key,
required this.title,
required this.child,
required this.onSave,
required this.changed,
this.hideSave = false,
this.scrollController})
: super(key: key);
@ -20,7 +20,7 @@ class FormPage extends StatefulWidget {
final String title;
final Function onSave;
final Widget child;
final ScrollController scrollController;
final ScrollController? scrollController;
/// If you need the page to progress to a certain point before saving, control it here
final bool hideSave;
@ -90,11 +90,15 @@ class _FormPageState extends State<FormPage> {
Utils.trailingSaveWidget(
context,
() {
if (!_formKey.currentState.validate()) {
if (_formKey.currentState == null) {
return;
}
_formKey.currentState.save();
if (!_formKey.currentState!.validate()) {
return;
}
_formKey.currentState!.save();
widget.onSave();
},
)

View File

@ -8,13 +8,13 @@ import 'IPField.dart';
//TODO: Support initialValue
class IPAndPortField extends StatefulWidget {
const IPAndPortField({
Key key,
Key? key,
this.ipOnly = false,
this.ipHelp = "ip address",
this.autoFocus = false,
this.focusNode,
this.nextFocusNode,
this.onChanged,
required this.onChanged,
this.textInputAction,
this.noBorder = false,
this.ipTextAlign,
@ -25,14 +25,14 @@ class IPAndPortField extends StatefulWidget {
final String ipHelp;
final bool ipOnly;
final bool autoFocus;
final FocusNode focusNode;
final FocusNode nextFocusNode;
final FocusNode? focusNode;
final FocusNode? nextFocusNode;
final ValueChanged<IPAndPort> onChanged;
final TextInputAction textInputAction;
final TextInputAction? textInputAction;
final bool noBorder;
final TextAlign ipTextAlign;
final TextEditingController ipController;
final TextEditingController portController;
final TextAlign? ipTextAlign;
final TextEditingController? ipController;
final TextEditingController? portController;
@override
_IPAndPortFieldState createState() => _IPAndPortFieldState();

View File

@ -8,17 +8,17 @@ import 'IPAndPortField.dart';
class IPAndPortFormField extends FormField<IPAndPort> {
//TODO: onSaved, validator, auto-validate, enabled?
IPAndPortFormField({
Key key,
Key? key,
ipOnly = false,
enableIPV6 = false,
ipHelp = "ip address",
autoFocus = false,
focusNode,
nextFocusNode,
ValueChanged<IPAndPort> onChanged,
FormFieldSetter<IPAndPort> onSaved,
ValueChanged<IPAndPort>? onChanged,
FormFieldSetter<IPAndPort>? onSaved,
textInputAction,
IPAndPort initialValue,
IPAndPort? initialValue,
noBorder,
ipTextAlign = TextAlign.center,
this.ipController,
@ -36,14 +36,14 @@ class IPAndPortFormField extends FormField<IPAndPort> {
return ipOnly ? 'Please enter a valid ip address' : 'Please enter a valid ip address or dns name';
}
if (ipAndPort.port == null || ipAndPort.port > 65535 || ipAndPort.port < 0) {
if (ipAndPort.port == null || ipAndPort.port! > 65535 || ipAndPort.port! < 0) {
return "Please enter a valid port";
}
return null;
},
builder: (FormFieldState<IPAndPort> field) {
final _IPAndPortFormField state = field;
final _IPAndPortFormField state = field as _IPAndPortFormField;
void onChangedHandler(IPAndPort value) {
if (onChanged != null) {
@ -67,42 +67,42 @@ class IPAndPortFormField extends FormField<IPAndPort> {
ipTextAlign: ipTextAlign,
),
field.hasError
? Text(field.errorText,
? Text(field.errorText!,
style: TextStyle(color: CupertinoColors.systemRed.resolveFrom(field.context), fontSize: 13))
: Container(height: 0)
]);
});
final TextEditingController ipController;
final TextEditingController portController;
final TextEditingController? ipController;
final TextEditingController? portController;
@override
_IPAndPortFormField createState() => _IPAndPortFormField();
}
class _IPAndPortFormField extends FormFieldState<IPAndPort> {
TextEditingController _ipController;
TextEditingController _portController;
TextEditingController? _ipController;
TextEditingController? _portController;
TextEditingController get _effectiveIPController => widget.ipController ?? _ipController;
TextEditingController get _effectivePortController => widget.portController ?? _portController;
TextEditingController get _effectiveIPController => widget.ipController ?? _ipController!;
TextEditingController get _effectivePortController => widget.portController ?? _portController!;
@override
IPAndPortFormField get widget => super.widget;
IPAndPortFormField get widget => super.widget as IPAndPortFormField;
@override
void initState() {
super.initState();
if (widget.ipController == null) {
_ipController = TextEditingController(text: widget.initialValue.ip);
_ipController = TextEditingController(text: widget.initialValue?.ip ?? "");
} else {
widget.ipController.addListener(_handleControllerChanged);
widget.ipController!.addListener(_handleControllerChanged);
}
if (widget.portController == null) {
_portController = TextEditingController(text: widget.initialValue?.port?.toString() ?? "");
} else {
widget.portController.addListener(_handleControllerChanged);
widget.portController!.addListener(_handleControllerChanged);
}
}
@ -118,12 +118,12 @@ class _IPAndPortFormField extends FormFieldState<IPAndPort> {
widget.ipController?.addListener(_handleControllerChanged);
if (oldWidget.ipController != null && widget.ipController == null) {
_ipController = TextEditingController.fromValue(oldWidget.ipController.value);
_ipController = TextEditingController.fromValue(oldWidget.ipController!.value);
}
if (widget.ipController != null) {
shouldUpdate = true;
update.ip = widget.ipController.text;
update.ip = widget.ipController!.text;
if (oldWidget.ipController == null) _ipController = null;
}
}
@ -133,12 +133,12 @@ class _IPAndPortFormField extends FormFieldState<IPAndPort> {
widget.portController?.addListener(_handleControllerChanged);
if (oldWidget.portController != null && widget.portController == null) {
_portController = TextEditingController.fromValue(oldWidget.portController.value);
_portController = TextEditingController.fromValue(oldWidget.portController!.value);
}
if (widget.portController != null) {
shouldUpdate = true;
update.port = int.parse(widget.portController.text);
update.port = int.parse(widget.portController!.text);
if (oldWidget.portController == null) _portController = null;
}
}
@ -159,8 +159,8 @@ class _IPAndPortFormField extends FormFieldState<IPAndPort> {
void reset() {
super.reset();
setState(() {
_effectiveIPController.text = widget.initialValue.ip;
_effectivePortController.text = widget.initialValue.port.toString();
_effectiveIPController.text = widget.initialValue?.ip ?? "";
_effectivePortController.text = widget.initialValue?.port?.toString() ?? "";
});
}
@ -173,7 +173,11 @@ class _IPAndPortFormField extends FormFieldState<IPAndPort> {
// example, the reset() method. In such cases, the FormField value will
// already have been set.
final effectivePort = int.parse(_effectivePortController.text);
if (_effectiveIPController.text != value.ip || effectivePort != value.port) {
if (value == null) {
return;
}
if (_effectiveIPController.text != value!.ip || effectivePort != value!.port) {
didChange(IPAndPort(ip: _effectiveIPController.text, port: effectivePort));
}
}

View File

@ -8,16 +8,16 @@ class IPField extends StatelessWidget {
final String help;
final bool ipOnly;
final bool autoFocus;
final FocusNode focusNode;
final FocusNode nextFocusNode;
final ValueChanged<String> onChanged;
final FocusNode? focusNode;
final FocusNode? nextFocusNode;
final ValueChanged<String>? onChanged;
final EdgeInsetsGeometry textPadding;
final TextInputAction textInputAction;
final TextInputAction? textInputAction;
final controller;
final textAlign;
const IPField(
{Key key,
{Key? key,
this.ipOnly = false,
this.help = "ip address",
this.autoFocus = false,
@ -33,7 +33,7 @@ class IPField extends StatelessWidget {
@override
Widget build(BuildContext context) {
var textStyle = CupertinoTheme.of(context).textTheme.textStyle;
final double ipWidth = ipOnly ? Utils.textSize("000000000000000", textStyle).width + 12 : null;
final double? ipWidth = ipOnly ? Utils.textSize("000000000000000", textStyle).width + 12 : null;
return SizedBox(
width: ipWidth,
@ -64,7 +64,7 @@ class IPTextInputFormatter extends TextInputFormatter {
(String substring) {
return whitelistedPattern
.allMatches(substring)
.map<String>((Match match) => match.group(0))
.map<String>((Match match) => match.group(0)!)
.join()
.replaceAll(RegExp(r','), '.');
},
@ -79,7 +79,7 @@ TextEditingValue _selectionAwareTextManipulation(
final int selectionStartIndex = value.selection.start;
final int selectionEndIndex = value.selection.end;
String manipulatedText;
TextSelection manipulatedSelection;
TextSelection? manipulatedSelection;
if (selectionStartIndex < 0 || selectionEndIndex < 0) {
manipulatedText = substringManipulation(value.text);
} else {

View File

@ -9,15 +9,15 @@ import 'IPField.dart';
class IPFormField extends FormField<String> {
//TODO: validator, auto-validate, enabled?
IPFormField({
Key key,
Key? key,
ipOnly = false,
enableIPV6 = false,
help = "ip address",
autoFocus = false,
focusNode,
nextFocusNode,
ValueChanged<String> onChanged,
FormFieldSetter<String> onSaved,
ValueChanged<String>? onChanged,
FormFieldSetter<String>? onSaved,
textPadding = const EdgeInsets.all(6.0),
textInputAction,
initialValue,
@ -41,7 +41,7 @@ class IPFormField extends FormField<String> {
return null;
},
builder: (FormFieldState<String> field) {
final _IPFormField state = field;
final _IPFormField state = field as _IPFormField;
void onChangedHandler(String value) {
if (onChanged != null) {
@ -64,7 +64,7 @@ class IPFormField extends FormField<String> {
textAlign: textAlign),
field.hasError
? Text(
field.errorText,
field.errorText!,
style: TextStyle(color: CupertinoColors.systemRed.resolveFrom(field.context), fontSize: 13),
textAlign: textAlign,
)
@ -72,19 +72,19 @@ class IPFormField extends FormField<String> {
]);
});
final TextEditingController controller;
final TextEditingController? controller;
@override
_IPFormField createState() => _IPFormField();
}
class _IPFormField extends FormFieldState<String> {
TextEditingController _controller;
TextEditingController? _controller;
TextEditingController get _effectiveController => widget.controller ?? _controller;
TextEditingController get _effectiveController => widget.controller ?? _controller!;
@override
IPFormField get widget => super.widget;
IPFormField get widget => super.widget as IPFormField;
@override
void initState() {
@ -92,7 +92,7 @@ class _IPFormField extends FormFieldState<String> {
if (widget.controller == null) {
_controller = TextEditingController(text: widget.initialValue);
} else {
widget.controller.addListener(_handleControllerChanged);
widget.controller!.addListener(_handleControllerChanged);
}
}
@ -104,9 +104,9 @@ class _IPFormField extends FormFieldState<String> {
widget.controller?.addListener(_handleControllerChanged);
if (oldWidget.controller != null && widget.controller == null)
_controller = TextEditingController.fromValue(oldWidget.controller.value);
_controller = TextEditingController.fromValue(oldWidget.controller!.value);
if (widget.controller != null) {
setValue(widget.controller.text);
setValue(widget.controller!.text);
if (oldWidget.controller == null) _controller = null;
}
}
@ -122,7 +122,7 @@ class _IPFormField extends FormFieldState<String> {
void reset() {
super.reset();
setState(() {
_effectiveController.text = widget.initialValue;
_effectiveController.text = widget.initialValue ?? "";
});
}

View File

@ -6,14 +6,14 @@ import 'package:mobile_nebula/components/SpecialTextField.dart';
class PlatformTextFormField extends FormField<String> {
//TODO: auto-validate, enabled?
PlatformTextFormField(
{Key key,
{Key? key,
widgetKey,
this.controller,
focusNode,
nextFocusNode,
TextInputType keyboardType,
TextInputType? keyboardType,
textInputAction,
List<TextInputFormatter> inputFormatters,
List<TextInputFormatter>? inputFormatters,
textAlign,
autofocus,
maxLines = 1,
@ -25,10 +25,10 @@ class PlatformTextFormField extends FormField<String> {
expands,
suffix,
textAlignVertical,
String initialValue,
String placeholder,
FormFieldValidator<String> validator,
ValueChanged<String> onSaved})
String? initialValue,
String? placeholder,
FormFieldValidator<String>? validator,
ValueChanged<String?>? onSaved})
: super(
key: key,
initialValue: controller != null ? controller.text : (initialValue ?? ''),
@ -41,7 +41,7 @@ class PlatformTextFormField extends FormField<String> {
return null;
},
builder: (FormFieldState<String> field) {
final _PlatformTextFormFieldState state = field;
final _PlatformTextFormFieldState state = field as _PlatformTextFormFieldState;
void onChangedHandler(String value) {
if (onChanged != null) {
@ -73,7 +73,7 @@ class PlatformTextFormField extends FormField<String> {
suffix: suffix),
field.hasError
? Text(
field.errorText,
field.errorText!,
style: TextStyle(color: CupertinoColors.systemRed.resolveFrom(field.context), fontSize: 13),
textAlign: textAlign,
)
@ -81,19 +81,19 @@ class PlatformTextFormField extends FormField<String> {
]);
});
final TextEditingController controller;
final TextEditingController? controller;
@override
_PlatformTextFormFieldState createState() => _PlatformTextFormFieldState();
}
class _PlatformTextFormFieldState extends FormFieldState<String> {
TextEditingController _controller;
TextEditingController? _controller;
TextEditingController get _effectiveController => widget.controller ?? _controller;
TextEditingController get _effectiveController => widget.controller ?? _controller!;
@override
PlatformTextFormField get widget => super.widget;
PlatformTextFormField get widget => super.widget as PlatformTextFormField;
@override
void initState() {
@ -101,7 +101,7 @@ class _PlatformTextFormFieldState extends FormFieldState<String> {
if (widget.controller == null) {
_controller = TextEditingController(text: widget.initialValue);
} else {
widget.controller.addListener(_handleControllerChanged);
widget.controller!.addListener(_handleControllerChanged);
}
}
@ -113,9 +113,9 @@ class _PlatformTextFormFieldState extends FormFieldState<String> {
widget.controller?.addListener(_handleControllerChanged);
if (oldWidget.controller != null && widget.controller == null)
_controller = TextEditingController.fromValue(oldWidget.controller.value);
_controller = TextEditingController.fromValue(oldWidget.controller!.value);
if (widget.controller != null) {
setValue(widget.controller.text);
setValue(widget.controller!.text);
if (oldWidget.controller == null) _controller = null;
}
}
@ -131,7 +131,7 @@ class _PlatformTextFormFieldState extends FormFieldState<String> {
void reset() {
super.reset();
setState(() {
_effectiveController.text = widget.initialValue;
_effectiveController.text = widget.initialValue ?? "";
});
}

View File

@ -13,9 +13,9 @@ enum SimpleScrollable {
class SimplePage extends StatelessWidget {
const SimplePage(
{Key key,
this.title,
@required this.child,
{Key? key,