Committed by
GitHub
Merge pull request #679 from navaronbracke/fix_zxing_bug_on_web
fix: fix mobile scanner startup bug on web
Showing
21 changed files
with
186 additions
and
42 deletions
| 1 | # This file tracks properties of this Flutter project. | 1 | # This file tracks properties of this Flutter project. |
| 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. | 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. |
| 3 | # | 3 | # |
| 4 | -# This file should be version controlled and should not be manually edited. | 4 | +# This file should be version controlled. |
| 5 | 5 | ||
| 6 | version: | 6 | version: |
| 7 | - revision: 5f105a6ca7a5ac7b8bc9b241f4c2d86f4188cf5c | 7 | + revision: 796c8ef79279f9c774545b3771238c3098dbefab |
| 8 | channel: stable | 8 | channel: stable |
| 9 | 9 | ||
| 10 | project_type: plugin | 10 | project_type: plugin |
| 11 | + | ||
| 12 | +# Tracks metadata for the flutter migrate command | ||
| 13 | +migration: | ||
| 14 | + platforms: | ||
| 15 | + - platform: root | ||
| 16 | + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab | ||
| 17 | + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab | ||
| 18 | + - platform: android | ||
| 19 | + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab | ||
| 20 | + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab | ||
| 21 | + - platform: ios | ||
| 22 | + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab | ||
| 23 | + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab | ||
| 24 | + - platform: macos | ||
| 25 | + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab | ||
| 26 | + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab | ||
| 27 | + - platform: web | ||
| 28 | + create_revision: 796c8ef79279f9c774545b3771238c3098dbefab | ||
| 29 | + base_revision: 796c8ef79279f9c774545b3771238c3098dbefab | ||
| 30 | + | ||
| 31 | + # User provided section | ||
| 32 | + | ||
| 33 | + # List of Local paths (relative to this file) that should be | ||
| 34 | + # ignored by the migrate tool. | ||
| 35 | + # | ||
| 36 | + # Files that are not part of the templates will be ignored by default. | ||
| 37 | + unmanaged_files: | ||
| 38 | + - 'lib/main.dart' | ||
| 39 | + - 'ios/Runner.xcodeproj/project.pbxproj' |
| @@ -50,6 +50,7 @@ class _BarcodeListScannerWithControllerState | @@ -50,6 +50,7 @@ class _BarcodeListScannerWithControllerState | ||
| 50 | @override | 50 | @override |
| 51 | Widget build(BuildContext context) { | 51 | Widget build(BuildContext context) { |
| 52 | return Scaffold( | 52 | return Scaffold( |
| 53 | + appBar: AppBar(title: const Text('With ValueListenableBuilder')), | ||
| 53 | backgroundColor: Colors.black, | 54 | backgroundColor: Colors.black, |
| 54 | body: Builder( | 55 | body: Builder( |
| 55 | builder: (context) { | 56 | builder: (context) { |
| @@ -50,6 +50,7 @@ class _BarcodeScannerWithControllerState | @@ -50,6 +50,7 @@ class _BarcodeScannerWithControllerState | ||
| 50 | @override | 50 | @override |
| 51 | Widget build(BuildContext context) { | 51 | Widget build(BuildContext context) { |
| 52 | return Scaffold( | 52 | return Scaffold( |
| 53 | + appBar: AppBar(title: const Text('With controller')), | ||
| 53 | backgroundColor: Colors.black, | 54 | backgroundColor: Colors.black, |
| 54 | body: Builder( | 55 | body: Builder( |
| 55 | builder: (context) { | 56 | builder: (context) { |
| @@ -70,6 +70,7 @@ class _BarcodeScannerPageViewState extends State<BarcodeScannerPageView> | @@ -70,6 +70,7 @@ class _BarcodeScannerPageViewState extends State<BarcodeScannerPageView> | ||
| 70 | @override | 70 | @override |
| 71 | Widget build(BuildContext context) { | 71 | Widget build(BuildContext context) { |
| 72 | return Scaffold( | 72 | return Scaffold( |
| 73 | + appBar: AppBar(title: const Text('With PageView')), | ||
| 73 | backgroundColor: Colors.black, | 74 | backgroundColor: Colors.black, |
| 74 | body: PageView( | 75 | body: PageView( |
| 75 | children: [ | 76 | children: [ |
| @@ -52,6 +52,7 @@ class _BarcodeScannerReturningImageState | @@ -52,6 +52,7 @@ class _BarcodeScannerReturningImageState | ||
| 52 | @override | 52 | @override |
| 53 | Widget build(BuildContext context) { | 53 | Widget build(BuildContext context) { |
| 54 | return Scaffold( | 54 | return Scaffold( |
| 55 | + appBar: AppBar(title: const Text('Returning image')), | ||
| 55 | body: SafeArea( | 56 | body: SafeArea( |
| 56 | child: Column( | 57 | child: Column( |
| 57 | children: [ | 58 | children: [ |
| @@ -3,6 +3,8 @@ import 'dart:io'; | @@ -3,6 +3,8 @@ import 'dart:io'; | ||
| 3 | import 'package:flutter/material.dart'; | 3 | import 'package:flutter/material.dart'; |
| 4 | import 'package:mobile_scanner/mobile_scanner.dart'; | 4 | import 'package:mobile_scanner/mobile_scanner.dart'; |
| 5 | 5 | ||
| 6 | +import 'package:mobile_scanner_example/scanner_error_widget.dart'; | ||
| 7 | + | ||
| 6 | class BarcodeScannerWithScanWindow extends StatefulWidget { | 8 | class BarcodeScannerWithScanWindow extends StatefulWidget { |
| 7 | const BarcodeScannerWithScanWindow({Key? key}) : super(key: key); | 9 | const BarcodeScannerWithScanWindow({Key? key}) : super(key: key); |
| 8 | 10 | ||
| @@ -32,6 +34,7 @@ class _BarcodeScannerWithScanWindowState | @@ -32,6 +34,7 @@ class _BarcodeScannerWithScanWindowState | ||
| 32 | height: 200, | 34 | height: 200, |
| 33 | ); | 35 | ); |
| 34 | return Scaffold( | 36 | return Scaffold( |
| 37 | + appBar: AppBar(title: const Text('With Scan window')), | ||
| 35 | backgroundColor: Colors.black, | 38 | backgroundColor: Colors.black, |
| 36 | body: Builder( | 39 | body: Builder( |
| 37 | builder: (context) { | 40 | builder: (context) { |
| @@ -47,6 +50,9 @@ class _BarcodeScannerWithScanWindowState | @@ -47,6 +50,9 @@ class _BarcodeScannerWithScanWindowState | ||
| 47 | this.arguments = arguments; | 50 | this.arguments = arguments; |
| 48 | }); | 51 | }); |
| 49 | }, | 52 | }, |
| 53 | + errorBuilder: (context, error, child) { | ||
| 54 | + return ScannerErrorWidget(error: error); | ||
| 55 | + }, | ||
| 50 | onDetect: onDetect, | 56 | onDetect: onDetect, |
| 51 | ), | 57 | ), |
| 52 | if (barcode != null && | 58 | if (barcode != null && |
| @@ -18,6 +18,7 @@ class _BarcodeScannerWithoutControllerState | @@ -18,6 +18,7 @@ class _BarcodeScannerWithoutControllerState | ||
| 18 | @override | 18 | @override |
| 19 | Widget build(BuildContext context) { | 19 | Widget build(BuildContext context) { |
| 20 | return Scaffold( | 20 | return Scaffold( |
| 21 | + appBar: AppBar(title: const Text('Without controller')), | ||
| 21 | backgroundColor: Colors.black, | 22 | backgroundColor: Colors.black, |
| 22 | body: Builder( | 23 | body: Builder( |
| 23 | builder: (context) { | 24 | builder: (context) { |
| @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; | @@ -2,6 +2,8 @@ import 'package:flutter/material.dart'; | ||
| 2 | import 'package:image_picker/image_picker.dart'; | 2 | import 'package:image_picker/image_picker.dart'; |
| 3 | import 'package:mobile_scanner/mobile_scanner.dart'; | 3 | import 'package:mobile_scanner/mobile_scanner.dart'; |
| 4 | 4 | ||
| 5 | +import 'package:mobile_scanner_example/scanner_error_widget.dart'; | ||
| 6 | + | ||
| 5 | class BarcodeScannerWithZoom extends StatefulWidget { | 7 | class BarcodeScannerWithZoom extends StatefulWidget { |
| 6 | const BarcodeScannerWithZoom({Key? key}) : super(key: key); | 8 | const BarcodeScannerWithZoom({Key? key}) : super(key: key); |
| 7 | 9 | ||
| @@ -23,6 +25,7 @@ class _BarcodeScannerWithZoomState extends State<BarcodeScannerWithZoom> | @@ -23,6 +25,7 @@ class _BarcodeScannerWithZoomState extends State<BarcodeScannerWithZoom> | ||
| 23 | @override | 25 | @override |
| 24 | Widget build(BuildContext context) { | 26 | Widget build(BuildContext context) { |
| 25 | return Scaffold( | 27 | return Scaffold( |
| 28 | + appBar: AppBar(title: const Text('With zoom slider')), | ||
| 26 | backgroundColor: Colors.black, | 29 | backgroundColor: Colors.black, |
| 27 | body: Builder( | 30 | body: Builder( |
| 28 | builder: (context) { | 31 | builder: (context) { |
| @@ -31,6 +34,9 @@ class _BarcodeScannerWithZoomState extends State<BarcodeScannerWithZoom> | @@ -31,6 +34,9 @@ class _BarcodeScannerWithZoomState extends State<BarcodeScannerWithZoom> | ||
| 31 | MobileScanner( | 34 | MobileScanner( |
| 32 | controller: controller, | 35 | controller: controller, |
| 33 | fit: BoxFit.contain, | 36 | fit: BoxFit.contain, |
| 37 | + errorBuilder: (context, error, child) { | ||
| 38 | + return ScannerErrorWidget(error: error); | ||
| 39 | + }, | ||
| 34 | onDetect: (barcode) { | 40 | onDetect: (barcode) { |
| 35 | setState(() { | 41 | setState(() { |
| 36 | this.barcode = barcode; | 42 | this.barcode = barcode; |
| @@ -17,6 +17,9 @@ class ScannerErrorWidget extends StatelessWidget { | @@ -17,6 +17,9 @@ class ScannerErrorWidget extends StatelessWidget { | ||
| 17 | case MobileScannerErrorCode.permissionDenied: | 17 | case MobileScannerErrorCode.permissionDenied: |
| 18 | errorMessage = 'Permission denied'; | 18 | errorMessage = 'Permission denied'; |
| 19 | break; | 19 | break; |
| 20 | + case MobileScannerErrorCode.unsupported: | ||
| 21 | + errorMessage = 'Scanning is unsupported on this device'; | ||
| 22 | + break; | ||
| 20 | default: | 23 | default: |
| 21 | errorMessage = 'Generic Error'; | 24 | errorMessage = 'Generic Error'; |
| 22 | break; | 25 | break; |
example/web/icons/Icon-maskable-192.png
0 → 100644
5.46 KB
example/web/icons/Icon-maskable-512.png
0 → 100644
20.5 KB
| @@ -8,40 +8,53 @@ | @@ -8,40 +8,53 @@ | ||
| 8 | The path provided below has to start and end with a slash "/" in order for | 8 | The path provided below has to start and end with a slash "/" in order for |
| 9 | it to work correctly. | 9 | it to work correctly. |
| 10 | 10 | ||
| 11 | - Fore more details: | 11 | + For more details: |
| 12 | * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base | 12 | * https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base |
| 13 | + | ||
| 14 | + This is a placeholder for base href that will be replaced by the value of | ||
| 15 | + the `--base-href` argument provided to `flutter build`. | ||
| 13 | --> | 16 | --> |
| 14 | - <base href="/"> | 17 | + <base href="$FLUTTER_BASE_HREF"> |
| 15 | 18 | ||
| 16 | <meta charset="UTF-8"> | 19 | <meta charset="UTF-8"> |
| 17 | <meta content="IE=Edge" http-equiv="X-UA-Compatible"> | 20 | <meta content="IE=Edge" http-equiv="X-UA-Compatible"> |
| 18 | - <meta name="description" content="A new Flutter project."> | 21 | + <meta name="description" content="Demonstrates how to use the mobile_scanner plugin."> |
| 19 | 22 | ||
| 20 | <!-- iOS meta tags & icons --> | 23 | <!-- iOS meta tags & icons --> |
| 21 | <meta name="apple-mobile-web-app-capable" content="yes"> | 24 | <meta name="apple-mobile-web-app-capable" content="yes"> |
| 22 | <meta name="apple-mobile-web-app-status-bar-style" content="black"> | 25 | <meta name="apple-mobile-web-app-status-bar-style" content="black"> |
| 23 | - <meta name="apple-mobile-web-app-title" content="example"> | 26 | + <meta name="apple-mobile-web-app-title" content="mobile_scanner_example"> |
| 24 | <link rel="apple-touch-icon" href="icons/Icon-192.png"> | 27 | <link rel="apple-touch-icon" href="icons/Icon-192.png"> |
| 25 | 28 | ||
| 26 | <!-- Favicon --> | 29 | <!-- Favicon --> |
| 27 | <link rel="icon" type="image/png" href="favicon.png"/> | 30 | <link rel="icon" type="image/png" href="favicon.png"/> |
| 28 | 31 | ||
| 29 | - <title>example</title> | 32 | + <title>mobile_scanner_example</title> |
| 30 | <link rel="manifest" href="manifest.json"> | 33 | <link rel="manifest" href="manifest.json"> |
| 34 | + | ||
| 35 | + <script> | ||
| 36 | + // The value below is injected by flutter build, do not touch. | ||
| 37 | + var serviceWorkerVersion = null; | ||
| 38 | + </script> | ||
| 39 | + <!-- This script adds the flutter initialization JS code --> | ||
| 40 | + <script src="flutter.js" defer></script> | ||
| 31 | </head> | 41 | </head> |
| 32 | <body> | 42 | <body> |
| 33 | <script src="https://unpkg.com/@zxing/library@0.19.1" type="application/javascript"></script> | 43 | <script src="https://unpkg.com/@zxing/library@0.19.1" type="application/javascript"></script> |
| 34 | - | ||
| 35 | - <!-- This script installs service_worker.js to provide PWA functionality to | ||
| 36 | - application. For more information, see: | ||
| 37 | - https://developers.google.com/web/fundamentals/primers/service-workers --> | ||
| 38 | <script> | 44 | <script> |
| 39 | - if ('serviceWorker' in navigator) { | ||
| 40 | - window.addEventListener('flutter-first-frame', function () { | ||
| 41 | - navigator.serviceWorker.register('flutter_service_worker.js'); | 45 | + window.addEventListener('load', function(ev) { |
| 46 | + // Download main.dart.js | ||
| 47 | + _flutter.loader.loadEntrypoint({ | ||
| 48 | + serviceWorker: { | ||
| 49 | + serviceWorkerVersion: serviceWorkerVersion, | ||
| 50 | + }, | ||
| 51 | + onEntrypointLoaded: function(engineInitializer) { | ||
| 52 | + engineInitializer.initializeEngine().then(function(appRunner) { | ||
| 53 | + appRunner.runApp(); | ||
| 54 | + }); | ||
| 55 | + } | ||
| 42 | }); | 56 | }); |
| 43 | - } | 57 | + }); |
| 44 | </script> | 58 | </script> |
| 45 | - <script src="main.dart.js" type="application/javascript"></script> | ||
| 46 | </body> | 59 | </body> |
| 47 | </html> | 60 | </html> |
| 1 | { | 1 | { |
| 2 | - "name": "Mobile Scanner Example", | 2 | + "name": "mobile_scanner_example", |
| 3 | "short_name": "mobile_scanner_example", | 3 | "short_name": "mobile_scanner_example", |
| 4 | "start_url": ".", | 4 | "start_url": ".", |
| 5 | "display": "standalone", | 5 | "display": "standalone", |
| 6 | "background_color": "#0175C2", | 6 | "background_color": "#0175C2", |
| 7 | "theme_color": "#0175C2", | 7 | "theme_color": "#0175C2", |
| 8 | - "description": "A barcode and qr code scanner example.", | 8 | + "description": "Demonstrates how to use the mobile_scanner plugin.", |
| 9 | "orientation": "portrait-primary", | 9 | "orientation": "portrait-primary", |
| 10 | "prefer_related_applications": false, | 10 | "prefer_related_applications": false, |
| 11 | "icons": [ | 11 | "icons": [ |
| @@ -18,6 +18,18 @@ | @@ -18,6 +18,18 @@ | ||
| 18 | "src": "icons/Icon-512.png", | 18 | "src": "icons/Icon-512.png", |
| 19 | "sizes": "512x512", | 19 | "sizes": "512x512", |
| 20 | "type": "image/png" | 20 | "type": "image/png" |
| 21 | + }, | ||
| 22 | + { | ||
| 23 | + "src": "icons/Icon-maskable-192.png", | ||
| 24 | + "sizes": "192x192", | ||
| 25 | + "type": "image/png", | ||
| 26 | + "purpose": "maskable" | ||
| 27 | + }, | ||
| 28 | + { | ||
| 29 | + "src": "icons/Icon-maskable-512.png", | ||
| 30 | + "sizes": "512x512", | ||
| 31 | + "type": "image/png", | ||
| 32 | + "purpose": "maskable" | ||
| 21 | } | 33 | } |
| 22 | ] | 34 | ] |
| 23 | } | 35 | } |
| @@ -61,6 +61,8 @@ class MobileScannerWebPlugin { | @@ -61,6 +61,8 @@ class MobileScannerWebPlugin { | ||
| 61 | return _torch(call.arguments); | 61 | return _torch(call.arguments); |
| 62 | case 'stop': | 62 | case 'stop': |
| 63 | return cancel(); | 63 | return cancel(); |
| 64 | + case 'updateScanWindow': | ||
| 65 | + return Future<void>.value(); | ||
| 64 | default: | 66 | default: |
| 65 | throw PlatformException( | 67 | throw PlatformException( |
| 66 | code: 'Unimplemented', | 68 | code: 'Unimplemented', |
| @@ -111,12 +113,14 @@ class MobileScannerWebPlugin { | @@ -111,12 +113,14 @@ class MobileScannerWebPlugin { | ||
| 111 | .map((e) => toFormat(e)) | 113 | .map((e) => toFormat(e)) |
| 112 | .toList(); | 114 | .toList(); |
| 113 | } | 115 | } |
| 116 | + | ||
| 114 | final Duration? detectionTimeout; | 117 | final Duration? detectionTimeout; |
| 115 | if (arguments.containsKey('timeout')) { | 118 | if (arguments.containsKey('timeout')) { |
| 116 | detectionTimeout = Duration(milliseconds: arguments['timeout'] as int); | 119 | detectionTimeout = Duration(milliseconds: arguments['timeout'] as int); |
| 117 | } else { | 120 | } else { |
| 118 | detectionTimeout = null; | 121 | detectionTimeout = null; |
| 119 | } | 122 | } |
| 123 | + | ||
| 120 | await barCodeReader.start( | 124 | await barCodeReader.start( |
| 121 | cameraFacing: cameraFacing, | 125 | cameraFacing: cameraFacing, |
| 122 | formats: formats, | 126 | formats: formats, |
| @@ -126,20 +130,31 @@ class MobileScannerWebPlugin { | @@ -126,20 +130,31 @@ class MobileScannerWebPlugin { | ||
| 126 | _barCodeStreamSubscription = | 130 | _barCodeStreamSubscription = |
| 127 | barCodeReader.detectBarcodeContinuously().listen((code) { | 131 | barCodeReader.detectBarcodeContinuously().listen((code) { |
| 128 | if (code != null) { | 132 | if (code != null) { |
| 133 | + final List<Offset>? corners = code.corners; | ||
| 134 | + | ||
| 129 | controller.add({ | 135 | controller.add({ |
| 130 | 'name': 'barcodeWeb', | 136 | 'name': 'barcodeWeb', |
| 131 | 'data': { | 137 | 'data': { |
| 132 | 'rawValue': code.rawValue, | 138 | 'rawValue': code.rawValue, |
| 133 | 'rawBytes': code.rawBytes, | 139 | 'rawBytes': code.rawBytes, |
| 134 | 'format': code.format.rawValue, | 140 | 'format': code.format.rawValue, |
| 141 | + 'displayValue': code.displayValue, | ||
| 142 | + 'type': code.type.index, | ||
| 143 | + if (corners != null && corners.isNotEmpty) | ||
| 144 | + 'corners': corners | ||
| 145 | + .map( | ||
| 146 | + (Offset c) => <Object?, Object?>{'x': c.dx, 'y': c.dy}, | ||
| 147 | + ) | ||
| 148 | + .toList(), | ||
| 135 | }, | 149 | }, |
| 136 | }); | 150 | }); |
| 137 | } | 151 | } |
| 138 | }); | 152 | }); |
| 153 | + | ||
| 139 | final hasTorch = await barCodeReader.hasTorch(); | 154 | final hasTorch = await barCodeReader.hasTorch(); |
| 140 | 155 | ||
| 141 | if (hasTorch && arguments.containsKey('torch')) { | 156 | if (hasTorch && arguments.containsKey('torch')) { |
| 142 | - barCodeReader.toggleTorch(enabled: arguments['torch'] as bool); | 157 | + await barCodeReader.toggleTorch(enabled: arguments['torch'] as bool); |
| 143 | } | 158 | } |
| 144 | 159 | ||
| 145 | return { | 160 | return { |
| @@ -148,8 +163,12 @@ class MobileScannerWebPlugin { | @@ -148,8 +163,12 @@ class MobileScannerWebPlugin { | ||
| 148 | 'videoHeight': barCodeReader.videoHeight, | 163 | 'videoHeight': barCodeReader.videoHeight, |
| 149 | 'torchable': hasTorch, | 164 | 'torchable': hasTorch, |
| 150 | }; | 165 | }; |
| 151 | - } catch (e) { | ||
| 152 | - throw PlatformException(code: 'MobileScannerWeb', message: '$e'); | 166 | + } catch (e, stackTrace) { |
| 167 | + throw PlatformException( | ||
| 168 | + code: 'MobileScannerWeb', | ||
| 169 | + message: '$e', | ||
| 170 | + details: stackTrace.toString(), | ||
| 171 | + ); | ||
| 153 | } | 172 | } |
| 154 | } | 173 | } |
| 155 | 174 |
| @@ -9,14 +9,16 @@ Size toSize(Map data) { | @@ -9,14 +9,16 @@ Size toSize(Map data) { | ||
| 9 | return Size(width, height); | 9 | return Size(width, height); |
| 10 | } | 10 | } |
| 11 | 11 | ||
| 12 | -List<Offset>? toCorners(List? data) { | ||
| 13 | - if (data != null) { | ||
| 14 | - return List.unmodifiable( | ||
| 15 | - data.map((e) => Offset((e as Map)['x'] as double, e['y'] as double)), | ||
| 16 | - ); | ||
| 17 | - } else { | 12 | +List<Offset>? toCorners(List<Map<Object?, Object?>>? data) { |
| 13 | + if (data == null) { | ||
| 18 | return null; | 14 | return null; |
| 19 | } | 15 | } |
| 16 | + | ||
| 17 | + return List.unmodifiable( | ||
| 18 | + data.map((Map<Object?, Object?> e) { | ||
| 19 | + return Offset(e['x']! as double, e['y']! as double); | ||
| 20 | + }), | ||
| 21 | + ); | ||
| 20 | } | 22 | } |
| 21 | 23 | ||
| 22 | BarcodeFormat toFormat(int value) { | 24 | BarcodeFormat toFormat(int value) { |
| @@ -11,4 +11,7 @@ enum MobileScannerErrorCode { | @@ -11,4 +11,7 @@ enum MobileScannerErrorCode { | ||
| 11 | 11 | ||
| 12 | /// The permission to use the camera was denied. | 12 | /// The permission to use the camera was denied. |
| 13 | permissionDenied, | 13 | permissionDenied, |
| 14 | + | ||
| 15 | + /// Scanning is unsupported on the current device. | ||
| 16 | + unsupported, | ||
| 14 | } | 17 | } |
| @@ -132,7 +132,6 @@ class _MobileScannerState extends State<MobileScanner> | @@ -132,7 +132,6 @@ class _MobileScannerState extends State<MobileScanner> | ||
| 132 | widget.onStart?.call(arguments); | 132 | widget.onStart?.call(arguments); |
| 133 | widget.onScannerStarted?.call(arguments); | 133 | widget.onScannerStarted?.call(arguments); |
| 134 | }).catchError((error) { | 134 | }).catchError((error) { |
| 135 | - debugPrint('mobile_scanner: $error'); | ||
| 136 | if (mounted) { | 135 | if (mounted) { |
| 137 | setState(() { | 136 | setState(() { |
| 138 | _startException = error as MobileScannerException; | 137 | _startException = error as MobileScannerException; |
| @@ -207,9 +207,21 @@ class MobileScannerController { | @@ -207,9 +207,21 @@ class MobileScannerController { | ||
| 207 | } on PlatformException catch (error) { | 207 | } on PlatformException catch (error) { |
| 208 | MobileScannerErrorCode errorCode = MobileScannerErrorCode.genericError; | 208 | MobileScannerErrorCode errorCode = MobileScannerErrorCode.genericError; |
| 209 | 209 | ||
| 210 | - if (error.code == "MobileScannerWeb") { | ||
| 211 | - errorCode = MobileScannerErrorCode.permissionDenied; | 210 | + final String? errorMessage = error.message; |
| 211 | + | ||
| 212 | + if (kIsWeb) { | ||
| 213 | + if (errorMessage == null) { | ||
| 214 | + errorCode = MobileScannerErrorCode.genericError; | ||
| 215 | + } else if (errorMessage.contains('NotFoundError') || | ||
| 216 | + errorMessage.contains('NotSupportedError')) { | ||
| 217 | + errorCode = MobileScannerErrorCode.unsupported; | ||
| 218 | + } else if (errorMessage.contains('NotAllowedError')) { | ||
| 219 | + errorCode = MobileScannerErrorCode.permissionDenied; | ||
| 220 | + } else { | ||
| 221 | + errorCode = MobileScannerErrorCode.genericError; | ||
| 222 | + } | ||
| 212 | } | 223 | } |
| 224 | + | ||
| 213 | isStarting = false; | 225 | isStarting = false; |
| 214 | 226 | ||
| 215 | throw MobileScannerException( | 227 | throw MobileScannerException( |
| @@ -388,6 +400,10 @@ class MobileScannerController { | @@ -388,6 +400,10 @@ class MobileScannerController { | ||
| 388 | rawValue: barcode['rawValue'] as String?, | 400 | rawValue: barcode['rawValue'] as String?, |
| 389 | rawBytes: barcode['rawBytes'] as Uint8List?, | 401 | rawBytes: barcode['rawBytes'] as Uint8List?, |
| 390 | format: toFormat(barcode['format'] as int), | 402 | format: toFormat(barcode['format'] as int), |
| 403 | + corners: toCorners( | ||
| 404 | + (barcode['corners'] as List<Object?>? ?? []) | ||
| 405 | + .cast<Map<Object?, Object?>>(), | ||
| 406 | + ), | ||
| 391 | ), | 407 | ), |
| 392 | ], | 408 | ], |
| 393 | ), | 409 | ), |
| @@ -92,7 +92,9 @@ class Barcode { | @@ -92,7 +92,9 @@ class Barcode { | ||
| 92 | 92 | ||
| 93 | /// Create a [Barcode] from native data. | 93 | /// Create a [Barcode] from native data. |
| 94 | Barcode.fromNative(Map data) | 94 | Barcode.fromNative(Map data) |
| 95 | - : corners = toCorners(data['corners'] as List?), | 95 | + : corners = toCorners( |
| 96 | + (data['corners'] as List?)?.cast<Map<Object?, Object?>>(), | ||
| 97 | + ), | ||
| 96 | format = toFormat(data['format'] as int), | 98 | format = toFormat(data['format'] as int), |
| 97 | rawBytes = data['rawBytes'] as Uint8List?, | 99 | rawBytes = data['rawBytes'] as Uint8List?, |
| 98 | rawValue = data['rawValue'] as String?, | 100 | rawValue = data['rawValue'] as String?, |
| @@ -201,18 +203,20 @@ class ContactInfo { | @@ -201,18 +203,20 @@ class ContactInfo { | ||
| 201 | /// Create a [ContactInfo] from native data. | 203 | /// Create a [ContactInfo] from native data. |
| 202 | ContactInfo.fromNative(Map data) | 204 | ContactInfo.fromNative(Map data) |
| 203 | : addresses = List.unmodifiable( | 205 | : addresses = List.unmodifiable( |
| 204 | - (data['addresses'] as List).map((e) => Address.fromNative(e as Map)), | 206 | + (data['addresses'] as List? ?? []) |
| 207 | + .cast<Map>() | ||
| 208 | + .map(Address.fromNative), | ||
| 205 | ), | 209 | ), |
| 206 | emails = List.unmodifiable( | 210 | emails = List.unmodifiable( |
| 207 | - (data['emails'] as List).map((e) => Email.fromNative(e as Map)), | 211 | + (data['emails'] as List? ?? []).cast<Map>().map(Email.fromNative), |
| 208 | ), | 212 | ), |
| 209 | name = toName(data['name'] as Map?), | 213 | name = toName(data['name'] as Map?), |
| 210 | organization = data['organization'] as String?, | 214 | organization = data['organization'] as String?, |
| 211 | phones = List.unmodifiable( | 215 | phones = List.unmodifiable( |
| 212 | - (data['phones'] as List).map((e) => Phone.fromNative(e as Map)), | 216 | + (data['phones'] as List? ?? []).cast<Map>().map(Phone.fromNative), |
| 213 | ), | 217 | ), |
| 214 | title = data['title'] as String?, | 218 | title = data['title'] as String?, |
| 215 | - urls = List.unmodifiable(data['urls'] as List); | 219 | + urls = List.unmodifiable((data['urls'] as List? ?? []).cast<String>()); |
| 216 | } | 220 | } |
| 217 | 221 | ||
| 218 | /// An address. | 222 | /// An address. |
| @@ -227,7 +231,9 @@ class Address { | @@ -227,7 +231,9 @@ class Address { | ||
| 227 | 231 | ||
| 228 | /// Create a [Address] from native data. | 232 | /// Create a [Address] from native data. |
| 229 | Address.fromNative(Map data) | 233 | Address.fromNative(Map data) |
| 230 | - : addressLines = List.unmodifiable(data['addressLines'] as List), | 234 | + : addressLines = List.unmodifiable( |
| 235 | + (data['addressLines'] as List? ?? []).cast<String>(), | ||
| 236 | + ), | ||
| 231 | type = AddressType.values[data['type'] as int]; | 237 | type = AddressType.values[data['type'] as int]; |
| 232 | } | 238 | } |
| 233 | 239 |
| @@ -125,10 +125,8 @@ mixin InternalTorchDetection on InternalStreamCreation { | @@ -125,10 +125,8 @@ mixin InternalTorchDetection on InternalStreamCreation { | ||
| 125 | final photoCapabilities = await promiseToFuture<PhotoCapabilities>( | 125 | final photoCapabilities = await promiseToFuture<PhotoCapabilities>( |
| 126 | imageCapture.getPhotoCapabilities(), | 126 | imageCapture.getPhotoCapabilities(), |
| 127 | ); | 127 | ); |
| 128 | - final fillLightMode = photoCapabilities.fillLightMode; | ||
| 129 | - if (fillLightMode != null) { | ||
| 130 | - return fillLightMode; | ||
| 131 | - } | 128 | + |
| 129 | + return photoCapabilities.fillLightMode; | ||
| 132 | } | 130 | } |
| 133 | } catch (e) { | 131 | } catch (e) { |
| 134 | // ImageCapture is not supported by some browsers: | 132 | // ImageCapture is not supported by some browsers: |
| @@ -162,9 +160,16 @@ class Promise<T> {} | @@ -162,9 +160,16 @@ class Promise<T> {} | ||
| 162 | 160 | ||
| 163 | @JS() | 161 | @JS() |
| 164 | @anonymous | 162 | @anonymous |
| 165 | -class PhotoCapabilities { | 163 | +@staticInterop |
| 164 | +class PhotoCapabilities {} | ||
| 165 | + | ||
| 166 | +extension PhotoCapabilitiesExtension on PhotoCapabilities { | ||
| 167 | + @JS('fillLightMode') | ||
| 168 | + external List<dynamic>? get _fillLightMode; | ||
| 169 | + | ||
| 166 | /// Returns an array of available fill light options. Options include auto, off, or flash. | 170 | /// Returns an array of available fill light options. Options include auto, off, or flash. |
| 167 | - external List<String>? get fillLightMode; | 171 | + List<String> get fillLightMode => |
| 172 | + _fillLightMode?.cast<String>() ?? <String>[]; | ||
| 168 | } | 173 | } |
| 169 | 174 | ||
| 170 | @JS('ImageCapture') | 175 | @JS('ImageCapture') |
| 1 | import 'dart:async'; | 1 | import 'dart:async'; |
| 2 | import 'dart:html'; | 2 | import 'dart:html'; |
| 3 | import 'dart:typed_data'; | 3 | import 'dart:typed_data'; |
| 4 | +import 'dart:ui'; | ||
| 4 | 5 | ||
| 5 | import 'package:js/js.dart'; | 6 | import 'package:js/js.dart'; |
| 6 | import 'package:mobile_scanner/src/enums/camera_facing.dart'; | 7 | import 'package:mobile_scanner/src/enums/camera_facing.dart'; |
| @@ -19,6 +20,16 @@ class JsZXingBrowserMultiFormatReader { | @@ -19,6 +20,16 @@ class JsZXingBrowserMultiFormatReader { | ||
| 19 | 20 | ||
| 20 | @JS() | 21 | @JS() |
| 21 | @anonymous | 22 | @anonymous |
| 23 | +abstract class ResultPoint { | ||
| 24 | + /// The x coordinate of the point. | ||
| 25 | + external double get x; | ||
| 26 | + | ||
| 27 | + /// The y coordinate of the point. | ||
| 28 | + external double get y; | ||
| 29 | +} | ||
| 30 | + | ||
| 31 | +@JS() | ||
| 32 | +@anonymous | ||
| 22 | abstract class Result { | 33 | abstract class Result { |
| 23 | /// raw text encoded by the barcode | 34 | /// raw text encoded by the barcode |
| 24 | external String get text; | 35 | external String get text; |
| @@ -28,15 +39,24 @@ abstract class Result { | @@ -28,15 +39,24 @@ abstract class Result { | ||
| 28 | 39 | ||
| 29 | /// Representing the format of the barcode that was decoded | 40 | /// Representing the format of the barcode that was decoded |
| 30 | external int? format; | 41 | external int? format; |
| 42 | + | ||
| 43 | + /// Returns the result points of the barcode. These points represent the corners of the barcode. | ||
| 44 | + external List<Object?> get resultPoints; | ||
| 31 | } | 45 | } |
| 32 | 46 | ||
| 33 | extension ResultExt on Result { | 47 | extension ResultExt on Result { |
| 34 | Barcode toBarcode() { | 48 | Barcode toBarcode() { |
| 49 | + final corners = resultPoints | ||
| 50 | + .cast<ResultPoint>() | ||
| 51 | + .map((ResultPoint rp) => Offset(rp.x, rp.y)) | ||
| 52 | + .toList(); | ||
| 53 | + | ||
| 35 | final rawBytes = this.rawBytes; | 54 | final rawBytes = this.rawBytes; |
| 36 | return Barcode( | 55 | return Barcode( |
| 37 | rawValue: text, | 56 | rawValue: text, |
| 38 | rawBytes: rawBytes != null ? Uint8List.fromList(rawBytes) : null, | 57 | rawBytes: rawBytes != null ? Uint8List.fromList(rawBytes) : null, |
| 39 | format: barcodeFormat, | 58 | format: barcodeFormat, |
| 59 | + corners: corners, | ||
| 40 | ); | 60 | ); |
| 41 | } | 61 | } |
| 42 | 62 |
-
Please register or login to post a comment