Toggle navigation
Toggle navigation
This project
Loading...
Sign in
flutter_package
/
mobile_scanner
Go to a project
Toggle navigation
Projects
Groups
Snippets
Help
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
Julian Steenbakker
2022-03-03 17:33:34 +0100
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
9c52dacb0e2c25ccf087cacc93b89faf19113e97
9c52dacb
1 parent
c08c6a00
refactor: web version of mobile_scanner
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
119 additions
and
187 deletions
example/web/index.html
example/web/manifest.json
lib/src/mobile_scanner.dart
lib/src/mobile_scanner_controller.dart
lib/src/web/flutter_qr_stub.dart
lib/src/web/flutter_qr_web.dart
lib/src/web/media.dart
lib/src/web/qr-scanner.dart
example/web/index.html
View file @
9c52dac
...
...
@@ -28,6 +28,7 @@
<title>
example
</title>
<link
rel=
"manifest"
href=
"manifest.json"
>
<!-- <script src="https://cdn.jsdelivr.net/npm/qr-scanner@1.4.1/qr-scanner.min.js"></script>-->
<script
src=
"https://cdn.jsdelivr.net/npm/jsqr@1.4.0/dist/jsQR.min.js"
></script>
</head>
<body>
...
...
example/web/manifest.json
View file @
9c52dac
{
"name"
:
"example"
,
"short_name"
:
"example"
,
"name"
:
"Mobile Scanner Example"
,
"short_name"
:
"mobile_scanner_example"
,
"start_url"
:
"."
,
"display"
:
"standalone"
,
"background_color"
:
"#0175C2"
,
"theme_color"
:
"#0175C2"
,
"description"
:
"A
new Flutter project
."
,
"description"
:
"A
barcode and qr code scanner example
."
,
"orientation"
:
"portrait-primary"
,
"prefer_related_applications"
:
false
,
"icons"
:
[
...
...
lib/src/mobile_scanner.dart
View file @
9c52dac
import
'package:flutter/foundation.dart'
;
import
'package:flutter/material.dart'
;
import
'package:mobile_scanner/mobile_scanner.dart'
;
...
...
@@ -67,7 +68,7 @@ class _MobileScannerState extends State<MobileScanner>
@override
Widget
build
(
BuildContext
context
)
{
if
(
kIsWeb
)
{
return
createWebQrView
(
return
WebScanner
(
onDetect:
(
barcode
)
=>
widget
.
onDetect
!(
barcode
,
null
),
cameraFacing:
CameraFacing
.
back
,
);
...
...
@@ -105,7 +106,6 @@ class _MobileScannerState extends State<MobileScanner>
);
}
});
}
});
}
}
...
...
lib/src/mobile_scanner_controller.dart
View file @
9c52dac
...
...
@@ -4,6 +4,7 @@ import 'package:flutter/cupertino.dart';
import
'package:flutter/services.dart'
;
import
'package:mobile_scanner/mobile_scanner.dart'
;
import
'mobile_scanner_arguments.dart'
;
import
'objects/barcode_utility.dart'
;
/// The facing of a camera.
...
...
lib/src/web/flutter_qr_stub.dart
deleted
100644 → 0
View file @
c08c6a0
// import 'package:flutter/material.dart';
// import 'package:qr_code_scanner/src/types/camera.dart';
//
// Widget createWebQrView({onPlatformViewCreated, CameraFacing? cameraFacing}) =>
// const SizedBox();
lib/src/web/flutter_qr_web.dart
View file @
9c52dac
...
...
@@ -3,7 +3,6 @@
import
'dart:async'
;
import
'dart:core'
;
import
'dart:html'
as
html
;
import
'dart:js_util'
;
import
'dart:ui'
as
ui
;
import
'package:flutter/material.dart'
;
...
...
@@ -18,21 +17,21 @@ import 'media.dart';
/// Copyright 2020 @treeder
/// Copyright 2021 The one with the braid
class
Web
QrView
extends
StatefulWidget
{
class
Web
Scanner
extends
StatefulWidget
{
final
Function
(
Barcode
)
onDetect
;
final
CameraFacing
?
cameraFacing
;
const
Web
QrView
(
const
Web
Scanner
(
{
Key
?
key
,
required
this
.
onDetect
,
this
.
cameraFacing
=
CameraFacing
.
front
})
:
super
(
key:
key
);
@override
_Web
QrViewState
createState
()
=>
_WebQrView
State
();
_Web
ScannerState
createState
()
=>
_WebScanner
State
();
static
html
.
DivElement
vidDiv
=
html
.
DivElement
();
// need a global for the registerViewFactory
// need a global for the registerViewFactory
static
html
.
DivElement
vidDiv
=
html
.
DivElement
();
static
Future
<
bool
>
cameraAvailable
()
async
{
final
sources
=
...
...
@@ -49,50 +48,65 @@ class WebQrView extends StatefulWidget {
}
}
class
_WebQrViewState
extends
State
<
WebQrView
>
{
class
_WebScannerState
extends
State
<
WebScanner
>
{
// Which way the camera is facing
// late CameraFacing facing;
// The camera stream to display to the user
html
.
MediaStream
?
_localStream
;
// html.CanvasElement canvas;
// html.CanvasRenderingContext2D ctx;
// Check if analyzer is processing barcode
bool
_currentlyProcessing
=
false
;
// QRViewControllerWeb? _controller;
late
Size
_size
=
const
Size
(
0
,
0
);
// Set size of the webview
// Size _size = const Size(0, 0);
// TODO: Timer for capture?
Timer
?
timer
;
String
?
code
;
// String? code;
// TODO: Error message if error
String
?
_errorMsg
;
// Video element to be played on
html
.
VideoElement
video
=
html
.
VideoElement
();
String
viewID
=
'QRVIEW-'
+
DateTime
.
now
().
millisecondsSinceEpoch
.
toString
();
final
StreamController
<
Barcode
>
_scanUpdateController
=
StreamController
<
Barcode
>();
late
CameraFacing
facing
;
// ID of the video feed
String
viewID
=
'WebScanner-'
+
DateTime
.
now
().
millisecondsSinceEpoch
.
toString
();
// final StreamController<Barcode> _scanUpdateController =
// StreamController<Barcode>();
// Timer for interval capture
Timer
?
_frameIntervall
;
@override
void
initState
()
{
super
.
initState
();
// facing = widget.cameraFacing ?? CameraFacing.front;
WebScanner
.
vidDiv
.
children
=
[
video
];
facing
=
widget
.
cameraFacing
??
CameraFacing
.
front
;
// video = html.VideoElement();
WebQrView
.
vidDiv
.
children
=
[
video
];
// ignore: UNDEFINED_PREFIXED_NAME
ui
.
platformViewRegistry
.
registerViewFactory
(
viewID
,
(
int
id
)
=>
WebQrView
.
vidDiv
);
.
registerViewFactory
(
viewID
,
(
int
id
)
=>
WebScanner
.
vidDiv
);
// giving JavaScipt some time to process the DOM changes
Timer
(
const
Duration
(
milliseconds:
500
),
()
{
start
();
});
}
/// Initialize camera and capture frame
Future
start
()
async
{
await
_
makeCall
();
await
_
startVideoStream
();
_frameIntervall
?.
cancel
();
_frameIntervall
=
Timer
.
periodic
(
const
Duration
(
milliseconds:
200
),
(
timer
)
{
_captureFrame
2
();
_captureFrame
();
});
}
...
...
@@ -102,7 +116,7 @@ class _WebQrViewState extends State<WebQrView> {
timer
=
null
;
}
if
(
_currentlyProcessing
)
{
_stopStream
();
_stop
Video
Stream
();
}
}
...
...
@@ -112,30 +126,42 @@ class _WebQrViewState extends State<WebQrView> {
super
.
dispose
();
}
// Platform messages are asynchronous, so we initialize in an async method.
Future
<
void
>
_makeCall
()
async
{
if
(
_localStream
!=
null
)
{
return
;
}
/// Starts a video stream if not started already
Future
<
void
>
_startVideoStream
()
async
{
// Check if stream is running
if
(
_localStream
!=
null
)
return
;
try
{
var
constraints
=
UserMediaOptions
(
video:
VideoOptions
(
facingMode:
(
facing
==
CameraFacing
.
front
?
'user'
:
'environment'
),
));
// dart style, not working properly:
// var stream =
// await html.window.navigator.mediaDevices.getUserMedia(constraints);
// straight JS:
var
stream
=
await
promiseToFuture
(
getUserMedia
(
constraints
));
_localStream
=
stream
;
// Check if browser supports multiple camera's and set if supported
Map
?
capabilities
=
html
.
window
.
navigator
.
mediaDevices
?.
getSupportedConstraints
();
if
(
capabilities
!=
null
&&
capabilities
[
'facingMode'
])
{
UserMediaOptions
constraints
=
UserMediaOptions
(
video:
VideoOptions
(
facingMode:
(
widget
.
cameraFacing
==
CameraFacing
.
front
?
'user'
:
'environment'
),
width:
{
'ideal'
:
4096
},
height:
{
'ideal'
:
2160
},
));
_localStream
=
await
html
.
window
.
navigator
.
getUserMedia
(
video:
constraints
);
}
else
{
_localStream
=
await
html
.
window
.
navigator
.
getUserMedia
(
video:
true
);
}
video
.
srcObject
=
_localStream
;
video
.
setAttribute
(
'playsinline'
,
'true'
);
// required to tell iOS safari we don't want fullscreen
// required to tell iOS safari we don't want fullscreen
video
.
setAttribute
(
'playsinline'
,
'true'
);
// TODO: Check controller
// if (_controller == null) {
// _controller = QRViewControllerWeb(this);
// widget.onPlatformViewCreated(_controller!);
// }
await
video
.
play
();
}
catch
(
e
)
{
cancel
();
...
...
@@ -144,6 +170,7 @@ class _WebQrViewState extends State<WebQrView> {
});
return
;
}
if
(!
mounted
)
return
;
setState
(()
{
...
...
@@ -151,45 +178,43 @@ class _WebQrViewState extends State<WebQrView> {
});
}
Future
<
void
>
_stopStream
()
async
{
Future
<
void
>
_stop
Video
Stream
()
async
{
try
{
//
await _localStream.dispose();
//
Stop the camera stream
_localStream
!.
getTracks
().
forEach
((
track
)
{
if
(
track
.
readyState
==
'live'
)
{
track
.
stop
();
}
});
// video.stop();
video
.
srcObject
=
null
;
_localStream
=
null
;
// _localRenderer.srcObject = null;
// ignore: empty_catches
}
catch
(
e
)
{}
}
catch
(
e
)
{
debugPrint
(
'Failed to stop stream:
$e
'
);
}
}
Future
<
dynamic
>
_captureFrame2
()
async
{
if
(
_localStream
==
null
)
{
return
null
;
}
final
canvas
=
html
.
CanvasElement
(
width:
video
.
videoWidth
,
height:
video
.
videoHeight
);
Future
<
dynamic
>
_captureFrame
()
async
{
if
(
_localStream
==
null
)
return
null
;
final
canvas
=
html
.
CanvasElement
(
width:
video
.
videoWidth
,
height:
video
.
videoHeight
);
final
ctx
=
canvas
.
context2D
;
// canvas.width = video.videoWidth;
// canvas.height = video.videoHeight;
ctx
.
drawImage
(
video
,
0
,
0
);
final
imgData
=
ctx
.
getImageData
(
0
,
0
,
canvas
.
width
!,
canvas
.
height
!);
final
size
=
Size
(
canvas
.
width
?.
toDouble
()
??
0
,
canvas
.
height
?.
toDouble
()
??
0
);
if
(
size
!=
_size
)
{
setState
(()
{
_setCanvasSize
(
size
);
});
}
// final size =
// Size(canvas.width?.toDouble() ?? 0, canvas.height?.toDouble() ?? 0);
// if (size != _size) {
// setState(() {
// _setCanvasSize(size);
// });
// }
// debugPrint('img.data: ${imgData.data}');
final
code
=
jsQR
(
imgData
.
data
,
canvas
.
width
,
canvas
.
height
);
// ignore: unnecessary_null_comparison
if
(
code
!=
null
)
{
widget
.
onDetect
(
Barcode
(
rawValue:
code
.
data
));
debugPrint
(
'CODE:
$code
'
);
// widget.onDetect(Barcode(rawValue: code.data));
// print('Barcode: ${code.data}');
// _scanUpdateController
// .add(Barcode(rawValue: code.data));
...
...
@@ -204,118 +229,14 @@ class _WebQrViewState extends State<WebQrView> {
if
(
_localStream
==
null
)
{
return
const
Center
(
child:
CircularProgressIndicator
());
}
return
LayoutBuilder
(
builder:
(
context
,
constraints
)
{
var
zoom
=
1.0
;
if
(
_size
.
height
!=
0
)
zoom
=
constraints
.
maxHeight
/
_size
.
height
;
if
(
_size
.
width
!=
0
)
{
final
horizontalZoom
=
constraints
.
maxWidth
/
_size
.
width
;
if
(
horizontalZoom
>
zoom
)
{
zoom
=
horizontalZoom
;
}
}
return
SizedBox
(
width:
constraints
.
maxWidth
,
height:
constraints
.
maxHeight
,
child:
Center
(
child:
SizedBox
.
fromSize
(
size:
_size
,
child:
Transform
.
scale
(
alignment:
Alignment
.
center
,
scale:
zoom
,
child:
HtmlElementView
(
viewType:
viewID
),
),
),
),
);
},
);
}
void
_setCanvasSize
(
ui
.
Size
size
)
{
setState
(()
{
_size
=
size
;
});
return
SizedBox
(
width:
MediaQuery
.
of
(
context
).
size
.
width
,
height:
MediaQuery
.
of
(
context
).
size
.
height
,
child:
FittedBox
(
child:
SizedBox
(
width:
video
.
videoWidth
.
toDouble
(),
height:
video
.
videoHeight
.
toDouble
(),
child:
HtmlElementView
(
viewType:
viewID
))));
}
}
//
// class QRViewControllerWeb implements QRViewController {
// final _WebQrViewState _state;
//
// QRViewControllerWeb(this._state);
// @override
// void dispose() => _state.cancel();
//
// @override
// Future<CameraFacing> flipCamera() async {
// // TODO: improve error handling
// _state.facing = _state.facing == CameraFacing.front
// ? CameraFacing.back
// : CameraFacing.front;
// await _state.start();
// return _state.facing;
// }
//
// @override
// Future<CameraFacing> getCameraInfo() async {
// return _state.facing;
// }
//
// @override
// Future<bool?> getFlashStatus() async {
// // TODO: flash is simply not supported by JavaScipt. To avoid issuing applications, we always return it to be off.
// return false;
// }
//
// @override
// Future<SystemFeatures> getSystemFeatures() {
// // TODO: implement getSystemFeatures
// throw UnimplementedError();
// }
//
// @override
// // TODO: implement hasPermissions. Blocking: WebQrView.cameraAvailable() returns a Future<bool> whereas a bool is required
// bool get hasPermissions => throw UnimplementedError();
//
// @override
// Future<void> pauseCamera() {
// // TODO: implement pauseCamera
// throw UnimplementedError();
// }
//
// @override
// Future<void> resumeCamera() {
// // TODO: implement resumeCamera
// throw UnimplementedError();
// }
//
// @override
// Stream<Barcode> get scannedDataStream => _state._scanUpdateController.stream;
//
// @override
// Future<void> stopCamera() {
// // TODO: implement stopCamera
// throw UnimplementedError();
// }
//
// @override
// Future<void> toggleFlash() async {
// // TODO: flash is simply not supported by JavaScipt
// return;
// }
//
// @override
// Future<void> scanInvert(bool isScanInvert) {
// // TODO: implement scanInvert
// throw UnimplementedError();
// }
// }
Widget
createWebQrView
(
{
required
Function
(
Barcode
)
onDetect
,
CameraFacing
?
cameraFacing
})
=>
WebQrView
(
onDetect:
onDetect
,
cameraFacing:
cameraFacing
,
);
...
...
lib/src/web/media.dart
View file @
9c52dac
// This is here because dart doesn't seem to support this properly
// https://stackoverflow.com/questions/61161135/adding-support-for-navigator-mediadevices-getusermedia-to-dart
// // This is here because dart doesn't seem to support this properly
// // https://stackoverflow.com/questions/61161135/adding-support-for-navigator-mediadevices-getusermedia-to-dart
@JS
(
'navigator.mediaDevices'
)
library
media_devices
;
...
...
@@ -22,9 +22,11 @@ class UserMediaOptions {
class
VideoOptions
{
external
String
get
facingMode
;
// external DeviceIdOptions get deviceId;
external
Map
get
width
;
external
Map
get
height
;
external
factory
VideoOptions
(
{
String
?
facingMode
,
DeviceIdOptions
?
deviceId
});
{
String
?
facingMode
,
DeviceIdOptions
?
deviceId
,
Map
?
width
,
Map
?
height
});
}
@JS
()
...
...
lib/src/web/qr-scanner.dart
0 → 100644
View file @
9c52dac
@JS
()
library
qrscanner
;
import
'package:js/js.dart'
;
@JS
(
'QrScanner'
)
external
String
scanImage
(
var
data
);
@JS
()
class
QrScanner
{
external
String
get
scanImage
;
}
...
...
Please
register
or
login
to post a comment