diff --git a/.github/workflows/base.yaml b/.github/workflows/base.yaml index a963f32..7a5a9f5 100644 --- a/.github/workflows/base.yaml +++ b/.github/workflows/base.yaml @@ -11,68 +11,22 @@ on: workflow_dispatch: +# This ensures that previous jobs for the PR are canceled when PR is updated +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: build: - runs-on: macos-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - with: - fetch-depth: 1 # Use shallow clone for faster checkout - - - name: Check broken links - uses: JustinBeckwith/linkinator-action@v1 - with: - paths: "**/*.md" - - - name: Setup Java - uses: actions/setup-java@v4 - with: - distribution: 'zulu' - java-version: '11' - - - name: Get Flutter version by FVM - uses: kuhnroyal/flutter-fvm-config-action@v2 - id: fvm-config-action - with: - path: ".fvmrc" - - - name: Flutter action - uses: subosito/flutter-action@v2 - with: - flutter-version: ${{ steps.fvm-config-action.outputs.FLUTTER_VERSION }} - channel: ${{ steps.fvm-config-action.outputs.FLUTTER_CHANNEL }} - architecture: x64 - cache: true - - - name: Install dependencies - run: flutter pub get - - name: Format code - run: dart format --set-exit-if-changed . - - name: Analyze static code - run: flutter analyze - - name: Run tests - run: flutter test --no-pub --coverage - - name: Check publish warnings - run: dart pub publish --dry-run - - name: Upload coverage to Codecov - uses: codecov/codecov-action@v4 - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - with: - files: coverage/lcov.info - name: form_builder_cupertino_fields - - name: Build example - run: | - cd example - flutter build appbundle --debug - flutter build ios --debug --no-codesign - flutter build web + uses: flutter-form-builder-ecosystem/.github/.github/workflows/minimal-quality.yaml@main + with: + codecov-name: 'form_builder_cupertino_fields' + example: + uses: flutter-form-builder-ecosystem/.github/.github/workflows/build-examples.yaml@main deployment: permissions: id-token: write uses: flutter-form-builder-ecosystem/.github/.github/workflows/deployment.yaml@main if: ${{ github.ref_type == 'tag' }} - needs: build + needs: [build, example] diff --git a/example/.metadata b/example/.metadata index 87fe974..b02a7e4 100644 --- a/example/.metadata +++ b/example/.metadata @@ -1,11 +1,11 @@ # This file tracks properties of this Flutter project. # Used by Flutter tool to assess capabilities and perform upgrades etc. # -# This file should be version controlled. +# This file should be version controlled and should not be manually edited. version: - revision: f72efea43c3013323d1b95cff571f3c1caa37583 - channel: stable + revision: "17025dd88227cd9532c33fa78f5250d548d87e9a" + channel: "stable" project_type: app @@ -13,26 +13,26 @@ project_type: app migration: platforms: - platform: root - create_revision: f72efea43c3013323d1b95cff571f3c1caa37583 - base_revision: f72efea43c3013323d1b95cff571f3c1caa37583 + create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a + base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a - platform: android - create_revision: f72efea43c3013323d1b95cff571f3c1caa37583 - base_revision: f72efea43c3013323d1b95cff571f3c1caa37583 + create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a + base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a - platform: ios - create_revision: f72efea43c3013323d1b95cff571f3c1caa37583 - base_revision: f72efea43c3013323d1b95cff571f3c1caa37583 + create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a + base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a - platform: linux - create_revision: f72efea43c3013323d1b95cff571f3c1caa37583 - base_revision: f72efea43c3013323d1b95cff571f3c1caa37583 + create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a + base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a - platform: macos - create_revision: f72efea43c3013323d1b95cff571f3c1caa37583 - base_revision: f72efea43c3013323d1b95cff571f3c1caa37583 + create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a + base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a - platform: web - create_revision: f72efea43c3013323d1b95cff571f3c1caa37583 - base_revision: f72efea43c3013323d1b95cff571f3c1caa37583 + create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a + base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a - platform: windows - create_revision: f72efea43c3013323d1b95cff571f3c1caa37583 - base_revision: f72efea43c3013323d1b95cff571f3c1caa37583 + create_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a + base_revision: 17025dd88227cd9532c33fa78f5250d548d87e9a # User provided section diff --git a/example/android/.gitignore b/example/android/.gitignore index 6f56801..55afd91 100644 --- a/example/android/.gitignore +++ b/example/android/.gitignore @@ -7,7 +7,7 @@ gradle-wrapper.jar GeneratedPluginRegistrant.java # Remember to never publicly share your keystore. -# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app +# See https://flutter.dev/to/reference-keystore key.properties **/*.keystore **/*.jks diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle index 404675e..b5511a9 100644 --- a/example/android/app/build.gradle +++ b/example/android/app/build.gradle @@ -1,64 +1,44 @@ plugins { id "com.android.application" id "kotlin-android" + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. id "dev.flutter.flutter-gradle-plugin" } -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - android { - compileSdkVersion flutter.compileSdkVersion - ndkVersion flutter.ndkVersion + namespace = "com.example.example" + compileSdk = flutter.compileSdkVersion + ndkVersion = flutter.ndkVersion compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 } kotlinOptions { - jvmTarget = '1.8' - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' + jvmTarget = JavaVersion.VERSION_1_8 } defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId "com.example.example" + applicationId = "com.example.example" // You can update the following values to match your application needs. - // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. - minSdkVersion flutter.minSdkVersion - targetSdkVersion flutter.targetSdkVersion - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName } buildTypes { release { // TODO: Add your own signing config for the release build. // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug + signingConfig = signingConfigs.debug } } } flutter { - source '../..' + source = "../.." } diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml index 45d523a..399f698 100644 --- a/example/android/app/src/debug/AndroidManifest.xml +++ b/example/android/app/src/debug/AndroidManifest.xml @@ -1,5 +1,4 @@ - + + + + + + + diff --git a/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt b/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt index e793a00..70f8f08 100644 --- a/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt +++ b/example/android/app/src/main/kotlin/com/example/example/MainActivity.kt @@ -2,5 +2,4 @@ package com.example.example import io.flutter.embedding.android.FlutterActivity -class MainActivity: FlutterActivity() { -} +class MainActivity: FlutterActivity() diff --git a/example/android/app/src/profile/AndroidManifest.xml b/example/android/app/src/profile/AndroidManifest.xml index 45d523a..399f698 100644 --- a/example/android/app/src/profile/AndroidManifest.xml +++ b/example/android/app/src/profile/AndroidManifest.xml @@ -1,5 +1,4 @@ - + - + @@ -31,29 +31,8 @@ example - - - - - + diff --git a/lib/form_builder_cupertino_fields.dart b/lib/form_builder_cupertino_fields.dart index 8541e2b..da027e6 100644 --- a/lib/form_builder_cupertino_fields.dart +++ b/lib/form_builder_cupertino_fields.dart @@ -1,5 +1,3 @@ -library form_builder_cupertino_fields; - export 'src/fields/form_builder_cupertino_checkbox.dart'; export 'src/fields/form_builder_cupertino_segmented_control.dart'; export 'src/fields/form_builder_cupertino_slider.dart'; diff --git a/lib/src/fields/form_builder_cupertino_checkbox.dart b/lib/src/fields/form_builder_cupertino_checkbox.dart index d47a14d..eab0ba4 100644 --- a/lib/src/fields/form_builder_cupertino_checkbox.dart +++ b/lib/src/fields/form_builder_cupertino_checkbox.dart @@ -45,10 +45,13 @@ class FormBuilderCupertinoCheckbox extends FormBuilderField { /// [prefix] and [child]. If null, the row is shorter. final Widget? Function(String error)? errorBuilder; - /// The color to use when this radio button is not selected. + /// {@macro flutter.cupertino.CupertinoCheckbox.fillColor} /// - /// Defaults to [CupertinoColors.white]. - final Color? inactiveColor; + /// If [fillColor] resolves to null for the requested state, then the fill color + /// falls back to [activeColor] if the state includes [WidgetState.selected], + /// [CupertinoColors.white] at 50% opacity if checkbox is disabled, + /// and [CupertinoColors.white] otherwise. + final WidgetStateProperty? fillColor; /// The color for the radio's border when it has the input focus. /// @@ -85,6 +88,40 @@ class FormBuilderCupertinoCheckbox extends FormBuilderField { /// [RoundedRectangleBorder] with a circular corner radius of 4.0. final OutlinedBorder? shape; + /// The semantic label for the checkbox that will be announced by screen readers. + /// + /// This is announced by assistive technologies (e.g TalkBack/VoiceOver). + /// + /// This label does not show in the UI. + final String? semanticLabel; + + /// {@macro flutter.widgets.Focus.autofocus} + final bool autofocus; + + /// The cursor for a mouse pointer when it enters or is hovering over the + /// widget. + /// + /// If [mouseCursor] is a [WidgetStateMouseCursor], + /// [WidgetStateProperty.resolve] is used for the following [WidgetState]s: + /// + /// * [WidgetState.selected]. + /// * [WidgetState.focused]. + /// * [WidgetState.disabled]. + /// + /// When [value] is null and [tristate] is true, [WidgetState.selected] is + /// included as a state. + /// + /// If null, then [SystemMouseCursors.basic] is used when this checkbox is + /// disabled. When the checkbox is enabled, [SystemMouseCursors.click] is used + /// on Web, and [SystemMouseCursors.basic] is used on other platforms. + /// + /// See also: + /// + /// * [WidgetStateMouseCursor], a [MouseCursor] that implements + /// [WidgetStateProperty] which is used in APIs that need to accept + /// either a [MouseCursor] or a [WidgetStateProperty]. + final MouseCursor? mouseCursor; + /// Creates On/Off Cupertino switch field FormBuilderCupertinoCheckbox({ super.key, @@ -106,11 +143,14 @@ class FormBuilderCupertinoCheckbox extends FormBuilderField { this.contentPadding, this.prefix, this.focusColor, - this.inactiveColor, + this.fillColor, this.checkColor, this.shape, this.side, this.tristate = false, + this.semanticLabel, + this.autofocus = false, + this.mouseCursor, }) : super( builder: (FormFieldState field) { final state = field as _FormBuilderCupertinoCheckboxState; @@ -118,12 +158,15 @@ class FormBuilderCupertinoCheckbox extends FormBuilderField { final fieldWidget = CupertinoCheckbox( focusColor: focusColor, focusNode: state.effectiveFocusNode, - inactiveColor: inactiveColor, + fillColor: fillColor, value: state.value ?? false, checkColor: checkColor, shape: shape, side: side, tristate: tristate, + autofocus: autofocus, + mouseCursor: mouseCursor, + semanticLabel: semanticLabel, onChanged: state.enabled ? (value) { field.didChange(value); diff --git a/lib/src/fields/form_builder_cupertino_switch.dart b/lib/src/fields/form_builder_cupertino_switch.dart index 65c8d3f..f5b0ecc 100644 --- a/lib/src/fields/form_builder_cupertino_switch.dart +++ b/lib/src/fields/form_builder_cupertino_switch.dart @@ -5,22 +5,238 @@ import 'package:flutter_form_builder/flutter_form_builder.dart'; /// On/Off Cupertino switch field class FormBuilderCupertinoSwitch extends FormBuilderField { - /// The color to use when this switch is on. + /// The color to use for the track when the switch is on. /// - /// Defaults to [CupertinoColors.systemGreen] when null and ignores - /// the [CupertinoTheme] in accordance to native iOS behavior. - final Color? activeColor; + /// If null and [applyTheme] is false, defaults to [CupertinoColors.systemGreen] + /// in accordance to native iOS behavior. Otherwise, defaults to + /// [CupertinoThemeData.primaryColor]. + /// + /// See also: + /// + /// * [inactiveTrackColor], the color to use for the track when the switch is off. + final Color? activeTrackColor; /// The color to use for the background when the switch is off. /// /// Defaults to [CupertinoColors.secondarySystemFill] when null. final Color? trackColor; - /// The color to use for the thumb of the switch. + /// The color to use on the thumb when the switch is off. + /// + /// If this color is not opaque, it is blended against + /// [CupertinoThemeData.scaffoldBackgroundColor], so as not to see through the + /// thumb to the track underneath. + /// + /// If null, defaults to [thumbColor]. If that is also null, + /// [CupertinoColors.white] is used. + /// + /// See also: + /// + /// * [thumbColor], the color to use for the thumb when the switch is on. + final Color? inactiveThumbColor; + + /// The color to use for the focus highlight for keyboard interactions. + /// + /// Defaults to [activeColor] with an opacity of 0.80, a brightness of 0.69 + /// and a saturation of 0.835. + final Color? focusColor; + + /// The color to use for the accessibility label when the switch is on. /// /// Defaults to [CupertinoColors.white] when null. + final Color? onLabelColor; + + /// The color to use for the accessibility label when the switch is off. + /// + /// Defaults to [Color.fromARGB(255, 179, 179, 179)] + /// (or [Color.fromARGB(255, 255, 255, 255)] in high contrast) when null. + final Color? offLabelColor; + + /// {@macro flutter.material.switch.activeThumbImage} + final ImageProvider? activeThumbImage; + + /// {@macro flutter.material.switch.onActiveThumbImageError} + final ImageErrorListener? onActiveThumbImageError; + + /// {@macro flutter.material.switch.inactiveThumbImage} + final ImageProvider? inactiveThumbImage; + + /// {@macro flutter.material.switch.onInactiveThumbImageError} + final ImageErrorListener? onInactiveThumbImageError; + + /// Handler called when the focus changes. + /// + /// Called with true if this widget's node gains focus, and false if it loses + /// focus. + final ValueChanged? onFocusChange; + + /// {@macro flutter.widgets.Focus.autofocus} + final bool autofocus; + + /// {@template flutter.cupertino.CupertinoSwitch.applyTheme} + /// Whether to apply the ambient [CupertinoThemeData]. + /// + /// If true, the track uses [CupertinoThemeData.primaryColor] for the track + /// when the switch is on. + /// + /// Defaults to [CupertinoThemeData.applyThemeToAll]. + /// {@endtemplate} + final bool? applyTheme; + + /// The color to use for the track when the switch is off. + /// + /// Defaults to [CupertinoColors.secondarySystemFill] when null. + /// + /// See also: + /// + /// * [activeTrackColor], the color to use for the track when the switch is on. + final Color? inactiveTrackColor; + + /// The color to use for the thumb when the switch is on. + /// + /// If this color is not opaque, it is blended against + /// [CupertinoThemeData.scaffoldBackgroundColor], so as not to see through the + /// thumb to the track underneath. + /// + /// Defaults to [CupertinoColors.white] when null. + /// + /// See also: + /// + /// * [inactiveThumbColor], the color to use for the thumb when the switch is off. final Color? thumbColor; + /// The cursor for a mouse pointer when it enters or is hovering over the + /// widget. + /// + /// Resolved in the following states: + /// * [WidgetState.selected]. + /// * [WidgetState.hovered]. + /// * [WidgetState.focused]. + /// * [WidgetState.disabled]. + /// + /// {@tool snippet} + /// This example resolves the [mouseCursor] based on the current + /// [WidgetState] of the [CupertinoSwitch], providing a different [mouseCursor] when it is + /// [WidgetState.disabled]. + /// + /// ```dart + /// CupertinoSwitch( + /// value: true, + /// onChanged: (bool value) { }, + /// mouseCursor: WidgetStateProperty.resolveWith((Set states) { + /// if (states.contains(WidgetState.disabled)) { + /// return SystemMouseCursors.click; + /// } + /// return SystemMouseCursors.basic; // All other states will use the default mouseCursor. + /// }), + /// ) + /// ``` + /// {@end-tool} + /// + /// If null, then [MouseCursor.defer] is used when the switch is disabled. + /// When the switch is enabled, [SystemMouseCursors.click] is used on Web, and + /// [MouseCursor.defer] is used on other platforms. + /// + /// See also: + /// + /// * [WidgetStateMouseCursor], a [MouseCursor] that implements + /// `WidgetStateProperty` which is used in APIs that need to accept + /// either a [MouseCursor] or a [WidgetStateProperty]. + final WidgetStateProperty? mouseCursor; + + /// The outline color of this [CupertinoSwitch]'s track. + /// + /// Resolved in the following states: + /// * [WidgetState.selected]. + /// * [WidgetState.hovered]. + /// * [WidgetState.focused]. + /// * [WidgetState.disabled]. + /// + /// {@tool snippet} + /// This example resolves the [trackOutlineColor] based on the current + /// [WidgetState] of the [CupertinoSwitch], providing a different [Color] when it is + /// [WidgetState.disabled]. + /// + /// ```dart + /// CupertinoSwitch( + /// value: true, + /// onChanged: (bool value) { }, + /// trackOutlineColor: WidgetStateProperty.resolveWith((Set states) { + /// if (states.contains(WidgetState.disabled)) { + /// return CupertinoColors.activeOrange.withOpacity(.48); + /// } + /// return null; // Use the default color. + /// }), + /// ) + /// ``` + /// {@end-tool} + /// + /// The [CupertinoSwitch] track has no outline by default. + final WidgetStateProperty? trackOutlineColor; + + /// The outline width of this [CupertinoSwitch]'s track. + /// + /// Resolved in the following states: + /// * [WidgetState.selected]. + /// * [WidgetState.hovered]. + /// * [WidgetState.focused]. + /// * [WidgetState.disabled]. + /// + /// {@tool snippet} + /// This example resolves the [trackOutlineWidth] based on the current + /// [WidgetState] of the [CupertinoSwitch], providing a different outline width when it is + /// [WidgetState.disabled]. + /// + /// ```dart + /// CupertinoSwitch( + /// value: true, + /// onChanged: (bool value) { }, + /// trackOutlineWidth: WidgetStateProperty.resolveWith((Set states) { + /// if (states.contains(WidgetState.disabled)) { + /// return 5.0; + /// } + /// return null; // Use the default width. + /// }), + /// ) + /// ``` + /// {@end-tool} + /// + /// Since a [CupertinoSwitch] has no track outline by default, this parameter + /// is set only if [trackOutlineColor] is provided. + /// + /// Defaults to 2.0 if a [trackOutlineColor] is provided. + final WidgetStateProperty? trackOutlineWidth; + + /// The icon to use on the thumb of this switch. + /// + /// Resolved in the following states: + /// * [WidgetState.selected]. + /// * [WidgetState.hovered]. + /// * [WidgetState.focused]. + /// * [WidgetState.disabled]. + /// + /// {@tool snippet} + /// This example resolves the [thumbIcon] based on the current + /// [WidgetState] of the [CupertinoSwitch], providing a different [Icon] when it is + /// [WidgetState.disabled]. + /// + /// ```dart + /// CupertinoSwitch( + /// value: true, + /// onChanged: (bool value) { }, + /// thumbIcon: WidgetStateProperty.resolveWith((Set states) { + /// if (states.contains(WidgetState.disabled)) { + /// return const Icon(Icons.close); + /// } + /// return null; // All other states will use the default thumbIcon. + /// }), + /// ) + /// ``` + /// {@end-tool} + /// + /// If null, then the [CupertinoSwitch] does not have any icons on the thumb. + final WidgetStateProperty? thumbIcon; + /// {@template flutter.cupertino.CupertinoSwitch.dragStartBehavior} /// Determines the way that drag start behavior is handled. /// @@ -94,7 +310,7 @@ class FormBuilderCupertinoSwitch extends FormBuilderField { super.onReset, super.focusNode, super.restorationId, - this.activeColor, + this.activeTrackColor, this.dragStartBehavior = DragStartBehavior.start, this.trackColor, this.thumbColor, @@ -103,6 +319,22 @@ class FormBuilderCupertinoSwitch extends FormBuilderField { this.helper, this.contentPadding, this.prefix, + this.focusColor, + this.inactiveThumbColor, + this.onLabelColor, + this.offLabelColor, + this.activeThumbImage, + this.onActiveThumbImageError, + this.inactiveThumbImage, + this.onInactiveThumbImageError, + this.onFocusChange, + this.autofocus = false, + this.applyTheme, + this.inactiveTrackColor, + this.mouseCursor, + this.trackOutlineColor, + this.trackOutlineWidth, + this.thumbIcon, }) : super( builder: (FormFieldState field) { final state = field as _FormBuilderCupertinoSwitchState; @@ -114,10 +346,26 @@ class FormBuilderCupertinoSwitch extends FormBuilderField { field.didChange(value); } : null, - activeColor: activeColor, dragStartBehavior: dragStartBehavior, thumbColor: thumbColor, - trackColor: trackColor, + activeTrackColor: activeTrackColor, + activeThumbImage: activeThumbImage, + inactiveThumbImage: inactiveThumbImage, + applyTheme: applyTheme, + autofocus: autofocus, + focusColor: focusColor, + focusNode: focusNode, + inactiveThumbColor: inactiveThumbColor, + inactiveTrackColor: inactiveTrackColor, + mouseCursor: mouseCursor, + onActiveThumbImageError: onActiveThumbImageError, + onInactiveThumbImageError: onInactiveThumbImageError, + offLabelColor: offLabelColor, + onLabelColor: onLabelColor, + onFocusChange: onFocusChange, + thumbIcon: thumbIcon, + trackOutlineColor: trackOutlineColor, + trackOutlineWidth: trackOutlineWidth, ); return CupertinoFormRow( error: state.hasError diff --git a/pubspec.yaml b/pubspec.yaml index 70229d2..1555eca 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -12,16 +12,16 @@ funding: - https://opencollective.com/flutter-form-builder-ecosystem environment: - sdk: '>=3.5.0 <4.0.0' - flutter: ">=3.24.0" + sdk: '>=3.6.0 <4.0.0' + flutter: ">=3.27.0" dependencies: flutter: sdk: flutter - flutter_form_builder: ^9.4.0 + flutter_form_builder: ^9.6.0 intl: ^0.19.0 dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^4.0.0 + flutter_lints: ">=5.0.0 <6.0.0"