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
p-mazhnik
2022-12-12 17:43:05 +0300
Browse Files
Options
Browse Files
Download
Plain Diff
Commit
3c7aa46b434ec973511c4274480c7a49204e8ca1
3c7aa46b
2 parents
97213cac
643caf07
Merge branch 'master' into pavel/web-format
# Conflicts: # lib/src/web/base.dart
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
110 additions
and
59 deletions
example/lib/barcode_scanner_controller.dart
lib/mobile_scanner_web_plugin.dart
lib/src/mobile_scanner_controller.dart
lib/src/web/base.dart
lib/src/web/zxing.dart
example/lib/barcode_scanner_controller.dart
View file @
3c7aa46
...
...
@@ -77,33 +77,41 @@ class _BarcodeScannerWithControllerState
child:
Row
(
mainAxisAlignment:
MainAxisAlignment
.
spaceEvenly
,
children:
[
IconButton
(
color:
Colors
.
white
,
icon:
ValueListenableBuilder
(
valueListenable:
controller
.
torchState
,
builder:
(
context
,
state
,
child
)
{
if
(
state
==
null
)
{
return
const
Icon
(
Icons
.
flash_off
,
color:
Colors
.
grey
,
);
}
switch
(
state
as
TorchState
)
{
case
TorchState
.
off
:
return
const
Icon
(
Icons
.
flash_off
,
color:
Colors
.
grey
,
);
case
TorchState
.
on
:
return
const
Icon
(
Icons
.
flash_on
,
color:
Colors
.
yellow
,
);
}
},
),
iconSize:
32.0
,
onPressed:
()
=>
controller
.
toggleTorch
(),
ValueListenableBuilder
(
valueListenable:
controller
.
hasTorchState
,
builder:
(
context
,
state
,
child
)
{
if
(
state
!=
true
)
{
return
const
SizedBox
.
shrink
();
}
return
IconButton
(
color:
Colors
.
white
,
icon:
ValueListenableBuilder
(
valueListenable:
controller
.
torchState
,
builder:
(
context
,
state
,
child
)
{
if
(
state
==
null
)
{
return
const
Icon
(
Icons
.
flash_off
,
color:
Colors
.
grey
,
);
}
switch
(
state
as
TorchState
)
{
case
TorchState
.
off
:
return
const
Icon
(
Icons
.
flash_off
,
color:
Colors
.
grey
,
);
case
TorchState
.
on
:
return
const
Icon
(
Icons
.
flash_on
,
color:
Colors
.
yellow
,
);
}
},
),
iconSize:
32.0
,
onPressed:
()
=>
controller
.
toggleTorch
(),
);
},
),
IconButton
(
color:
Colors
.
white
,
...
...
lib/mobile_scanner_web_plugin.dart
View file @
3c7aa46
...
...
@@ -84,11 +84,12 @@ class MobileScannerWebPlugin {
// Check if stream is running
if
(
barCodeReader
.
isStarted
)
{
final
hasTorch
=
await
barCodeReader
.
hasTorch
();
return
{
'ViewID'
:
viewID
,
'videoWidth'
:
barCodeReader
.
videoWidth
,
'videoHeight'
:
barCodeReader
.
videoHeight
,
'torchable'
:
barCodeReader
.
hasTorch
,
'torchable'
:
hasTorch
,
};
}
try
{
...
...
@@ -124,12 +125,17 @@ class MobileScannerWebPlugin {
});
}
});
final
hasTorch
=
await
barCodeReader
.
hasTorch
();
if
(
hasTorch
&&
arguments
.
containsKey
(
'torch'
))
{
barCodeReader
.
toggleTorch
(
enabled:
arguments
[
'torch'
]
as
bool
);
}
return
{
'ViewID'
:
viewID
,
'videoWidth'
:
barCodeReader
.
videoWidth
,
'videoHeight'
:
barCodeReader
.
videoHeight
,
'torchable'
:
barCodeReader
.
hasTorch
,
'torchable'
:
hasTorch
,
};
}
catch
(
e
)
{
throw
PlatformException
(
code:
'MobileScannerWeb'
,
message:
'
$e
'
);
...
...
lib/src/mobile_scanner_controller.dart
View file @
3c7aa46
...
...
@@ -99,19 +99,21 @@ class MobileScannerController {
bool
isStarting
=
false
;
bool
?
_hasTorch
;
/// A notifier that provides availability of the Torch (Flash)
final
ValueNotifier
<
bool
?>
hasTorchState
=
ValueNotifier
(
false
);
/// Returns whether the device has a torch.
///
/// Throws an error if the controller is not initialized.
bool
get
hasTorch
{
if
(
_hasTorch
==
null
)
{
final
hasTorch
=
hasTorchState
.
value
;
if
(
hasTorch
==
null
)
{
throw
const
MobileScannerException
(
errorCode:
MobileScannerErrorCode
.
controllerUninitialized
,
);
}
return
_hasTorch
!
;
return
hasTorch
;
}
/// Set the starting arguments for the camera
...
...
@@ -210,8 +212,9 @@ class MobileScannerController {
);
}
_hasTorch
=
startResult
[
'torchable'
]
as
bool
?
??
false
;
if
(
_hasTorch
!
&&
torchEnabled
)
{
final
hasTorch
=
startResult
[
'torchable'
]
as
bool
?
??
false
;
hasTorchState
.
value
=
hasTorch
;
if
(
hasTorch
&&
torchEnabled
)
{
torchState
.
value
=
TorchState
.
on
;
}
...
...
@@ -223,7 +226,7 @@ class MobileScannerController {
startResult
[
'videoHeight'
]
as
double
?
??
0
,
)
:
toSize
(
startResult
[
'size'
]
as
Map
?
??
{}),
hasTorch:
_hasTorch
!
,
hasTorch:
hasTorch
,
textureId:
kIsWeb
?
null
:
startResult
[
'textureId'
]
as
int
?,
webId:
kIsWeb
?
startResult
[
'ViewID'
]
as
String
?
:
null
,
);
...
...
@@ -244,7 +247,7 @@ class MobileScannerController {
///
/// Throws if the controller was not initialized.
Future
<
void
>
toggleTorch
()
async
{
final
hasTorch
=
_hasTorch
;
final
hasTorch
=
hasTorchState
.
value
;
if
(
hasTorch
==
null
)
{
throw
const
MobileScannerException
(
...
...
lib/src/web/base.dart
View file @
3c7aa46
import
'dart:html'
;
import
'dart:html'
as
html
;
import
'package:flutter/material.dart'
;
import
'package:js/js.dart'
;
import
'package:js/js_util.dart'
;
import
'package:mobile_scanner/src/enums/camera_facing.dart'
;
import
'package:mobile_scanner/src/objects/barcode.dart'
;
import
'package:mobile_scanner/src/web/media.dart'
;
...
...
@@ -9,7 +10,7 @@ import 'package:mobile_scanner/src/web/media.dart';
abstract
class
WebBarcodeReaderBase
{
/// Timer used to capture frames to be analyzed
Duration
frameInterval
=
const
Duration
(
milliseconds:
200
);
final
DivElement
videoContainer
;
final
html
.
DivElement
videoContainer
;
WebBarcodeReaderBase
({
required
this
.
videoContainer
,
...
...
@@ -37,24 +38,24 @@ abstract class WebBarcodeReaderBase {
Future
<
void
>
toggleTorch
({
required
bool
enabled
});
/// Determine whether device has flash
bool
get
hasTorch
;
Future
<
bool
>
hasTorch
()
;
}
mixin
InternalStreamCreation
on
WebBarcodeReaderBase
{
/// The video stream.
/// Will be initialized later to see which camera needs to be used.
MediaStream
?
localMediaStream
;
final
VideoElement
video
=
VideoElement
();
html
.
MediaStream
?
localMediaStream
;
final
html
.
VideoElement
video
=
html
.
VideoElement
();
@override
int
get
videoWidth
=>
video
.
videoWidth
;
@override
int
get
videoHeight
=>
video
.
videoHeight
;
Future
<
MediaStream
?>
initMediaStream
(
CameraFacing
cameraFacing
)
async
{
Future
<
html
.
MediaStream
?>
initMediaStream
(
CameraFacing
cameraFacing
)
async
{
// Check if browser supports multiple camera's and set if supported
final
Map
?
capabilities
=
window
.
navigator
.
mediaDevices
?.
getSupportedConstraints
();
html
.
window
.
navigator
.
mediaDevices
?.
getSupportedConstraints
();
final
Map
<
String
,
dynamic
>
constraints
;
if
(
capabilities
!=
null
&&
capabilities
[
'facingMode'
]
as
bool
)
{
constraints
=
{
...
...
@@ -67,15 +68,15 @@ mixin InternalStreamCreation on WebBarcodeReaderBase {
constraints
=
{
'video'
:
true
};
}
final
stream
=
await
window
.
navigator
.
mediaDevices
?.
getUserMedia
(
constraints
);
await
html
.
window
.
navigator
.
mediaDevices
?.
getUserMedia
(
constraints
);
return
stream
;
}
void
prepareVideoElement
(
VideoElement
videoSource
);
void
prepareVideoElement
(
html
.
VideoElement
videoSource
);
Future
<
void
>
attachStreamToVideo
(
MediaStream
stream
,
VideoElement
videoSource
,
html
.
MediaStream
stream
,
html
.
VideoElement
videoSource
,
);
@override
...
...
@@ -98,19 +99,34 @@ mixin InternalStreamCreation on WebBarcodeReaderBase {
/// Mixin for libraries that don't have built-in torch support
mixin
InternalTorchDetection
on
InternalStreamCreation
{
Future
<
List
<
String
>>
getSupportedTorchStates
()
async
{
try
{
final
track
=
localMediaStream
?.
getVideoTracks
();
if
(
track
!=
null
)
{
final
imageCapture
=
ImageCapture
(
track
.
first
);
final
photoCapabilities
=
await
promiseToFuture
<
PhotoCapabilities
>(
imageCapture
.
getPhotoCapabilities
(),
);
final
fillLightMode
=
photoCapabilities
.
fillLightMode
;
if
(
fillLightMode
!=
null
)
{
return
fillLightMode
;
}
}
}
catch
(
e
)
{
// ImageCapture is not supported by some browsers:
// https://developer.mozilla.org/en-US/docs/Web/API/ImageCapture#browser_compatibility
}
return
[];
}
@override
bool
get
hasTorch
{
// TODO: fix flash light. See https://github.com/dart-lang/sdk/issues/48533
// final track = _localStream?.getVideoTracks();
// if (track != null) {
// final imageCapture = html.ImageCapture(track.first);
// final photoCapabilities = await imageCapture.getPhotoCapabilities();
// }
return
false
;
Future
<
bool
>
hasTorch
()
async
{
return
(
await
getSupportedTorchStates
()).
isNotEmpty
;
}
@override
Future
<
void
>
toggleTorch
({
required
bool
enabled
})
async
{
final
hasTorch
=
await
this
.
hasTorch
();
if
(
hasTorch
)
{
final
track
=
localMediaStream
?.
getVideoTracks
();
await
track
?.
first
.
applyConstraints
({
...
...
@@ -122,6 +138,28 @@ mixin InternalTorchDetection on InternalStreamCreation {
}
}
@JS
(
'Promise'
)
@staticInterop
class
Promise
<
T
>
{}
@JS
()
@anonymous
class
PhotoCapabilities
{
/// Returns an array of available fill light options. Options include auto, off, or flash.
external
List
<
String
>?
get
fillLightMode
;
}
@JS
(
'ImageCapture'
)
@staticInterop
class
ImageCapture
{
/// MediaStreamTrack
external
factory
ImageCapture
(
dynamic
track
);
}
extension
ImageCaptureExt
on
ImageCapture
{
external
Promise
<
PhotoCapabilities
>
getPhotoCapabilities
();
}
@JS
(
'Map'
)
@staticInterop
class
JsMap
{
...
...
lib/src/web/zxing.dart
View file @
3c7aa46
...
...
@@ -7,10 +7,6 @@ import 'package:mobile_scanner/src/enums/camera_facing.dart';
import
'package:mobile_scanner/src/objects/barcode.dart'
;
import
'package:mobile_scanner/src/web/base.dart'
;
@JS
(
'Promise'
)
@staticInterop
class
Promise
<
T
>
{}
@JS
(
'ZXing.BrowserMultiFormatReader'
)
@staticInterop
class
JsZXingBrowserMultiFormatReader
{
...
...
Please
register
or
login
to post a comment