2025-01-12 23:51:00 +01:00
Grocy . Components . CameraBarcodeScanner = { } ;
2019-09-19 12:48:02 +02:00
2025-03-21 18:41:39 +02:00
Grocy . Components . CameraBarcodeScanner . Scanner = null ;
2025-01-12 23:51:00 +01:00
Grocy . Components . CameraBarcodeScanner . LiveVideoSizeAdjusted = false ;
Grocy . Components . CameraBarcodeScanner . CameraSelectLoaded = false ;
Grocy . Components . CameraBarcodeScanner . TorchIsOn = false ;
Grocy . Components . CameraBarcodeScanner . CheckCapabilities = async function ( )
2020-03-29 14:25:04 +02:00
{
2025-03-21 18:41:39 +02:00
var track = Grocy . Components . CameraBarcodeScanner . Scanner . stream . getVideoTracks ( ) [ 0 ] ;
2020-03-29 14:25:04 +02:00
var capabilities = { } ;
2020-08-30 12:18:16 +02:00
if ( typeof track . getCapabilities === 'function' )
{
2020-03-29 14:25:04 +02:00
capabilities = track . getCapabilities ( ) ;
}
2020-08-29 16:41:27 +02:00
2025-01-12 23:51:00 +01:00
// Init camera select dropdown
if ( ! Grocy . Components . CameraBarcodeScanner . CameraSelectLoaded )
2020-08-30 12:18:16 +02:00
{
2025-01-12 23:51:00 +01:00
var cameraSelect = document . querySelector ( '.cameraSelect' ) ;
2025-03-21 18:41:39 +02:00
var cameras = await Grocy . Components . CameraBarcodeScanner . Scanner . listVideoInputDevices ( ) ;
2025-01-12 23:51:00 +01:00
cameras . forEach ( camera =>
{
var option = document . createElement ( "option" ) ;
option . text = camera . label ;
option . value = camera . deviceId ;
if ( track . label == camera . label )
{
option . selected = "selected" ;
}
cameraSelect . appendChild ( option ) ;
} ) ;
Grocy . Components . CameraBarcodeScanner . CameraSelectLoaded = true ;
2020-04-13 22:07:38 +02:00
}
2020-08-29 16:41:27 +02:00
2025-01-12 23:51:00 +01:00
// Check if the camera is capable to turn on a torch
var hasTorch = typeof capabilities . torch === 'boolean' && capabilities . torch ;
// Remove the torch button if the select camera doesn't have a torch
if ( ! hasTorch )
2020-08-30 12:18:16 +02:00
{
2025-01-14 17:54:06 +01:00
document . querySelector ( '.camerabarcodescanner-modal .modal-footer' ) . setAttribute ( 'style' , 'display:none !important;' ) ;
2020-03-29 14:25:04 +02:00
}
2025-01-12 23:51:00 +01:00
else
2020-08-30 12:18:16 +02:00
{
2025-01-14 17:54:06 +01:00
document . querySelector ( '.camerabarcodescanner-modal .modal-footer' ) . setAttribute ( 'style' , 'flex;' ) ;
2020-03-29 14:25:04 +02:00
}
2025-03-21 18:41:39 +02:00
// Reduce the height of the video if it's higher than the viewport
2025-01-12 23:51:00 +01:00
if ( ! Grocy . Components . CameraBarcodeScanner . LiveVideoSizeAdjusted )
2020-04-13 22:34:52 +02:00
{
2025-01-14 17:54:06 +01:00
var bc = document . getElementById ( 'camerabarcodescanner-container' ) ;
2020-04-13 22:34:52 +02:00
if ( bc )
{
var bcAspectRatio = bc . offsetWidth / bc . offsetHeight ;
var settings = track . getSettings ( ) ;
if ( bcAspectRatio > settings . aspectRatio )
{
2025-03-21 18:41:39 +02:00
var v = document . querySelector ( '#camerabarcodescanner-livestream' ) ;
2020-04-13 22:34:52 +02:00
if ( v )
{
var newWidth = v . clientWidth / bcAspectRatio * settings . aspectRatio + 'px' ;
v . style . width = newWidth ;
}
2020-03-29 14:25:04 +02:00
}
2020-04-13 22:34:52 +02:00
2025-01-12 23:51:00 +01:00
Grocy . Components . CameraBarcodeScanner . LiveVideoSizeAdjusted = true ;
2020-03-29 14:25:04 +02:00
}
}
}
2025-01-12 23:51:00 +01:00
Grocy . Components . CameraBarcodeScanner . StartScanning = function ( )
2019-09-19 12:48:02 +02:00
{
2025-03-21 18:41:39 +02:00
Grocy . Components . CameraBarcodeScanner . Scanner . decodeFromVideoDevice (
window . localStorage . getItem ( 'cameraId' ) ,
document . querySelector ( "#camerabarcodescanner-livestream" ) ,
( result , error ) =>
{
if ( error )
{
return ;
2019-09-19 12:48:02 +02:00
}
2025-03-21 18:41:39 +02:00
Grocy . Components . CameraBarcodeScanner . StopScanning ( ) ;
$ ( document ) . trigger ( "Grocy.BarcodeScanned" , [ result . getText ( ) , Grocy . Components . CameraBarcodeScanner . CurrentTarget ] ) ;
$ ( ".modal" ) . last ( ) . modal ( "hide" ) ;
}
)
. then ( ( ) =>
{
Grocy . Components . CameraBarcodeScanner . CheckCapabilities ( ) ;
if ( Grocy . FeatureFlags . GROCY _FEATURE _FLAG _AUTO _TORCH _ON _WITH _CAMERA )
{
setTimeout ( function ( )
{
Grocy . Components . CameraBarcodeScanner . TorchToggle ( Grocy . Components . CameraBarcodeScanner . Scanner . stream . getVideoTracks ( ) [ 0 ] ) ;
} , 250 ) ;
2019-09-19 12:48:02 +02:00
}
2025-03-21 18:41:39 +02:00
} )
. catch ( ( error ) =>
2019-09-19 12:48:02 +02:00
{
Grocy . FrontendHelpers . ShowGenericError ( "Error while initializing the barcode scanning library" , error . message ) ;
2023-05-19 18:08:26 +02:00
toastr . info ( _ _t ( "Camera access is only possible when supported and allowed by your browser and when Grocy is served via a secure (https://) connection" ) ) ;
2020-04-13 22:07:38 +02:00
window . localStorage . removeItem ( "cameraId" ) ;
2019-09-20 13:37:53 +02:00
setTimeout ( function ( )
{
2025-01-10 17:15:09 +01:00
$ ( ".modal" ) . last ( ) . modal ( "hide" ) ;
2025-01-31 15:35:34 +01:00
} , Grocy . FormFocusDelay ) ;
2019-09-19 12:48:02 +02:00
return ;
2025-03-21 18:41:39 +02:00
} )
2019-09-19 12:48:02 +02:00
}
2025-01-12 23:51:00 +01:00
Grocy . Components . CameraBarcodeScanner . StopScanning = function ( )
2019-09-19 12:48:02 +02:00
{
2025-03-21 18:41:39 +02:00
Grocy . Components . CameraBarcodeScanner . Scanner . reset ( ) ;
2020-08-29 16:41:27 +02:00
2025-01-12 23:51:00 +01:00
Grocy . Components . CameraBarcodeScanner . LiveVideoSizeAdjusted = false ;
Grocy . Components . CameraBarcodeScanner . CameraSelectLoaded = false ;
Grocy . Components . CameraBarcodeScanner . TorchIsOn = false ;
2019-09-19 12:48:02 +02:00
}
2025-01-12 23:51:00 +01:00
Grocy . Components . CameraBarcodeScanner . TorchToggle = function ( track )
2020-03-29 14:25:04 +02:00
{
2020-08-30 12:18:16 +02:00
if ( track )
{
2025-01-12 23:51:00 +01:00
Grocy . Components . CameraBarcodeScanner . TorchIsOn = ! Grocy . Components . CameraBarcodeScanner . TorchIsOn ;
2020-08-29 16:41:27 +02:00
track . applyConstraints ( {
2020-03-29 14:25:04 +02:00
advanced : [
2020-08-29 16:41:27 +02:00
{
2025-01-12 23:51:00 +01:00
torch : Grocy . Components . CameraBarcodeScanner . TorchIsOn
2020-03-29 14:25:04 +02:00
}
]
} ) ;
}
}
2025-01-14 17:54:06 +01:00
$ ( document ) . on ( "click" , "#camerabarcodescanner-start-button" , async function ( e )
2019-09-19 12:48:02 +02:00
{
e . preventDefault ( ) ;
2025-03-21 18:41:39 +02:00
2019-09-27 17:24:44 +02:00
var inputElement = $ ( e . currentTarget ) . prev ( ) ;
if ( inputElement . hasAttr ( "disabled" ) )
{
// Do nothing and disable the barcode scanner start button
$ ( e . currentTarget ) . addClass ( "disabled" ) ;
return ;
}
2025-01-12 23:51:00 +01:00
Grocy . Components . CameraBarcodeScanner . CurrentTarget = inputElement . attr ( "data-target" ) ;
2020-08-29 16:41:27 +02:00
2020-04-13 22:07:38 +02:00
var dialog = bootbox . dialog ( {
2025-03-21 18:41:39 +02:00
message : '<div id="camerabarcodescanner-container" class="col"><video id="camerabarcodescanner-livestream"></div></div>' ,
2019-09-19 12:48:02 +02:00
title : _ _t ( 'Scan a barcode' ) ,
2025-01-12 23:51:00 +01:00
size : 'large' ,
2019-09-19 12:48:02 +02:00
backdrop : true ,
2020-03-01 17:53:28 +01:00
closeButton : true ,
2025-01-14 17:54:06 +01:00
className : "form camerabarcodescanner-modal" ,
2019-09-19 12:48:02 +02:00
buttons : {
2020-03-01 17:53:28 +01:00
torch : {
2025-01-08 20:50:35 +01:00
label : '<i class="fa-solid fa-lightbulb"></i>' ,
2020-03-29 14:25:04 +02:00
className : 'btn-warning responsive-button torch' ,
2020-03-01 17:58:10 +01:00
callback : function ( )
{
2025-03-21 18:41:39 +02:00
if ( Grocy . Components . CameraBarcodeScanner . Scanner . stream )
{
Grocy . Components . CameraBarcodeScanner . TorchToggle ( Grocy . Components . CameraBarcodeScanner . Scanner . stream . getVideoTracks ( ) [ 0 ] ) ;
}
2020-03-01 17:58:10 +01:00
return false ;
2020-08-30 12:18:16 +02:00
}
2019-09-20 13:37:53 +02:00
}
2025-01-12 23:51:00 +01:00
} ,
onHide : function ( e )
{
Grocy . Components . CameraBarcodeScanner . StopScanning ( ) ;
2019-09-19 12:48:02 +02:00
}
} ) ;
2020-08-29 16:41:27 +02:00
2020-04-13 22:07:38 +02:00
// Add camera select to existing dialog
2025-03-21 18:41:39 +02:00
dialog . find ( '.bootbox-body' ) . append ( '<div class="form-group pb-0 pt-2 my-1 d-block cameraSelect-wrapper"><select class="custom-control custom-select cameraSelect"></select></div>' ) ;
2020-04-13 22:07:38 +02:00
var cameraSelect = document . querySelector ( '.cameraSelect' ) ;
2020-08-30 12:18:16 +02:00
cameraSelect . onchange = function ( )
{
2020-04-13 22:07:38 +02:00
window . localStorage . setItem ( 'cameraId' , cameraSelect . value ) ;
2025-03-21 18:41:39 +02:00
Grocy . Components . CameraBarcodeScanner . Scanner . reset ( ) ;
2025-01-12 23:51:00 +01:00
Grocy . Components . CameraBarcodeScanner . StartScanning ( ) ;
2020-04-13 22:07:38 +02:00
} ;
2020-08-29 16:41:27 +02:00
2025-01-12 23:51:00 +01:00
Grocy . Components . CameraBarcodeScanner . StartScanning ( ) ;
2019-09-19 12:48:02 +02:00
} ) ;
2025-01-12 23:51:00 +01:00
Grocy . Components . CameraBarcodeScanner . InitDone = false ;
Grocy . Components . CameraBarcodeScanner . Init = function ( )
2019-09-19 12:48:02 +02:00
{
2025-01-12 23:51:00 +01:00
if ( Grocy . Components . CameraBarcodeScanner . InitDone )
2022-02-11 18:18:17 +01:00
{
return ;
}
2025-03-21 18:41:39 +02:00
Grocy . Components . CameraBarcodeScanner . Scanner = new ZXing . BrowserMultiFormatReader ( new Map ( ) . set ( ZXing . DecodeHintType . POSSIBLE _FORMATS , [
ZXing . BarcodeFormat . EAN _8 ,
ZXing . BarcodeFormat . EAN _13 ,
ZXing . BarcodeFormat . CODE _39 ,
ZXing . BarcodeFormat . CODE _128 ,
ZXing . BarcodeFormat . DATA _MATRIX ,
ZXing . BarcodeFormat . QR _CODE ,
] ) ) ;
2019-09-27 17:24:44 +02:00
$ ( ".barcodescanner-input:visible" ) . each ( function ( )
{
if ( $ ( this ) . hasAttr ( "disabled" ) )
{
2025-01-14 17:54:06 +01:00
$ ( this ) . after ( '<a id="camerabarcodescanner-start-button" class="btn btn-sm btn-primary text-white disabled" data-target="' + $ ( this ) . attr ( "data-target" ) + '"><i class="fa-solid fa-camera"></i></a>' ) ;
2019-09-27 17:24:44 +02:00
}
else
{
2025-01-14 17:54:06 +01:00
$ ( this ) . after ( '<a id="camerabarcodescanner-start-button" class="btn btn-sm btn-primary text-white" data-target="' + $ ( this ) . attr ( "data-target" ) + '"><i class="fa-solid fa-camera"></i></a>' ) ;
2019-09-27 17:24:44 +02:00
}
2022-02-11 18:18:17 +01:00
2025-01-12 23:51:00 +01:00
Grocy . Components . CameraBarcodeScanner . InitDone = true ;
2019-09-27 17:24:44 +02:00
} ) ;
2022-02-11 18:18:17 +01:00
}
setTimeout ( function ( )
{
2025-01-12 23:51:00 +01:00
Grocy . Components . CameraBarcodeScanner . Init ( ) ;
2019-09-19 12:48:02 +02:00
} , 50 ) ;