diff --git a/AUTHORS b/AUTHORS
index 6a6707a..6c56fc7 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -5,4 +5,5 @@ Charles Crete: @cretezy
Dmitry: @kelegorm
Pedro Massango: @pedromassango
Luke Pighetti: @lukepighetti
-Jonas Zebari: @jonas-zebari
\ No newline at end of file
+Jonas Zebari: @jonas-zebari
+Ivan Semkin: @vanyasem
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 35b3ec5..b35b156 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,6 @@
+# 4.1.0
+- Bump `qr` dependency (from `^3.0.0` to `^3.0.1`).
+
# 4.0.1
- Bump `qr` dependency (from `^2.0.0` to `^3.0.0`).
- **BREAKING**: Rename `QrImage` to `QrImageView`
diff --git a/README.md b/README.md
index 3c8f84b..49869e1 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,7 @@ You should add the following to your `pubspec.yaml` file:
```yaml
dependencies:
- qr_flutter: ^4.0.0
+ qr_flutter: ^4.1.0
```
**Note**: If you're using the Flutter `master` channel, if you encounter build issues, or want to try the latest and greatest then you should use the `master` branch and not a specific release version. To do so, use the following configuration in your `pubspec.yaml`:
@@ -37,7 +37,7 @@ dependencies:
dependencies:
qr_flutter:
git:
- url: git://github.com/lukef/qr.flutter.git
+ url: https://github.com/theyakka/qr.flutter.git
```
Keep in mind the `master` branch could be unstable.
@@ -55,8 +55,8 @@ import 'package:qr_flutter/qr_flutter.dart';
Next, to render a basic QR code you can use the following code (or something like it):
```dart
-QrImage(
- data: "1234567890",
+QrImageView(
+ data: '1234567890',
version: QrVersions.auto,
size: 200.0,
),
@@ -64,21 +64,22 @@ QrImage(
Depending on your data requirements you may want to tweak the QR code output. The following options are available:
-| Property | Type | Description |
-|----|----|----|
-| `version` | int | `QrVersions.auto` or a value between 1 and 40. See http://www.qrcode.com/en/about/version.html for limitations and details. |
-| `errorCorrectionLevel` | int | A value defined on `QrErrorCorrectLevel`. e.g.: `QrErrorCorrectLevel.L`. |
-| `size` | double | The (square) size of the image. If not given, will auto size using shortest size constraint. |
-| `padding` | EdgeInsets | Padding surrounding the QR code data. |
-| `backgroundColor` | Color | The background color (default is none). |
-| `foregroundColor` | Color | The foreground color (default is black). |
-| `gapless` | bool | Adds an extra pixel in size to prevent gaps (default is true). |
-| `errorStateBuilder` | QrErrorBuilder | Allows you to show an error state `Widget` in the event there is an error rendering the QR code (e.g.: version is too low, input is too long, etc). |
-| `constrainErrorBounds` | bool | If true, the error `Widget` will be constrained to the square that the QR code was going to be drawn in. If false, the error state `Widget` will grow/shrink to whatever size it needs. |
-| `embeddedImage` | ImageProvider | An `ImageProvider` that defines an image to be overlaid in the center of the QR code. |
-| `embeddedImageStyle` | QrEmbeddedImageStyle | Properties to style the embedded image. |
-| `embeddedImageEmitsError` | bool | If true, any failure to load the embedded image will trigger the `errorStateBuilder` or render an empty `Container`. If false, the QR code will be rendered and the embedded image will be ignored. |
-|`semanticsLabel`|String|`semanticsLabel` will be used by screen readers to describe the content of the QR code.|
+| Property | Type | Description |
+|---------------------------|----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `version` | int | `QrVersions.auto` or a value between 1 and 40. See http://www.qrcode.com/en/about/version.html for limitations and details. |
+| `errorCorrectionLevel` | int | A value defined on `QrErrorCorrectLevel`. e.g.: `QrErrorCorrectLevel.L`. |
+| `size` | double | The (square) size of the image. If not given, will auto size using shortest size constraint. |
+| `padding` | EdgeInsets | Padding surrounding the QR code data. |
+| `backgroundColor` | Color | The background color (default is none). |
+| `eyeStyle` | QrEyeStyle | Configures the QR code eyes' (corners') shape and color. |
+| `dataModuleStyle` | QrDataModuleStyle | Configures the shape and the color of the dots. |
+| `gapless` | bool | Adds an extra pixel in size to prevent gaps (default is true). |
+| `errorStateBuilder` | QrErrorBuilder | Allows you to show an error state `Widget` in the event there is an error rendering the QR code (e.g.: version is too low, input is too long, etc). |
+| `constrainErrorBounds` | bool | If true, the error `Widget` will be constrained to the square that the QR code was going to be drawn in. If false, the error state `Widget` will grow/shrink to whatever size it needs. |
+| `embeddedImage` | ImageProvider | An `ImageProvider` that defines an image to be overlaid in the center of the QR code. |
+| `embeddedImageStyle` | QrEmbeddedImageStyle | Properties to style the embedded image. |
+| `embeddedImageEmitsError` | bool | If true, any failure to load the embedded image will trigger the `errorStateBuilder` or render an empty `Container`. If false, the QR code will be rendered and the embedded image will be ignored. |
+| `semanticsLabel` | String | `semanticsLabel` will be used by screen readers to describe the content of the QR code. |
# Examples
@@ -90,7 +91,7 @@ Also, the following examples give you a quick overview on how to use the library
A basic QR code will look something like:
```dart
-QrImage(
+QrImageView(
data: 'This is a simple QR code',
version: QrVersions.auto,
size: 320,
@@ -101,7 +102,7 @@ QrImage(
A QR code with an image (from your application's assets) will look like:
```dart
-QrImage(
+QrImageView(
data: 'This QR code has an embedded image as well',
version: QrVersions.auto,
size: 320,
@@ -116,7 +117,7 @@ QrImage(
To show an error state in the event that the QR code can't be validated:
```dart
-QrImage(
+QrImageView(
data: 'This QR code will show the error state instead',
version: 1,
size: 320,
@@ -125,7 +126,7 @@ QrImage(
return Container(
child: Center(
child: Text(
- "Uh oh! Something went wrong...",
+ 'Uh oh! Something went wrong...',
textAlign: TextAlign.center,
),
),
@@ -134,13 +135,6 @@ QrImage(
)
```
-
-# FAQ
-## Has it been tested in production? Can I use it in production?
-
-Yep! It's stable and ready to rock. It's currently in use in quite a few production applications including:
-- Sixpoint: [Android](https://play.google.com/store/apps/details?id=com.sixpoint.sixpoint&hl=en_US) & [iOS](https://itunes.apple.com/us/app/sixpoint/id663008674?mt=8)
-
# Outro
## Credits
Thanks to Kevin Moore for his awesome [QR - Dart](https://github.com/kevmoo/qr.dart) library. It's the core of this library.
diff --git a/analysis_options.yaml b/analysis_options.yaml
index 82b26a2..2607df3 100644
--- a/analysis_options.yaml
+++ b/analysis_options.yaml
@@ -80,7 +80,6 @@ linter:
# libraries
# classes
- one_member_abstracts # avoid
- - avoid_classes_with_only_static_members # avoid
- public_member_api_docs
# constructors
- prefer_constructors_over_static_methods
diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle
index 6ca16fd..eb3501b 100644
--- a/example/android/app/build.gradle
+++ b/example/android/app/build.gradle
@@ -26,7 +26,16 @@ apply plugin: 'kotlin-android'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
- compileSdkVersion 33
+ compileSdkVersion flutter.compileSdkVersion
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ kotlinOptions {
+ jvmTarget = '1.8'
+ }
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
@@ -39,7 +48,7 @@ android {
defaultConfig {
applicationId "app.yakka.example"
minSdkVersion 16
- targetSdkVersion 33
+ targetSdkVersion flutter.targetSdkVersion
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
@@ -59,7 +68,7 @@ flutter {
}
dependencies {
- implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test:runner:1.3.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
diff --git a/example/android/app/src/debug/AndroidManifest.xml b/example/android/app/src/debug/AndroidManifest.xml
index 654eca8..6b107e9 100644
--- a/example/android/app/src/debug/AndroidManifest.xml
+++ b/example/android/app/src/debug/AndroidManifest.xml
@@ -1,6 +1,7 @@
-
diff --git a/example/android/app/src/main/AndroidManifest.xml b/example/android/app/src/main/AndroidManifest.xml
index 16aa498..bae8b78 100644
--- a/example/android/app/src/main/AndroidManifest.xml
+++ b/example/android/app/src/main/AndroidManifest.xml
@@ -8,21 +8,16 @@
FlutterApplication and put your custom class here. -->
-
-
+
+
diff --git a/example/android/app/src/main/res/values/styles.xml b/example/android/app/src/main/res/values/styles.xml
index cd32859..c745a5e 100644
--- a/example/android/app/src/main/res/values/styles.xml
+++ b/example/android/app/src/main/res/values/styles.xml
@@ -8,5 +8,4 @@
-
diff --git a/example/android/app/src/profile/AndroidManifest.xml b/example/android/app/src/profile/AndroidManifest.xml
index 654eca8..6b107e9 100644
--- a/example/android/app/src/profile/AndroidManifest.xml
+++ b/example/android/app/src/profile/AndroidManifest.xml
@@ -1,6 +1,7 @@
-
diff --git a/example/android/build.gradle b/example/android/build.gradle
index 9816430..29a8f72 100644
--- a/example/android/build.gradle
+++ b/example/android/build.gradle
@@ -1,20 +1,23 @@
buildscript {
- ext.kotlin_version = '1.6.21'
+ ext {
+ buildGradleVersion = '7.4.2'
+ kotlinVersion = '1.7.21'
+ }
repositories {
google()
- jcenter()
+ mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:4.1.2'
- classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
+ classpath "com.android.tools.build:gradle:$buildGradleVersion"
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
}
}
allprojects {
repositories {
google()
- jcenter()
+ mavenCentral()
}
}
diff --git a/example/android/gradle/wrapper/gradle-wrapper.properties b/example/android/gradle/wrapper/gradle-wrapper.properties
index 734b469..3c472b9 100644
--- a/example/android/gradle/wrapper/gradle-wrapper.properties
+++ b/example/android/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,5 @@
-#Sun Mar 14 10:07:12 PDT 2021
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
diff --git a/example/android/settings.gradle b/example/android/settings.gradle
index 5a2f14f..44e62bc 100644
--- a/example/android/settings.gradle
+++ b/example/android/settings.gradle
@@ -1,15 +1,11 @@
include ':app'
-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"
diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist
index 6b4c0f7..4f8d4d2 100644
--- a/example/ios/Flutter/AppFrameworkInfo.plist
+++ b/example/ios/Flutter/AppFrameworkInfo.plist
@@ -21,6 +21,6 @@
CFBundleVersion
1.0
MinimumOSVersion
- 8.0
+ 11.0
diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj
index d96dd44..6802989 100644
--- a/example/ios/Runner.xcodeproj/project.pbxproj
+++ b/example/ios/Runner.xcodeproj/project.pbxproj
@@ -3,17 +3,13 @@
archiveVersion = 1;
classes = {
};
- objectVersion = 46;
+ objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
- 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
- 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
- 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
- 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
@@ -27,8 +23,6 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
- 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
- 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
@@ -39,13 +33,11 @@
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; };
- 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; };
- 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; };
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
@@ -58,8 +50,6 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
- 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
- 3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -69,9 +59,7 @@
9740EEB11CF90186004384FC /* Flutter */ = {
isa = PBXGroup;
children = (
- 3B80C3931E831B6300D905FE /* App.framework */,
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
- 9740EEBA1CF902C7004384FC /* Flutter.framework */,
9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */,
@@ -148,7 +136,7 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 1020;
+ LastUpgradeCheck = 1300;
ORGANIZATIONNAME = "The Chromium Authors";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
@@ -193,6 +181,7 @@
/* Begin PBXShellScriptBuildPhase section */
3B06AD1E1E4923F5004D2608 /* Thin Binary */ = {
isa = PBXShellScriptBuildPhase;
+ alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
@@ -203,10 +192,11 @@
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
- shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
+ shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
};
9740EEB61CF901F6004384FC /* Run Script */ = {
isa = PBXShellScriptBuildPhase;
+ alwaysOutOfDate = 1;
buildActionMask = 2147483647;
files = (
);
@@ -255,7 +245,6 @@
/* Begin XCBuildConfiguration section */
249021D3217E4FDB00AE95B9 /* Profile */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
@@ -295,7 +284,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
@@ -331,7 +320,6 @@
};
97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
@@ -377,7 +365,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -387,7 +375,6 @@
};
97C147041CF9000F007C117D /* Release */ = {
isa = XCBuildConfiguration;
- baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
@@ -427,7 +414,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
diff --git a/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
index 1d526a1..919434a 100644
--- a/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
+++ b/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -2,6 +2,6 @@
+ location = "self:">
diff --git a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
index a28140c..3db53b6 100644
--- a/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+++ b/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -1,6 +1,6 @@
UIViewControllerBasedStatusBarAppearance
+ CADisableMinimumFrameDurationOnPhone
+
+ UIApplicationSupportsIndirectInputEvents
+
diff --git a/example/lib/main.dart b/example/lib/main.dart
index df0c819..f0305a2 100644
--- a/example/lib/main.dart
+++ b/example/lib/main.dart
@@ -16,12 +16,14 @@ class ExampleApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
- SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
- statusBarColor: Colors.white,
- statusBarIconBrightness: Brightness.dark,
- systemNavigationBarColor: Colors.white,
- systemNavigationBarIconBrightness: Brightness.dark,
- ));
+ SystemChrome.setSystemUIOverlayStyle(
+ const SystemUiOverlayStyle(
+ statusBarColor: Colors.white,
+ statusBarIconBrightness: Brightness.dark,
+ systemNavigationBarColor: Colors.white,
+ systemNavigationBarIconBrightness: Brightness.dark,
+ ),
+ );
return MaterialApp(
title: 'QR.Flutter',
theme: ThemeData.light(),
diff --git a/example/lib/main_screen.dart b/example/lib/main_screen.dart
index 38c67bb..c744be7 100644
--- a/example/lib/main_screen.dart
+++ b/example/lib/main_screen.dart
@@ -10,13 +10,13 @@ import 'package:qr_flutter/qr_flutter.dart';
/// This is the screen that you'll see when the app starts
class MainScreen extends StatefulWidget {
@override
- _MainScreenState createState() => _MainScreenState();
+ State createState() => _MainScreenState();
}
class _MainScreenState extends State {
@override
Widget build(BuildContext context) {
- final message =
+ const String message =
// ignore: lines_longer_than_80_chars
'Hey this is a QR code. Change this value in the main_screen.dart file.';
diff --git a/example/pubspec.yaml b/example/pubspec.yaml
index 9c94669..22cc746 100644
--- a/example/pubspec.yaml
+++ b/example/pubspec.yaml
@@ -2,13 +2,12 @@ name: example
description: >
The QR.Flutter example app.
version: 2.0.0
-author: Yakka, LLC
homepage: https://github.com/lukef/qr.flutter
publish_to: none
environment:
- sdk: ">=2.12.0 <3.0.0"
- flutter: ">=1.7.0"
+ sdk: '>=2.19.6 <3.0.0'
+ flutter: ">=3.7.0"
dependencies:
flutter:
diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart
deleted file mode 100644
index 2a9f3b2..0000000
--- a/example/test/widget_test.dart
+++ /dev/null
@@ -1,29 +0,0 @@
-// This is a basic Flutter widget test.
-//
-// To perform an interaction with a widget in your test, use the WidgetTester
-// utility that Flutter provides. For example, you can send tap and scroll
-// gestures. You can also use WidgetTester to find child widgets in the widget
-// tree, read text, and verify that the values of widget properties are correct.
-
-import 'package:example/main.dart';
-import 'package:flutter/material.dart';
-import 'package:flutter_test/flutter_test.dart';
-
-void main() {
- testWidgets('Counter increments smoke test', (tester) async {
- // Build our app and trigger a frame.
- await tester.pumpWidget(ExampleApp());
-
- // Verify that our counter starts at 0.
- expect(find.text('0'), findsOneWidget);
- expect(find.text('1'), findsNothing);
-
- // Tap the '+' icon and trigger a frame.
- await tester.tap(find.byIcon(Icons.add));
- await tester.pump();
-
- // Verify that our counter has incremented.
- expect(find.text('0'), findsNothing);
- expect(find.text('1'), findsOneWidget);
- });
-}
diff --git a/lib/src/paint_cache.dart b/lib/src/paint_cache.dart
index 6a23e4c..ead3df3 100644
--- a/lib/src/paint_cache.dart
+++ b/lib/src/paint_cache.dart
@@ -8,19 +8,23 @@ import 'package:flutter/widgets.dart';
import 'types.dart';
-///
+/// Caches painter objects so we do have to recreate them and waste expensive
+/// cycles.
class PaintCache {
final List _pixelPaints = [];
final Map _keyedPaints = {};
String _cacheKey(QrCodeElement element, {FinderPatternPosition? position}) {
final posKey = position != null ? position.toString() : 'any';
- return '${element.toString()}:$posKey';
+ return '$element:$posKey';
}
/// Save a [Paint] for the provided element and position into the cache.
- void cache(Paint paint, QrCodeElement element,
- {FinderPatternPosition? position}) {
+ void cache(
+ Paint paint,
+ QrCodeElement element, {
+ FinderPatternPosition? position,
+ }) {
if (element == QrCodeElement.codePixel) {
_pixelPaints.add(paint);
} else {
@@ -31,23 +35,21 @@ class PaintCache {
/// Retrieve the first [Paint] object from the paint cache for the provided
/// element and position.
Paint? firstPaint(QrCodeElement element, {FinderPatternPosition? position}) {
- if (element == QrCodeElement.codePixel) {
- return _pixelPaints.first;
- } else {
- return _keyedPaints[_cacheKey(element, position: position)];
- }
+ return element == QrCodeElement.codePixel
+ ? _pixelPaints.first
+ : _keyedPaints[_cacheKey(element, position: position)];
}
/// Retrieve all [Paint] objects from the paint cache for the provided
/// element and position. Note: Finder pattern elements can only have a max
/// one [Paint] object per position. As such they will always return a [List]
/// with a fixed size of `1`.
- List paints(QrCodeElement element,
- {FinderPatternPosition? position}) {
- if (element == QrCodeElement.codePixel) {
- return _pixelPaints;
- } else {
- return [_keyedPaints[_cacheKey(element, position: position)]];
- }
+ List paints(
+ QrCodeElement element, {
+ FinderPatternPosition? position,
+ }) {
+ return element == QrCodeElement.codePixel
+ ? _pixelPaints
+ : [_keyedPaints[_cacheKey(element, position: position)]];
}
}
diff --git a/lib/src/qr_image_view.dart b/lib/src/qr_image_view.dart
index 239d552..357d6ca 100644
--- a/lib/src/qr_image_view.dart
+++ b/lib/src/qr_image_view.dart
@@ -21,10 +21,11 @@ class QrImageView extends StatefulWidget {
/// using the default options).
QrImageView({
required String data,
- Key? key,
+ super.key,
this.size,
this.padding = const EdgeInsets.all(10.0),
this.backgroundColor = Colors.transparent,
+ @Deprecated('use colors in eyeStyle and dataModuleStyle instead')
this.foregroundColor = Colors.black,
this.version = QrVersions.auto,
this.errorCorrectionLevel = QrErrorCorrectLevel.L,
@@ -42,19 +43,22 @@ class QrImageView extends StatefulWidget {
),
this.embeddedImageEmitsError = false,
this.gradient,
- }) : assert(QrVersions.isSupportedVersion(version)),
+ }) : assert(
+ QrVersions.isSupportedVersion(version),
+ 'QR code version $version is not supported',
+ ),
_data = data,
- _qrCode = null,
- super(key: key);
+ _qrCode = null;
/// Create a new QR code using the [QrCode] data and the passed options (or
/// using the default options).
QrImageView.withQr({
required QrCode qr,
- Key? key,
+ super.key,
this.size,
this.padding = const EdgeInsets.all(10.0),
this.backgroundColor = Colors.transparent,
+ @Deprecated('use colors in eyeStyle and dataModuleStyle instead')
this.foregroundColor = Colors.black,
this.version = QrVersions.auto,
this.errorCorrectionLevel = QrErrorCorrectLevel.L,
@@ -74,13 +78,16 @@ class QrImageView extends StatefulWidget {
),
this.embeddedImageEmitsError = false,
this.gradient,
- }) : assert(QrVersions.isSupportedVersion(version)),
+ }) : assert(
+ QrVersions.isSupportedVersion(version),
+ 'QR code version $version is not supported',
+ ),
_data = null,
- _qrCode = qr,
- super(key: key);
+ _qrCode = qr;
// The data passed to the widget
final String? _data;
+
// The QR code data passed to the widget
final QrCode? _qrCode;
@@ -149,7 +156,7 @@ class QrImageView extends StatefulWidget {
final QrDataModuleStyle dataModuleStyle;
@override
- _QrImageViewState createState() => _QrImageViewState();
+ State createState() => _QrImageViewState();
}
class _QrImageViewState extends State {
@@ -167,55 +174,53 @@ class _QrImageViewState extends State {
version: widget.version,
errorCorrectionLevel: widget.errorCorrectionLevel,
);
- if (_validationResult.isValid) {
- _qr = _validationResult.qrCode;
- } else {
- _qr = null;
- }
+ _qr = _validationResult.isValid ? _validationResult.qrCode : null;
} else if (widget._qrCode != null) {
_qr = widget._qrCode;
_validationResult =
QrValidationResult(status: QrValidationStatus.valid, qrCode: _qr);
}
- return LayoutBuilder(builder: (context, constraints) {
- // validation failed, show an error state widget if builder is present.
- if (!_validationResult.isValid) {
- return _errorWidget(context, constraints, _validationResult.error);
- }
- // no error, build the regular widget
- final widgetSize = widget.size ?? constraints.biggest.shortestSide;
- if (widget.embeddedImage != null) {
- // if requesting to embed an image then we need to load via a
- // FutureBuilder because the image provider will be async.
- return FutureBuilder(
- future: _loadQrImage(context, widget.embeddedImageStyle),
- builder: (ctx, snapshot) {
- if (snapshot.error != null) {
- print("snapshot error: ${snapshot.error}");
- if (widget.embeddedImageEmitsError) {
- return _errorWidget(context, constraints, snapshot.error);
- } else {
- return _qrWidget(context, null, widgetSize);
+ return LayoutBuilder(
+ builder: (context, constraints) {
+ // validation failed, show an error state widget if builder is present.
+ if (!_validationResult.isValid) {
+ return _errorWidget(context, constraints, _validationResult.error);
+ }
+ // no error, build the regular widget
+ final widgetSize =
+ widget.size ?? constraints.biggest.shortestSide;
+ if (widget.embeddedImage != null) {
+ // if requesting to embed an image then we need to load via a
+ // FutureBuilder because the image provider will be async.
+ return FutureBuilder(
+ future: _loadQrImage(context, widget.embeddedImageStyle),
+ builder: (ctx, snapshot) {
+ if (snapshot.error != null) {
+ debugPrint('snapshot error: ${snapshot.error}');
+ return widget.embeddedImageEmitsError
+ ? _errorWidget(context, constraints, snapshot.error)
+ : _qrWidget(null, widgetSize);
}
- }
- if (snapshot.hasData) {
- print('loaded image');
- final loadedImage = snapshot.data;
- return _qrWidget(context, loadedImage, widgetSize);
- } else {
- return Container();
- }
- },
- );
- } else {
- return _qrWidget(context, null, widgetSize);
- }
- });
+ if (snapshot.hasData) {
+ debugPrint('loaded image');
+ final loadedImage = snapshot.data;
+ return _qrWidget(loadedImage, widgetSize);
+ } else {
+ return Container();
+ }
+ },
+ );
+ } else {
+ return _qrWidget(null, widgetSize);
+ }
+ },
+ );
}
- Widget _qrWidget(BuildContext context, ui.Image? image, double edgeLength) {
+ Widget _qrWidget(ui.Image? image, double edgeLength) {
final painter = QrPainter.withQr(
qr: _qr!,
+ // ignore: deprecated_member_use_from_same_package
color: widget.foregroundColor,
gapless: widget.gapless,
embeddedImageStyle: widget.embeddedImageStyle,
@@ -234,40 +239,51 @@ class _QrImageViewState extends State {
}
Widget _errorWidget(
- BuildContext context, BoxConstraints constraints, Object? error) {
+ BuildContext context,
+ BoxConstraints constraints,
+ Object? error,
+ ) {
final errorWidget = widget.errorStateBuilder == null
? Container()
: widget.errorStateBuilder!(context, error);
- final errorSideLength = (widget.constrainErrorBounds
+ final errorSideLength = widget.constrainErrorBounds
? widget.size ?? constraints.biggest.shortestSide
- : constraints.biggest.longestSide);
+ : constraints.biggest.longestSide;
return _QrContentView(
edgeLength: errorSideLength,
backgroundColor: widget.backgroundColor,
padding: widget.padding,
- child: errorWidget,
semanticsLabel: widget.semanticsLabel,
+ child: errorWidget,
);
}
late ImageStreamListener streamListener;
+
Future _loadQrImage(
- BuildContext buildContext, QrEmbeddedImageStyle? style) async {
+ BuildContext buildContext,
+ QrEmbeddedImageStyle? style,
+ ) {
if (style != null) {}
final mq = MediaQuery.of(buildContext);
final completer = Completer();
- final stream = widget.embeddedImage!.resolve(ImageConfiguration(
- devicePixelRatio: mq.devicePixelRatio,
- ));
+ final stream = widget.embeddedImage!.resolve(
+ ImageConfiguration(
+ devicePixelRatio: mq.devicePixelRatio,
+ ),
+ );
- streamListener = ImageStreamListener((info, err) {
- stream.removeListener(streamListener);
- completer.complete(info.image);
- }, onError: (dynamic err, _) {
- stream.removeListener(streamListener);
- completer.completeError(err);
- });
+ streamListener = ImageStreamListener(
+ (info, err) {
+ stream.removeListener(streamListener);
+ completer.complete(info.image);
+ },
+ onError: (err, _) {
+ stream.removeListener(streamListener);
+ completer.completeError(err);
+ },
+ );
stream.addListener(streamListener);
return completer.future;
}
@@ -278,7 +294,7 @@ class _QrImageViewState extends State {
typedef QrErrorBuilder = Widget Function(BuildContext context, Object? error);
class _QrContentView extends StatelessWidget {
- _QrContentView({
+ const _QrContentView({
required this.edgeLength,
required this.child,
this.backgroundColor,
diff --git a/lib/src/qr_painter.dart b/lib/src/qr_painter.dart
index 3168c9a..e773c57 100644
--- a/lib/src/qr_painter.dart
+++ b/lib/src/qr_painter.dart
@@ -19,7 +19,7 @@ import 'validator.dart';
// ignore_for_file: deprecated_member_use_from_same_package
-const _finderPatternLimit = 7;
+const int _finderPatternLimit = 7;
// default colors for the qr code pixels
const Color _qrDefaultColor = Color(0xff000000);
@@ -32,7 +32,11 @@ class QrPainter extends CustomPainter {
required String data,
required this.version,
this.errorCorrectionLevel = QrErrorCorrectLevel.L,
+ @Deprecated('use colors in eyeStyle and dataModuleStyle instead')
this.color = _qrDefaultColor,
+ @Deprecated(
+ 'You should use the background color value of your container widget',
+ )
this.emptyColor = _qrDefaultEmptyColor,
this.gapless = false,
this.embeddedImage,
@@ -40,7 +44,10 @@ class QrPainter extends CustomPainter {
this.eyeStyle = const QrEyeStyle(),
this.dataModuleStyle = const QrDataModuleStyle(),
this.gradient,
- }) : assert(QrVersions.isSupportedVersion(version)) {
+ }) : assert(
+ QrVersions.isSupportedVersion(version),
+ 'QR code version $version is not supported',
+ ) {
_init(data);
}
@@ -49,7 +56,11 @@ class QrPainter extends CustomPainter {
/// flow or for when you need to pre-validate the QR data.
QrPainter.withQr({
required QrCode qr,
+ @Deprecated('use colors in eyeStyle and dataModuleStyle instead')
this.color = _qrDefaultColor,
+ @Deprecated(
+ 'You should use the background color value of your container widget',
+ )
this.emptyColor = _qrDefaultEmptyColor,
this.gapless = false,
this.embeddedImage,
@@ -112,7 +123,7 @@ class QrPainter extends CustomPainter {
final double _gapSize = 0.25;
/// Cache for all of the [Paint] objects.
- final _paintCache = PaintCache();
+ final PaintCache _paintCache = PaintCache();
void _init(String data) {
if (!QrVersions.isSupportedVersion(version)) {
@@ -138,23 +149,33 @@ class QrPainter extends CustomPainter {
// Cache the pixel paint object. For now there is only one but we might
// expand it to multiple later (e.g.: different colours).
_paintCache.cache(
- Paint()..style = PaintingStyle.fill, QrCodeElement.codePixel);
+ Paint()..style = PaintingStyle.fill,
+ QrCodeElement.codePixel,
+ );
// Cache the empty pixel paint object. Empty color is deprecated and will go
// away.
_paintCache.cache(
- Paint()..style = PaintingStyle.fill, QrCodeElement.codePixelEmpty);
+ Paint()..style = PaintingStyle.fill,
+ QrCodeElement.codePixelEmpty,
+ );
// Cache the finder pattern painters. We'll keep one for each one in case
// we want to provide customization options later.
for (final position in FinderPatternPosition.values) {
- _paintCache.cache(Paint()..style = PaintingStyle.stroke,
- QrCodeElement.finderPatternOuter,
- position: position);
- _paintCache.cache(Paint()..style = PaintingStyle.stroke,
- QrCodeElement.finderPatternInner,
- position: position);
_paintCache.cache(
- Paint()..style = PaintingStyle.fill, QrCodeElement.finderPatternDot,
- position: position);
+ Paint()..style = PaintingStyle.stroke,
+ QrCodeElement.finderPatternOuter,
+ position: position,
+ );
+ _paintCache.cache(
+ Paint()..style = PaintingStyle.stroke,
+ QrCodeElement.finderPatternInner,
+ position: position,
+ );
+ _paintCache.cache(
+ Paint()..style = PaintingStyle.fill,
+ QrCodeElement.finderPatternDot,
+ position: position,
+ );
}
}
@@ -162,23 +183,34 @@ class QrPainter extends CustomPainter {
void paint(Canvas canvas, Size size) {
// if the widget has a zero size side then we cannot continue painting.
if (size.shortestSide == 0) {
- print("[QR] WARN: width or height is zero. You should set a 'size' value "
- "or nest this painter in a Widget that defines a non-zero size");
+ debugPrint(
+ "[QR] WARN: width or height is zero. You should set a 'size' value "
+ 'or nest this painter in a Widget that defines a non-zero size');
return;
}
final paintMetrics = _PaintMetrics(
containerSize: size.shortestSide,
moduleCount: _qr!.moduleCount,
- gapSize: (gapless ? 0 : _gapSize),
+ gapSize: gapless ? 0 : _gapSize,
);
// draw the finder pattern elements
- _drawFinderPatternItem(FinderPatternPosition.topLeft, canvas, paintMetrics);
_drawFinderPatternItem(
- FinderPatternPosition.bottomLeft, canvas, paintMetrics);
+ FinderPatternPosition.topLeft,
+ canvas,
+ paintMetrics,
+ );
_drawFinderPatternItem(
- FinderPatternPosition.topRight, canvas, paintMetrics);
+ FinderPatternPosition.bottomLeft,
+ canvas,
+ paintMetrics,
+ );
+ _drawFinderPatternItem(
+ FinderPatternPosition.topRight,
+ canvas,
+ paintMetrics,
+ );
// DEBUG: draw the inner content boundary
// final paint = Paint()..style = ui.PaintingStyle.stroke;
@@ -271,10 +303,14 @@ class QrPainter extends CustomPainter {
for (var x = 0; x < _qr!.moduleCount; x++) {
for (var y = 0; y < _qr!.moduleCount; y++) {
// draw the finder patterns independently
- if (_isFinderPatternPosition(x, y)) continue;
+ if (_isFinderPatternPosition(x, y)) {
+ continue;
+ }
final isDark = _qrImage.isDark(y, x);
final paint = isDark ? pixelPaint : emptyPixelPaint;
- if (!isDark && !isRoundedOutsideCorners) continue;
+ if (!isDark && !isRoundedOutsideCorners) {
+ continue;
+ }
// paint a pixel
final squareRect = _createDataModuleRect(paintMetrics, x, y, gap);
// check safeArea
@@ -422,21 +458,25 @@ class QrPainter extends CustomPainter {
}
bool _hasAdjacentVerticalPixel(int x, int y, int moduleCount) {
- if (y + 1 >= moduleCount) return false;
+ if (y + 1 >= moduleCount) {
+ return false;
+ }
return _qrImage.isDark(y + 1, x);
}
bool _hasAdjacentHorizontalPixel(int x, int y, int moduleCount) {
- if (x + 1 >= moduleCount) return false;
+ if (x + 1 >= moduleCount) {
+ return false;
+ }
return _qrImage.isDark(y, x + 1);
}
bool _isFinderPatternPosition(int x, int y) {
- final isTopLeft = (y < _finderPatternLimit && x < _finderPatternLimit);
- final isBottomLeft = (y < _finderPatternLimit &&
- (x >= _qr!.moduleCount - _finderPatternLimit));
- final isTopRight = (y >= _qr!.moduleCount - _finderPatternLimit &&
- (x < _finderPatternLimit));
+ final isTopLeft = y < _finderPatternLimit && x < _finderPatternLimit;
+ final isBottomLeft = y < _finderPatternLimit &&
+ (x >= _qr!.moduleCount - _finderPatternLimit);
+ final isTopRight = y >= _qr!.moduleCount - _finderPatternLimit &&
+ (x < _finderPatternLimit);
return isTopLeft || isBottomLeft || isTopRight;
}
@@ -446,9 +486,10 @@ class QrPainter extends CustomPainter {
_PaintMetrics metrics,
) {
final totalGap = (_finderPatternLimit - 1) * metrics.gapSize;
- final radius = ((_finderPatternLimit * metrics.pixelSize) + totalGap) -
- metrics.pixelSize;
- final strokeAdjust = (metrics.pixelSize / 2.0);
+ final radius =
+ ((_finderPatternLimit * metrics.pixelSize) + totalGap) -
+ metrics.pixelSize;
+ final strokeAdjust = metrics.pixelSize / 2.0;
final edgePos =
(metrics.inset + metrics.innerContentSize) - (radius + strokeAdjust);
@@ -463,31 +504,44 @@ class QrPainter extends CustomPainter {
}
// configure the paints
- final outerPaint = _paintCache.firstPaint(QrCodeElement.finderPatternOuter,
- position: position)!;
+ final outerPaint = _paintCache.firstPaint(
+ QrCodeElement.finderPatternOuter,
+ position: position,
+ )!;
final color = _priorityColor(eyeStyle.color);
outerPaint.strokeWidth = metrics.pixelSize;
outerPaint.color = color;
- final innerPaint = _paintCache.firstPaint(QrCodeElement.finderPatternInner,
- position: position)!;
+ final innerPaint = _paintCache
+ .firstPaint(QrCodeElement.finderPatternInner, position: position)!;
innerPaint.strokeWidth = metrics.pixelSize;
innerPaint.color = emptyColor;
- final dotPaint = _paintCache.firstPaint(QrCodeElement.finderPatternDot,
- position: position);
+ final dotPaint = _paintCache.firstPaint(
+ QrCodeElement.finderPatternDot,
+ position: position,
+ );
dotPaint!.color = color;
- final outerRect = Rect.fromLTWH(offset.dx, offset.dy, radius, radius);
+ final outerRect =
+ Rect.fromLTWH(offset.dx, offset.dy, radius, radius);
final innerRadius = radius - (2 * metrics.pixelSize);
- final innerRect = Rect.fromLTWH(offset.dx + metrics.pixelSize,
- offset.dy + metrics.pixelSize, innerRadius, innerRadius);
+ final innerRect = Rect.fromLTWH(
+ offset.dx + metrics.pixelSize,
+ offset.dy + metrics.pixelSize,
+ innerRadius,
+ innerRadius,
+ );
final gap = metrics.pixelSize * 2;
final dotSize = radius - gap - (2 * strokeAdjust);
- final dotRect = Rect.fromLTWH(offset.dx + metrics.pixelSize + strokeAdjust,
- offset.dy + metrics.pixelSize + strokeAdjust, dotSize, dotSize);
+ final dotRect = Rect.fromLTWH(
+ offset.dx + metrics.pixelSize + strokeAdjust,
+ offset.dy + metrics.pixelSize + strokeAdjust,
+ dotSize,
+ dotSize,
+ );
switch(eyeStyle.eyeShape) {
case QrEyeShape.square:
@@ -524,7 +578,10 @@ class QrPainter extends CustomPainter {
bool _hasOneNonZeroSide(Size size) => size.longestSide > 0;
Size _scaledAspectSize(
- Size widgetSize, Size originalSize, Size? requestedSize) {
+ Size widgetSize,
+ Size originalSize,
+ Size? requestedSize,
+ ) {
if (requestedSize != null && !requestedSize.isEmpty) {
return requestedSize;
} else if (requestedSize != null && _hasOneNonZeroSide(requestedSize)) {
@@ -539,7 +596,11 @@ class QrPainter extends CustomPainter {
}
void _drawImageOverlay(
- Canvas canvas, Offset position, Size size, QrEmbeddedImageStyle? style) {
+ Canvas canvas,
+ Offset position,
+ Size size,
+ QrEmbeddedImageStyle? style,
+ ) {
final paint = Paint()
..isAntiAlias = true
..filterQuality = FilterQuality.high;
@@ -587,24 +648,26 @@ class QrPainter extends CustomPainter {
}
/// Returns the raw QR code [ui.Image] object.
- Future toImage(double size,
- {ui.ImageByteFormat format = ui.ImageByteFormat.png}) async {
- return await toPicture(size).toImage(size.toInt(), size.toInt());
+ Future toImage(double size) {
+ return toPicture(size).toImage(size.toInt(), size.toInt());
}
/// Returns the raw QR code image byte data.
- Future toImageData(double size,
- {ui.ImageByteFormat format = ui.ImageByteFormat.png}) async {
- final image = await toImage(size, format: format);
+ Future toImageData(
+ double size, {
+ ui.ImageByteFormat format = ui.ImageByteFormat.png,
+ }) async {
+ final image = await toImage(size);
return image.toByteData(format: format);
}
}
class _PaintMetrics {
- _PaintMetrics(
- {required this.containerSize,
- required this.gapSize,
- required this.moduleCount}) {
+ _PaintMetrics({
+ required this.containerSize,
+ required this.gapSize,
+ required this.moduleCount,
+ }) {
_calculateMetrics();
}
@@ -623,7 +686,7 @@ class _PaintMetrics {
void _calculateMetrics() {
final gapTotal = (moduleCount - 1) * gapSize;
- var pixelSize = (containerSize - gapTotal) / moduleCount;
+ final pixelSize = (containerSize - gapTotal) / moduleCount;
_pixelSize = (pixelSize * 2).roundToDouble() / 2;
_innerContentSize = (_pixelSize * moduleCount) + gapTotal;
_inset = (containerSize - _innerContentSize) / 2;
diff --git a/lib/src/types.dart b/lib/src/types.dart
index 1e7da62..07a85e9 100644
--- a/lib/src/types.dart
+++ b/lib/src/types.dart
@@ -4,6 +4,7 @@
* See LICENSE for distribution and usage details.
*/
+import 'package:flutter/widgets.dart';
import 'dart:ui';
@@ -70,6 +71,7 @@ enum EmbeddedImageShape {
}
/// Styling options for finder pattern eye.
+@immutable
class QrEyeStyle {
/// Create a new set of styling options for QR Eye.
const QrEyeStyle({
@@ -100,6 +102,7 @@ class QrEyeStyle {
}
/// Styling options for data module.
+@immutable
class QrDataModuleStyle {
/// Create a new set of styling options for data modules.
const QrDataModuleStyle({
@@ -152,6 +155,7 @@ class QrDataModuleStyle {
}
/// Styling options for any embedded image overlay
+@immutable
class QrEmbeddedImageStyle {
/// Create a new set of styling options.
const QrEmbeddedImageStyle({
diff --git a/lib/src/validator.dart b/lib/src/validator.dart
index b40d31c..12a1eb8 100644
--- a/lib/src/validator.dart
+++ b/lib/src/validator.dart
@@ -30,10 +30,14 @@ class QrValidator {
);
}
return QrValidationResult(
- status: QrValidationStatus.valid, qrCode: qrCode);
- } on InputTooLongException catch (itle) {
+ status: QrValidationStatus.valid,
+ qrCode: qrCode,
+ );
+ } on InputTooLongException catch (title) {
return QrValidationResult(
- status: QrValidationStatus.contentTooLong, error: itle);
+ status: QrValidationStatus.contentTooLong,
+ error: title,
+ );
} on Exception catch (ex) {
return QrValidationResult(status: QrValidationStatus.error, error: ex);
}
diff --git a/pubspec.yaml b/pubspec.yaml
index 04b46d3..f0e2e74 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -2,22 +2,21 @@ name: qr_flutter
description: >
QR.Flutter is a Flutter library for simple and fast QR code rendering via a
Widget or custom painter.
-version: 4.0.1
+version: 4.1.0
homepage: https://github.com/theyakka/qr.flutter
environment:
- sdk: ">=2.12.0 <3.0.0"
- flutter: ">=1.16.0"
+ sdk: '>=2.19.6 <4.0.0'
+ flutter: ">=3.7.0"
dependencies:
flutter:
sdk: flutter
- qr: ^3.0.0
+ qr: ^3.0.1
dev_dependencies:
flutter_test:
sdk: flutter
- test: ^1.16.5
flutter:
uses-material-design: false
diff --git a/test/.golden/qr_image_data_module_styled_golden.png b/test/.golden/qr_image_data_module_styled_golden.png
index 47a1641..d50b737 100644
Binary files a/test/.golden/qr_image_data_module_styled_golden.png and b/test/.golden/qr_image_data_module_styled_golden.png differ
diff --git a/test/.golden/qr_image_eye_data_module_styled_golden.png b/test/.golden/qr_image_eye_data_module_styled_golden.png
index 8f44474..275496d 100644
Binary files a/test/.golden/qr_image_eye_data_module_styled_golden.png and b/test/.golden/qr_image_eye_data_module_styled_golden.png differ
diff --git a/test/.golden/qr_image_eye_styled_golden.png b/test/.golden/qr_image_eye_styled_golden.png
index fe964e5..867ae26 100644
Binary files a/test/.golden/qr_image_eye_styled_golden.png and b/test/.golden/qr_image_eye_styled_golden.png differ
diff --git a/test/.golden/qr_image_foreground_colored_golden.png b/test/.golden/qr_image_foreground_colored_golden.png
index affaf04..60de4e7 100644
Binary files a/test/.golden/qr_image_foreground_colored_golden.png and b/test/.golden/qr_image_foreground_colored_golden.png differ
diff --git a/test/.golden/qr_image_golden.png b/test/.golden/qr_image_golden.png
index 93e2dd8..493c247 100644
Binary files a/test/.golden/qr_image_golden.png and b/test/.golden/qr_image_golden.png differ
diff --git a/test/.golden/qr_image_logo_golden.png b/test/.golden/qr_image_logo_golden.png
index 0ab1b80..8856a1b 100644
Binary files a/test/.golden/qr_image_logo_golden.png and b/test/.golden/qr_image_logo_golden.png differ
diff --git a/test/image_test.dart b/test/image_test.dart
index a6bf5be..578c1c8 100644
--- a/test/image_test.dart
+++ b/test/image_test.dart
@@ -11,7 +11,9 @@ import 'package:flutter_test/flutter_test.dart';
import 'package:qr_flutter/qr_flutter.dart';
void main() {
- testWidgets('QrImageView generates correct image', (tester) async {
+ testWidgets('QrImageView generates correct image', (
+ tester,
+ ) async {
final qrImage = MaterialApp(
home: Center(
child: RepaintBoundary(
@@ -31,143 +33,156 @@ void main() {
);
});
- testWidgets('QrImageView generates correct image with eye style',
- (tester) async {
- final qrImage = MaterialApp(
- home: Center(
- child: RepaintBoundary(
- child: QrImageView(
- data: 'This is a test image',
- version: QrVersions.auto,
- gapless: true,
- errorCorrectionLevel: QrErrorCorrectLevel.L,
- eyeStyle: const QrEyeStyle(
- eyeShape: QrEyeShape.circle,
- color: Colors.green,
- ),
- ),
- ),
- ),
- );
- await tester.pumpWidget(qrImage);
- await expectLater(
- find.byType(QrImageView),
- matchesGoldenFile('./.golden/qr_image_eye_styled_golden.png'),
- );
- });
-
- testWidgets('QrImageView generates correct image with data module style',
- (tester) async {
- final qrImage = MaterialApp(
- home: Center(
- child: RepaintBoundary(
- child: QrImageView(
- data: 'This is a test image',
- version: QrVersions.auto,
- gapless: true,
- errorCorrectionLevel: QrErrorCorrectLevel.L,
- dataModuleStyle: const QrDataModuleStyle(
- dataModuleShape: QrDataModuleShape.circle,
- color: Colors.blue,
- ),
- ),
- ),
- ),
- );
- await tester.pumpWidget(qrImage);
- await expectLater(
- find.byType(QrImageView),
- matchesGoldenFile('./.golden/qr_image_data_module_styled_golden.png'),
- );
- });
-
testWidgets(
- 'QrImageView generates correct image with eye and data module sytle',
- (tester) async {
- final qrImage = MaterialApp(
- home: Center(
- child: RepaintBoundary(
- child: QrImageView(
- data: 'This is a test image',
- version: QrVersions.auto,
- gapless: true,
- errorCorrectionLevel: QrErrorCorrectLevel.L,
- eyeStyle: const QrEyeStyle(
- eyeShape: QrEyeShape.circle,
- color: Colors.green,
- ),
- dataModuleStyle: const QrDataModuleStyle(
- dataModuleShape: QrDataModuleShape.circle,
- color: Colors.blue,
- ),
- ),
- ),
- ),
- );
- await tester.pumpWidget(qrImage);
- await expectLater(
- find.byType(QrImageView),
- matchesGoldenFile('./.golden/qr_image_eye_data_module_styled_golden.png'),
- );
- });
-
- testWidgets(
- 'QrImageView does not apply eye and data module color when foreground '
- 'color is also specified', (tester) async {
- final qrImage = MaterialApp(
- home: Center(
- child: RepaintBoundary(
- child: QrImageView(
- data: 'This is a test image',
- version: QrVersions.auto,
- gapless: true,
- foregroundColor: Colors.red,
- errorCorrectionLevel: QrErrorCorrectLevel.L,
- eyeStyle: const QrEyeStyle(
- eyeShape: QrEyeShape.circle,
- color: Colors.green,
- ),
- dataModuleStyle: const QrDataModuleStyle(
- dataModuleShape: QrDataModuleShape.circle,
- color: Colors.blue,
- ),
- ),
- ),
- ),
- );
- await tester.pumpWidget(qrImage);
- await expectLater(
- find.byType(QrImageView),
- matchesGoldenFile('./.golden/qr_image_foreground_colored_golden.png'),
- );
- });
-
- testWidgets('QrImageView generates correct image with logo', (tester) async {
- await pumpWidgetWithImages(
- tester,
- MaterialApp(
+ 'QrImageView generates correct image with eye style',
+ (tester) async {
+ final qrImage = MaterialApp(
home: Center(
child: RepaintBoundary(
child: QrImageView(
- data: 'This is a a qr code with a logo',
+ data: 'This is a test image',
version: QrVersions.auto,
gapless: true,
errorCorrectionLevel: QrErrorCorrectLevel.L,
- embeddedImage: FileImage(File('test/.images/logo_yakka.png')),
+ eyeStyle: const QrEyeStyle(
+ eyeShape: QrEyeShape.circle,
+ color: Colors.green,
+ ),
),
),
),
- ),
- ['test/.images/logo_yakka.png'],
- );
+ );
+ await tester.pumpWidget(qrImage);
+ await expectLater(
+ find.byType(QrImageView),
+ matchesGoldenFile('./.golden/qr_image_eye_styled_golden.png'),
+ );
+ },
+ );
- await tester.pumpAndSettle();
+ testWidgets(
+ 'QrImageView generates correct image with data module style',
+ (tester) async {
+ final qrImage = MaterialApp(
+ home: Center(
+ child: RepaintBoundary(
+ child: QrImageView(
+ data: 'This is a test image',
+ version: QrVersions.auto,
+ gapless: true,
+ errorCorrectionLevel: QrErrorCorrectLevel.L,
+ dataModuleStyle: const QrDataModuleStyle(
+ dataModuleShape: QrDataModuleShape.circle,
+ color: Colors.blue,
+ ),
+ ),
+ ),
+ ),
+ );
+ await tester.pumpWidget(qrImage);
+ await expectLater(
+ find.byType(QrImageView),
+ matchesGoldenFile('./.golden/qr_image_data_module_styled_golden.png'),
+ );
+ },
+ );
- await expectLater(
- find.byType(QrImageView),
- matchesGoldenFile('./.golden/qr_image_logo_golden.png'),
- );
- });
+ testWidgets(
+ 'QrImageView generates correct image with eye and data module sytle',
+ (tester) async {
+ final qrImage = MaterialApp(
+ home: Center(
+ child: RepaintBoundary(
+ child: QrImageView(
+ data: 'This is a test image',
+ version: QrVersions.auto,
+ gapless: true,
+ errorCorrectionLevel: QrErrorCorrectLevel.L,
+ eyeStyle: const QrEyeStyle(
+ eyeShape: QrEyeShape.circle,
+ color: Colors.green,
+ ),
+ dataModuleStyle: const QrDataModuleStyle(
+ dataModuleShape: QrDataModuleShape.circle,
+ color: Colors.blue,
+ ),
+ ),
+ ),
+ ),
+ );
+ await tester.pumpWidget(qrImage);
+ await expectLater(
+ find.byType(QrImageView),
+ matchesGoldenFile(
+ './.golden/qr_image_eye_data_module_styled_golden.png',
+ ),
+ );
+ },
+ );
+
+ testWidgets(
+ 'QrImageView does not apply eye and data module color when foreground '
+ 'color is also specified',
+ (tester) async {
+ final qrImage = MaterialApp(
+ home: Center(
+ child: RepaintBoundary(
+ child: QrImageView(
+ data: 'This is a test image',
+ version: QrVersions.auto,
+ gapless: true,
+ // ignore: deprecated_member_use_from_same_package
+ foregroundColor: Colors.red,
+ errorCorrectionLevel: QrErrorCorrectLevel.L,
+ eyeStyle: const QrEyeStyle(
+ eyeShape: QrEyeShape.circle,
+ color: Colors.green,
+ ),
+ dataModuleStyle: const QrDataModuleStyle(
+ dataModuleShape: QrDataModuleShape.circle,
+ color: Colors.blue,
+ ),
+ ),
+ ),
+ ),
+ );
+ await tester.pumpWidget(qrImage);
+ await expectLater(
+ find.byType(QrImageView),
+ matchesGoldenFile('./.golden/qr_image_foreground_colored_golden.png'),
+ );
+ },
+ );
+
+ testWidgets(
+ 'QrImageView generates correct image with logo',
+ (tester) async {
+ await pumpWidgetWithImages(
+ tester,
+ MaterialApp(
+ home: Center(
+ child: RepaintBoundary(
+ child: QrImageView(
+ data: 'This is a a qr code with a logo',
+ version: QrVersions.auto,
+ gapless: true,
+ errorCorrectionLevel: QrErrorCorrectLevel.L,
+ embeddedImage: FileImage(File('test/.images/logo_yakka.png')),
+ ),
+ ),
+ ),
+ ),
+ ['test/.images/logo_yakka.png'],
+ );
+
+ await tester.pumpAndSettle();
+
+ await expectLater(
+ find.byType(QrImageView),
+ matchesGoldenFile('./.golden/qr_image_logo_golden.png'),
+ );
+ },
+ );
}
/// Pre-cache images to make sure they show up in golden tests.
@@ -180,19 +195,24 @@ Future pumpWidgetWithImages(
) async {
Future? precacheFuture;
await tester.pumpWidget(
- Builder(builder: (buildContext) {
- precacheFuture = tester.runAsync(() async {
- await Future.wait([
- for (final assetName in assetNames)
- precacheImage(FileImage(File(assetName)), buildContext),
- ]);
- });
- return widget;
- }),
+ Builder(
+ builder: (buildContext) {
+ precacheFuture = tester.runAsync(() async {
+ await Future.wait(>[
+ for (final String assetName in assetNames)
+ precacheImage(FileImage(File(assetName)), buildContext),
+ ]);
+ });
+ return widget;
+ },
+ ),
);
await precacheFuture;
}
Widget buildTestableWidget(Widget widget) {
- return MediaQuery(data: MediaQueryData(), child: MaterialApp(home: widget));
+ return MediaQuery(
+ data: const MediaQueryData(),
+ child: MaterialApp(home: widget),
+ );
}
diff --git a/test/painter_test.dart b/test/painter_test.dart
index 31bbba6..3e292c9 100644
--- a/test/painter_test.dart
+++ b/test/painter_test.dart
@@ -22,9 +22,9 @@ void main() {
imageData = await painter.toImageData(600.0);
});
final imageBytes = imageData!.buffer.asUint8List();
- final widget = Center(
+ final Widget widget = Center(
child: RepaintBoundary(
- child: Container(
+ child: SizedBox(
width: 600,
height: 600,
child: Image.memory(imageBytes),