diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1c2f606..3e55077 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,2 +1,8 @@
## 0.1.0
* Initial release.
+
+## 0.1.1
+* Beta release
+
+## 0.1.2
+* Fixed QR code eyes on web
\ No newline at end of file
diff --git a/README.md b/README.md
index 0accbdc..ccf3c67 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,8 @@
# Custom QR generator for Flutter
[](https://pub.dartlang.org/packages/custom_qr_generator)
+
+
Flutter port of [Android library](https://github.com/alexzhirkevich/custom-qr-generator)
# Progress
@@ -22,10 +24,10 @@ This will add a line like this to your package's `pubspec.yaml` (and run an impl
```yaml
dependencies:
- custom_qr_generator: ^0.1.0
+ custom_qr_generator: ^0.1.2
```
-## Import it
+## Import it
Now in your Dart code, you can use:
@@ -73,11 +75,50 @@ class MyApp extends StatelessWidget {
)
)
)),
- size: const Size(300, 300),
+ size: const Size(350, 350),
),
),
),
);
}
}
+
+```
+
+# Customization
+
+You can implement custom shapes for any QR code parts: QrPixelShape, QrBallShape, QrFrameShape
+like this:
+```dart
+class QrPixelShapeCircle extends QrPixelShape {
+
+ @override
+ Path createPath(double size, Neighbors neighbors) =>
+ Path()..addOval(Rect.fromLTRB(0, 0, size, size));
+}
+```
+
+Also you can create custom paint for this elements:
+
+```dart
+
+class QrColorRadialGradient extends QrColor {
+
+ final List colors;
+
+ const QrColorRadialGradient({
+ required this.colors,
+ });
+
+ @override
+ Paint createPaint(final double width, final double height) =>
+ Paint()
+ ..shader = Gradient.radial(
+ Offset(width / 2, height / 2),
+ min(width, height),
+ colors
+ );
+}
+
+
```
diff --git a/example/ios/Flutter/AppFrameworkInfo.plist b/example/ios/Flutter/AppFrameworkInfo.plist
index 8d4492f..9625e10 100644
--- a/example/ios/Flutter/AppFrameworkInfo.plist
+++ b/example/ios/Flutter/AppFrameworkInfo.plist
@@ -21,6 +21,6 @@
CFBundleVersion
1.0
MinimumOSVersion
- 9.0
+ 11.0
diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj
index c6759a6..30b6524 100644
--- a/example/ios/Runner.xcodeproj/project.pbxproj
+++ b/example/ios/Runner.xcodeproj/project.pbxproj
@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
- objectVersion = 46;
+ objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
@@ -127,7 +127,7 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 1020;
+ LastUpgradeCheck = 1300;
ORGANIZATIONNAME = "";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
@@ -272,7 +272,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@@ -346,7 +346,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -395,7 +395,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 9.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 11.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
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
+
diff --git a/example/lib/main.dart b/example/lib/main.dart
index fd8a8b5..47d9027 100644
--- a/example/lib/main.dart
+++ b/example/lib/main.dart
@@ -18,34 +18,29 @@ class MyApp extends StatelessWidget {
),
body: Center(
child: CustomPaint(
+ // painter: Painter(),
painter: QrPainter(
- data: "Welcome to Flutter",
+ data: 'https://youtube.com',
options: const QrOptions(
shapes: QrShapes(
- darkPixel: QrPixelShapeRoundCorners(
- cornerFraction: .5
- ),
- frame: QrFrameShapeRoundCorners(
- cornerFraction: .25
- ),
- ball: QrBallShapeRoundCorners(
- cornerFraction: .25
- )
+ darkPixel: QrPixelShapeRoundCorners(cornerFraction: .5),
+ frame: QrFrameShapeRoundCorners(cornerFraction: .25),
+ ball: QrBallShapeRoundCorners(cornerFraction: .25)
),
colors: QrColors(
dark: QrColorLinearGradient(
colors: [
Color.fromARGB(255, 255, 0, 0),
- Color.fromARGB(255, 0, 0, 255),
+ Color.fromARGB(255, 0, 0, 255)
],
orientation: GradientOrientation.leftDiagonal
)
)
)),
- size: const Size(300, 300),
+ size: const Size(350, 350),
),
),
),
);
}
-}
\ No newline at end of file
+}
diff --git a/example/pubspec.lock b/example/pubspec.lock
index 8c6977d..eaf6331 100644
--- a/example/pubspec.lock
+++ b/example/pubspec.lock
@@ -7,7 +7,7 @@ packages:
name: async
url: "https://pub.dartlang.org"
source: hosted
- version: "2.8.1"
+ version: "2.9.0"
boolean_selector:
dependency: transitive
description:
@@ -21,14 +21,7 @@ packages:
name: characters
url: "https://pub.dartlang.org"
source: hosted
- version: "1.1.0"
- charcode:
- dependency: transitive
- description:
- name: charcode
- url: "https://pub.dartlang.org"
- source: hosted
- version: "1.3.1"
+ version: "1.2.1"
charset:
dependency: transitive
description:
@@ -42,28 +35,28 @@ packages:
name: clock
url: "https://pub.dartlang.org"
source: hosted
- version: "1.1.0"
+ version: "1.1.1"
collection:
dependency: transitive
description:
name: collection
url: "https://pub.dartlang.org"
source: hosted
- version: "1.15.0"
+ version: "1.16.0"
custom_qr_generator:
dependency: "direct main"
description:
path: ".."
relative: true
source: path
- version: "0.1.0"
+ version: "0.1.2"
fake_async:
dependency: transitive
description:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
- version: "1.2.0"
+ version: "1.3.1"
flutter:
dependency: "direct main"
description: flutter
@@ -101,21 +94,28 @@ packages:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
- version: "0.12.10"
+ version: "0.12.12"
+ material_color_utilities:
+ dependency: transitive
+ description:
+ name: material_color_utilities
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.1.5"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
source: hosted
- version: "1.7.0"
+ version: "1.8.0"
path:
dependency: transitive
description:
name: path
url: "https://pub.dartlang.org"
source: hosted
- version: "1.8.0"
+ version: "1.8.2"
sky_engine:
dependency: transitive
description: flutter
@@ -127,7 +127,7 @@ packages:
name: source_span
url: "https://pub.dartlang.org"
source: hosted
- version: "1.8.1"
+ version: "1.9.0"
stack_trace:
dependency: transitive
description:
@@ -148,35 +148,28 @@ packages:
name: string_scanner
url: "https://pub.dartlang.org"
source: hosted
- version: "1.1.0"
+ version: "1.1.1"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.dartlang.org"
source: hosted
- version: "1.2.0"
+ version: "1.2.1"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
- version: "0.4.2"
- typed_data:
- dependency: transitive
- description:
- name: typed_data
- url: "https://pub.dartlang.org"
- source: hosted
- version: "1.3.0"
+ version: "0.4.12"
vector_math:
dependency: transitive
description:
name: vector_math
url: "https://pub.dartlang.org"
source: hosted
- version: "2.1.0"
+ version: "2.1.2"
zxing_lib:
dependency: transitive
description:
@@ -185,5 +178,5 @@ packages:
source: hosted
version: "0.6.0"
sdks:
- dart: ">=2.14.0 <3.0.0"
+ dart: ">=2.17.0-0 <3.0.0"
flutter: ">=1.17.0"
diff --git a/example/test/widget_test.dart b/example/test/widget_test.dart
deleted file mode 100644
index a19dabb..0000000
--- a/example/test/widget_test.dart
+++ /dev/null
@@ -1,30 +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:flutter/material.dart';
-import 'package:flutter_test/flutter_test.dart';
-
-import 'package:example/main.dart';
-
-void main() {
- testWidgets('Counter increments smoke test', (WidgetTester tester) async {
- // Build our app and trigger a frame.
- await tester.pumpWidget(const MyApp());
-
- // 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/colors/color.dart b/lib/colors/color.dart
index 17cb0d8..67a9491 100644
--- a/lib/colors/color.dart
+++ b/lib/colors/color.dart
@@ -5,9 +5,27 @@ import 'package:custom_qr_generator/util.dart';
abstract class QrColor {
+ const QrColor();
+
Paint createPaint(final double width, final double height);
- const QrColor();
+ static const unspecified = QrColorUnspecified();
+
+ static QrColor solid(Color color) => QrColorSolid(color);
+
+ static QrColorLinearGradient linearGradient({
+ required List colors,
+ required GradientOrientation orientation
+ }) => QrColorLinearGradient(colors: colors, orientation: orientation);
+
+ static QrColorRadialGradient radialGradient({
+ required List colors,
+ double radiusFraction = 1
+ }) => QrColorRadialGradient(colors: colors, radiusFraction: radiusFraction);
+
+ static QrColorSweepGradient sweepGradient({
+ required List colors
+ }) => QrColorSweepGradient(colors: colors);
}
class QrColorUnspecified extends QrColor {
@@ -16,7 +34,8 @@ class QrColorUnspecified extends QrColor {
@override
Paint createPaint(double width, double height) =>
- const QrColorSolid(Color.fromARGB(0,0,0,0)).createPaint(width, height);
+ const QrColorSolid(Color.fromARGB(0,0,0,0))
+ .createPaint(width, height);
@override
bool operator ==(Object other) =>
diff --git a/lib/neighbors.dart b/lib/neighbors.dart
index 454787f..083ca6a 100644
--- a/lib/neighbors.dart
+++ b/lib/neighbors.dart
@@ -9,6 +9,8 @@ class Neighbors {
final bool bottom;
final bool bottomRight;
+ static const empty = Neighbors();
+
const Neighbors({
this.topLeft = false,
this.topRight = false,
diff --git a/lib/qr_painter.dart b/lib/qr_painter.dart
index 10c13fa..a781560 100644
--- a/lib/qr_painter.dart
+++ b/lib/qr_painter.dart
@@ -1,11 +1,14 @@
+import 'dart:convert';
import 'dart:math';
+import 'package:custom_qr_generator/custom_qr_generator.dart';
import 'package:custom_qr_generator/util.dart';
import 'package:custom_qr_generator/colors/color.dart';
import 'package:custom_qr_generator/options/options.dart';
import 'package:flutter/widgets.dart';
import 'package:zxing_lib/qrcode.dart';
+import 'package:zxing_lib/zxing.dart';
class QrPainter extends CustomPainter {
@@ -15,13 +18,21 @@ class QrPainter extends CustomPainter {
QrPainter({
required this.data,
- required this.options
+ required this.options,
}) {
+
matrix = Encoder
- .encode(
- data, options.ecl, Map.fromEntries([
- ]))
+ .encode(data, options.ecl)
.matrix!;
+
+ var width = matrix.width~/4;
+ if (width % 2 != matrix.width%2) {
+ width++;
+ }
+ var height = matrix.height~/4;
+ if (height % 2 != matrix.height%2) {
+ height++;
+ }
}
@override
@@ -39,19 +50,18 @@ class QrPainter extends CustomPainter {
Path fullDarkPath = Path();
Path fullLightPath = Path();
- final framePath = options.shapes.frame.createPath(pixelSize * 7, null);
- final framePaint = options.colors.frame.createPaint(
- pixelSize * 3, pixelSize * 3);
- final ballPath = options.shapes.ball.createPath(pixelSize * 3, null);
- final ballPaint = options.colors.ball.createPaint(
- pixelSize * 3, pixelSize * 3);
+ var frameSize= pixelSize * 7;
+ var ballSize = pixelSize * 3;
- if (!options.shapes.darkPixel.dependOnNeighbors) {
- darkPath = options.shapes.darkPixel.createPath(pixelSize, null);
- }
- if (!options.shapes.lightPixel.dependOnNeighbors) {
- lightPath = options.shapes.lightPixel.createPath(pixelSize, null);
- }
+ final framePathZeroOffset = options.shapes.frame
+ .createPath(Offset.zero, frameSize, Neighbors.empty);
+ final framePaint = options.colors.frame
+ .createPaint(pixelSize * 3, pixelSize * 3);
+
+ final ballPathZeroOffset = options.shapes.ball
+ .createPath(Offset.zero, pixelSize * 3, Neighbors.empty);
+ final ballPaint = options.colors.ball
+ .createPaint(pixelSize * 3, pixelSize * 3);
canvas.drawRect(
Rect.fromLTWH(0, 0, size.width, size.height),
@@ -61,57 +71,40 @@ class QrPainter extends CustomPainter {
canvas.save();
canvas.translate(padding, padding);
- // todo: workaround for Dart bug with adding combined path.
- fullDarkPath = Path.combine(PathOperation.union, fullDarkPath, Path());
-
- if (options.colors.frame is! QrColorUnspecified) {
- canvas.drawPath(framePath, framePaint);
- } else {
- fullDarkPath.addPath(framePath, Offset.zero);
+ void drawFrame(double dx, double dy) {
+ if (options.colors.frame is! QrColorUnspecified) {
+ canvas.save();
+ canvas.translate(dx, dy);
+ canvas.drawPath(framePathZeroOffset, framePaint);
+ canvas.restore();
+ } else {
+ var path = options.shapes.frame
+ .createPath(Offset(dx, dy), frameSize, Neighbors.empty);
+ canvas.drawPath(path, darkPaint);
+ }
}
- if (options.colors.ball is! QrColorUnspecified) {
- canvas.save();
- canvas.translate(pixelSize * 2, pixelSize * 2);
- canvas.drawPath(ballPath, ballPaint);
- canvas.restore();
- } else {
- fullDarkPath.addPath(ballPath, Offset(pixelSize * 2, pixelSize * 2));
+ void drawBall(double dx, double dy) {
+ if (options.colors.ball is! QrColorUnspecified) {
+ canvas.save();
+ canvas.translate(dx, dy);
+ canvas.drawPath(ballPathZeroOffset, ballPaint);
+ canvas.restore();
+ } else {
+ var path = options.shapes.ball
+ .createPath(Offset(dx, dy), ballSize, Neighbors.empty);
+ canvas.drawPath(path, darkPaint);
+ }
}
- canvas.save();
- canvas.translate(pixelSize * (matrix.width - 7), 0);
- if (options.colors.frame is! QrColorUnspecified) {
- canvas.drawPath(framePath, framePaint);
- } else {
- fullDarkPath.addPath(
- framePath, Offset(pixelSize * (matrix.width - 7), 0));
- }
- if (options.colors.ball is! QrColorUnspecified) {
- canvas.translate(pixelSize * 2, pixelSize * 2);
- canvas.drawPath(ballPath, ballPaint);
- } else {
- fullDarkPath.addPath(
- ballPath, Offset(pixelSize * (matrix.width - 5), pixelSize * 2));
- }
- canvas.restore();
+ drawFrame(0,0);
+ drawBall(pixelSize * 2, pixelSize * 2);
- canvas.save();
- canvas.translate(0, pixelSize * (matrix.height - 7));
- if (options.colors.frame is! QrColorUnspecified) {
- canvas.drawPath(framePath, framePaint);
- } else {
- fullDarkPath.addPath(
- framePath, Offset(0, pixelSize * (matrix.width - 7)));
- }
- if (options.colors.ball is! QrColorUnspecified) {
- canvas.translate(pixelSize * 2, pixelSize * 2);
- canvas.drawPath(ballPath, ballPaint);
- } else {
- fullDarkPath.addPath(
- ballPath, Offset(pixelSize * 2, pixelSize * (matrix.height - 5)));
- }
- canvas.restore();
+ drawFrame(pixelSize * (matrix.width - 7), 0);
+ drawBall(pixelSize * (matrix.width - 5), pixelSize * 2);
+
+ drawFrame(0,pixelSize * (matrix.width - 7));
+ drawBall(pixelSize * 2, pixelSize * (matrix.height - 5));
for (int i = 0; i < matrix.width; i++) {
@@ -123,28 +116,34 @@ class QrPainter extends CustomPainter {
continue;
}
- if (options.shapes.darkPixel.dependOnNeighbors) {
+ if (options.colors.dark is! QrColorUnspecified) {
darkPath = options.shapes.darkPixel.createPath(
- pixelSize, matrix.neighbors(i, j)
+ Offset.zero, pixelSize, matrix.neighbors(i, j)
);
}
- if (options.shapes.lightPixel.dependOnNeighbors) {
+ if (options.colors.light is! QrColorUnspecified) {
lightPath = options.shapes.lightPixel.createPath(
- pixelSize, matrix.neighbors(i, j)
+ Offset.zero, pixelSize, matrix.neighbors(i, j)
);
}
- if (matrix.get(i, j) == 1) {
+ if (matrix.get(i, j) == 1 && options.colors.dark is! QrColorUnspecified) {
fullDarkPath.addPath(darkPath!, Offset(i * pixelSize, j * pixelSize));
}
- if (matrix.get(i, j) != 0) {
- fullLightPath.addPath(
- lightPath!, Offset(i * pixelSize, j * pixelSize));
+ if (matrix.get(i, j) != 0 && options.colors.light is! QrColorUnspecified) {
+ fullLightPath.addPath(lightPath!, Offset(i * pixelSize, j * pixelSize));
}
}
}
- canvas.drawPath(fullDarkPath, darkPaint);
- canvas.drawPath(fullLightPath, lightPaint);
+
+
+ if (options.colors.dark is! QrColorUnspecified) {
+ canvas.drawPath(fullDarkPath, darkPaint);
+ }
+ if (options.colors.light is! QrColorUnspecified) {
+ canvas.drawPath(fullLightPath, lightPaint);
+ }
canvas.restore();
+
}
@override
diff --git a/lib/shapes/ball_shape.dart b/lib/shapes/ball_shape.dart
index 07be4a2..1ad7fcd 100644
--- a/lib/shapes/ball_shape.dart
+++ b/lib/shapes/ball_shape.dart
@@ -1,12 +1,18 @@
import 'package:custom_qr_generator/shapes/shape.dart';
-abstract class QrBallShape extends Shape {
-
- @override
- bool get dependOnNeighbors => false;
+abstract class QrBallShape extends QrElementShape {
const QrBallShape();
+
+ static const basic = QrBallShapeDefault();
+
+ static QrBallShapeCircle circle({double radiusFraction = 1}) =>
+ QrBallShapeCircle(radiusFraction: radiusFraction);
+
+ static QrBallShapeRoundCorners roundCorners({
+ required double cornerFraction
+ }) => QrBallShapeRoundCorners(cornerFraction: cornerFraction);
}
class QrBallShapeDefault extends QrBallShape with ShapeRect {
diff --git a/lib/shapes/frame_shape.dart b/lib/shapes/frame_shape.dart
index 97ad8ff..97b8101 100644
--- a/lib/shapes/frame_shape.dart
+++ b/lib/shapes/frame_shape.dart
@@ -1,15 +1,36 @@
import 'dart:ui';
import 'package:custom_qr_generator/custom_qr_generator.dart';
-import 'package:custom_qr_generator/neighbors.dart';
-import 'package:custom_qr_generator/util.dart';
-import 'package:custom_qr_generator/shapes/shape.dart';
-abstract class QrFrameShape extends Shape{
- @override
- bool get dependOnNeighbors => false;
+abstract class QrFrameShape extends QrElementShape {
const QrFrameShape();
+
+ static const basic = QrFrameShapeDefault();
+
+ static QrFrameShapeCircle circle({
+ double widthFraction = 1,
+ double radiusFraction = 1
+ }) => QrFrameShapeCircle(
+ widthFraction: widthFraction,
+ radiusFraction: radiusFraction
+ );
+
+ static QrFrameShapeRoundCorners roundCorners({
+ required double cornerFraction,
+ double widthFraction = 1,
+ bool topLeft = true,
+ bool topRight = true,
+ bool bottomLeft = true,
+ bool bottomRight = true
+ }) => QrFrameShapeRoundCorners(
+ widthFraction: widthFraction,
+ cornerFraction: cornerFraction,
+ topLeft: topLeft,
+ topRight: topRight,
+ bottomLeft: bottomLeft,
+ bottomRight: bottomRight
+ );
}
class QrFrameShapeDefault extends QrFrameShape {
@@ -17,14 +38,12 @@ class QrFrameShapeDefault extends QrFrameShape {
const QrFrameShapeDefault();
@override
- Path createPath(double size, Neighbors? neighbors) {
- final big = Path()
- ..addRect(Rect.fromLTWH(0, 0, size, size));
- final small = Path()
- ..addRect(Rect.fromLTWH(size / 7, size / 7, size * 5 / 7, size * 5 / 7));
+ Path createPath(Offset offset, double size, Neighbors? neighbors) =>
+ Path()
+ ..fillType = PathFillType.evenOdd
+ ..addRect(Rect.fromLTWH(offset.dx, offset.dy, size, size))
+ ..addRect(Rect.fromLTWH(offset.dx +size / 7,offset.dy+ size / 7, size * 5 / 7, size * 5 / 7));
- return Path.combine(PathOperation.xor, big, small);
- }
@override
bool operator ==(Object other) => other is QrFrameShapeDefault;
@@ -44,20 +63,23 @@ class QrFrameShapeCircle extends QrFrameShape {
});
@override
- Path createPath(double size, Neighbors? neighbors) {
+ Path createPath(Offset offset, double size, Neighbors? neighbors) {
+
final realSize = size * radiusFraction;
- final offset = (size - realSize) / 2;
+ final offset2 = (size - realSize) / 2;
final width = size / 7 * widthFraction.coerceAtLeast(0);
- final big = Path()
- ..addOval(Rect.fromLTWH(offset, offset, realSize, realSize));
- final small = Path()
- ..addOval(Rect.fromLTWH(
- offset + width, offset + width,
- size - offset * 2 - width * 2, size - offset * 2 - width * 2
- ));
- return Path.combine(PathOperation.xor, small, big);
+ return Path()
+ ..fillType = PathFillType.evenOdd
+ ..addOval(Rect.fromLTWH(offset.dx + offset2, offset.dy + offset2, realSize, realSize))
+ ..addOval(Rect.fromLTWH(
+ offset.dx + offset2 + width,
+ offset.dy + offset2 + width,
+ size - offset2 * 2 - width * 2,
+ size - offset2 * 2 - width * 2
+ ))
+ ;
}
@override
@@ -89,7 +111,7 @@ class QrFrameShapeRoundCorners extends QrFrameShape {
});
@override
- Path createPath(double size, Neighbors? neighbors) {
+ Path createPath(Offset offset,double size, Neighbors? neighbors) {
final cf = cornerFraction.coerceIn(0, .5);
final cTopLeft = topLeft ? cf : 0;
final cTopRight = topRight ? cf : 0;
@@ -97,23 +119,24 @@ class QrFrameShapeRoundCorners extends QrFrameShape {
final cBottomRight = bottomRight ? cf : 0;
final w = size / 7 * widthFraction.coerceIn(0, 2);
- final big = Path()
- ..addRRect(RRect.fromLTRBAndCorners(0, 0, size, size,
+ return Path()
+ ..fillType=PathFillType.evenOdd
+ ..addRRect(RRect.fromLTRBAndCorners(
+ offset.dx, offset.dy,
+ offset.dx + size, offset.dy + size,
topLeft: Radius.circular(size * cTopLeft),
topRight: Radius.circular(size * cTopRight),
bottomLeft: Radius.circular(size * cBottomLeft),
bottomRight: Radius.circular(size * cBottomRight),
- ));
-
- final small = Path()
- ..addRRect(RRect.fromLTRBAndCorners(w, w, size - w, size - w,
+ ))
+ ..addRRect(RRect.fromLTRBAndCorners(
+ offset.dx + w, offset.dy + w,
+ offset.dx + size - w, offset.dy + size - w,
topLeft: Radius.circular((size - 2 * w) * cTopLeft),
topRight: Radius.circular((size - 2 * w) * cTopRight),
bottomLeft: Radius.circular((size - 2 * w) * cBottomLeft),
bottomRight: Radius.circular((size - 2 * w) * cBottomRight),
));
-
- return Path.combine(PathOperation.xor, big, small);
}
@override
diff --git a/lib/shapes/pixel_shape.dart b/lib/shapes/pixel_shape.dart
index 4cc0e92..85f8c3d 100644
--- a/lib/shapes/pixel_shape.dart
+++ b/lib/shapes/pixel_shape.dart
@@ -1,17 +1,25 @@
import 'package:custom_qr_generator/shapes/shape.dart';
-abstract class QrPixelShape extends Shape {
- const QrPixelShape();
+abstract class QrPixelShape extends QrElementShape {
+
+ const QrPixelShape();
+
+ static const basic = QrPixelShapeDefault();
+
+ static QrPixelShapeCircle circle({
+ double radiusFraction = 1
+ }) => QrPixelShapeCircle(radiusFraction: radiusFraction);
+
+ static QrPixelShapeRoundCorners roundCorners({
+ double cornerFraction = 1
+ }) => QrPixelShapeRoundCorners(cornerFraction: cornerFraction);
}
class QrPixelShapeDefault extends QrPixelShape with ShapeRect {
const QrPixelShapeDefault();
- @override
- bool get dependOnNeighbors => false;
-
@override
bool operator ==(Object other) => other is QrPixelShapeDefault;
@@ -24,9 +32,6 @@ class QrPixelShapeCircle extends QrPixelShape with ShapeCircle {
@override
final double radiusFraction;
- @override
- bool get dependOnNeighbors => false;
-
const QrPixelShapeCircle({
this.radiusFraction = 1.0
});
@@ -39,22 +44,19 @@ class QrPixelShapeCircle extends QrPixelShape with ShapeCircle {
int get hashCode => radiusFraction.hashCode;
}
-
class QrPixelShapeRoundCorners extends QrPixelShape with ShapeRoundCorners {
- @override
- final double cornerFraction;
-
- @override
- bool get dependOnNeighbors => true;
+ @override
+ final double cornerFraction;
- const QrPixelShapeRoundCorners({
- this.cornerFraction = .5
- });
+ const QrPixelShapeRoundCorners({
+ this.cornerFraction = .5
+ });
- @override
- bool operator ==(Object other) => other is QrPixelShapeRoundCorners &&
- other.cornerFraction == cornerFraction;
+ @override
+ bool operator ==(Object other) =>
+ other is QrPixelShapeRoundCorners &&
+ other.cornerFraction == cornerFraction;
@override
int get hashCode => cornerFraction.hashCode;
diff --git a/lib/shapes/shape.dart b/lib/shapes/shape.dart
index 771e9b5..62e8980 100644
--- a/lib/shapes/shape.dart
+++ b/lib/shapes/shape.dart
@@ -4,55 +4,50 @@ import 'package:custom_qr_generator/util.dart';
import '../../neighbors.dart';
-abstract class Shape {
+abstract class QrElementShape {
- abstract final bool dependOnNeighbors;
+ Path createPath(Offset offset, double size, Neighbors neighbors);
- Path createPath(double size, Neighbors? neighbors);
-
- const Shape();
+ const QrElementShape();
}
-mixin ShapeRect implements Shape {
-
- @override
- bool get dependOnNeighbors => false;
+mixin ShapeRect implements QrElementShape {
@override
- Path createPath(double size, Neighbors? neighbors) => Path()
- ..addRect(Rect.fromLTRB(0, 0, size, size));
+ Path createPath(Offset offset, double size, Neighbors neighbors) => Path()
+ ..addRect(Rect.fromLTWH(offset.dx, offset.dy, size, size));
}
-mixin ShapeCircle implements Shape {
+mixin ShapeCircle implements QrElementShape {
abstract final double radiusFraction;
@override
- bool get dependOnNeighbors => false;
-
- @override
- Path createPath(double size, Neighbors? neighbors) {
- Path path = Path();
+ Path createPath(Offset offset, double size, Neighbors neighbors) {
double cSizeFraction = radiusFraction.coerceIn(0.0, 1.0);
double padding = size * (1 - cSizeFraction)/2;
- path.addOval(Rect.fromLTRB(padding, padding, size- padding, size-padding));
- return path;
+ var sSize = size - 2*padding;
+ return Path()
+ ..addOval(Rect.fromLTWH(offset.dx + padding, offset.dy + padding,sSize, sSize));
}
}
-mixin ShapeRoundCorners implements Shape {
+mixin ShapeRoundCorners implements QrElementShape {
abstract final double cornerFraction;
@override
- Path createPath(double size, Neighbors? neighbors) {
+ Path createPath(Offset offset, double size, Neighbors neighbors) {
Path path = Path();
double corner = cornerFraction.coerceIn(0, .5) * size;
-
- if (!dependOnNeighbors || neighbors == null || !neighbors.hasAny()){
- path.addRRect(RRect.fromLTRBR(0, 0, size, size, Radius.circular(corner)));
+ if (!neighbors.hasAny()){
+ path.addRRect(RRect.fromLTRBR(
+ offset.dx, offset.dy,
+ offset.dx + size, offset.dy + size,
+ Radius.circular(corner))
+ );
} else {
double topLeft =0;
@@ -73,7 +68,8 @@ mixin ShapeRoundCorners implements Shape {
bottomRight = corner;
}
- path.addRRect(RRect.fromLTRBAndCorners(0, 0, size, size,
+ path.addRRect(RRect.fromLTRBAndCorners(
+ offset.dx, offset.dy, offset.dx + size, offset.dy + size,
topLeft: Radius.circular(topLeft),
topRight: Radius.circular(topRight),
bottomLeft: Radius.circular(bottomLeft),
diff --git a/pubspec.lock b/pubspec.lock
index d1eeafe..ca9b728 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -7,7 +7,7 @@ packages:
name: async
url: "https://pub.dartlang.org"
source: hosted
- version: "2.8.1"
+ version: "2.9.0"
boolean_selector:
dependency: transitive
description:
@@ -21,14 +21,7 @@ packages:
name: characters
url: "https://pub.dartlang.org"
source: hosted
- version: "1.1.0"
- charcode:
- dependency: transitive
- description:
- name: charcode
- url: "https://pub.dartlang.org"
- source: hosted
- version: "1.3.1"
+ version: "1.2.1"
charset:
dependency: transitive
description:
@@ -42,21 +35,21 @@ packages:
name: clock
url: "https://pub.dartlang.org"
source: hosted
- version: "1.1.0"
+ version: "1.1.1"
collection:
dependency: transitive
description:
name: collection
url: "https://pub.dartlang.org"
source: hosted
- version: "1.15.0"
+ version: "1.16.0"
fake_async:
dependency: transitive
description:
name: fake_async
url: "https://pub.dartlang.org"
source: hosted
- version: "1.2.0"
+ version: "1.3.1"
flutter:
dependency: "direct main"
description: flutter
@@ -94,21 +87,28 @@ packages:
name: matcher
url: "https://pub.dartlang.org"
source: hosted
- version: "0.12.10"
+ version: "0.12.12"
+ material_color_utilities:
+ dependency: transitive
+ description:
+ name: material_color_utilities
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "0.1.5"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.dartlang.org"
source: hosted
- version: "1.7.0"
+ version: "1.8.0"
path:
dependency: transitive
description:
name: path
url: "https://pub.dartlang.org"
source: hosted
- version: "1.8.0"
+ version: "1.8.2"
sky_engine:
dependency: transitive
description: flutter
@@ -120,7 +120,7 @@ packages:
name: source_span
url: "https://pub.dartlang.org"
source: hosted
- version: "1.8.1"
+ version: "1.9.0"
stack_trace:
dependency: transitive
description:
@@ -141,35 +141,28 @@ packages:
name: string_scanner
url: "https://pub.dartlang.org"
source: hosted
- version: "1.1.0"
+ version: "1.1.1"
term_glyph:
dependency: transitive
description:
name: term_glyph
url: "https://pub.dartlang.org"
source: hosted
- version: "1.2.0"
+ version: "1.2.1"
test_api:
dependency: transitive
description:
name: test_api
url: "https://pub.dartlang.org"
source: hosted
- version: "0.4.2"
- typed_data:
- dependency: transitive
- description:
- name: typed_data
- url: "https://pub.dartlang.org"
- source: hosted
- version: "1.3.0"
+ version: "0.4.12"
vector_math:
dependency: transitive
description:
name: vector_math
url: "https://pub.dartlang.org"
source: hosted
- version: "2.1.0"
+ version: "2.1.2"
zxing_lib:
dependency: "direct main"
description:
@@ -178,5 +171,5 @@ packages:
source: hosted
version: "0.6.0"
sdks:
- dart: ">=2.14.0 <3.0.0"
+ dart: ">=2.17.0-0 <3.0.0"
flutter: ">=1.17.0"
diff --git a/pubspec.yaml b/pubspec.yaml
index 30bfec7..d0dae30 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,6 +1,6 @@
name: custom_qr_generator
description: Custom QR generator for Flutter
-version: 0.1.0
+version: 0.1.2
homepage: https://github.com/alexzhirkevich/custom-qr-generator-flutter
environment:
@@ -8,9 +8,9 @@ environment:
flutter: ">=1.17.0"
dependencies:
+ zxing_lib: ^0.6.0
flutter:
sdk: flutter
- zxing_lib: ^0.6.0
dev_dependencies:
flutter_test: