p-mazhnik

feat: add hasTorch notifier

@@ -77,7 +77,13 @@ class _BarcodeScannerWithControllerState @@ -77,7 +77,13 @@ class _BarcodeScannerWithControllerState
77 child: Row( 77 child: Row(
78 mainAxisAlignment: MainAxisAlignment.spaceEvenly, 78 mainAxisAlignment: MainAxisAlignment.spaceEvenly,
79 children: [ 79 children: [
80 - IconButton( 80 + ValueListenableBuilder(
  81 + valueListenable: controller.hasTorchState,
  82 + builder: (context, state, child) {
  83 + if (state != true) {
  84 + return const SizedBox.shrink();
  85 + }
  86 + return IconButton(
81 color: Colors.white, 87 color: Colors.white,
82 icon: ValueListenableBuilder( 88 icon: ValueListenableBuilder(
83 valueListenable: controller.torchState, 89 valueListenable: controller.torchState,
@@ -104,7 +110,8 @@ class _BarcodeScannerWithControllerState @@ -104,7 +110,8 @@ class _BarcodeScannerWithControllerState
104 ), 110 ),
105 iconSize: 32.0, 111 iconSize: 32.0,
106 onPressed: () => controller.toggleTorch(), 112 onPressed: () => controller.toggleTorch(),
107 - ), 113 + );
  114 + }),
108 IconButton( 115 IconButton(
109 color: Colors.white, 116 color: Colors.white,
110 icon: isStarted 117 icon: isStarted
@@ -99,7 +99,8 @@ class MobileScannerController { @@ -99,7 +99,8 @@ class MobileScannerController {
99 99
100 bool isStarting = false; 100 bool isStarting = false;
101 101
102 - bool? _hasTorch; 102 + /// A notifier that provides availability of the Torch (Flash)
  103 + final ValueNotifier<bool?> hasTorchState = ValueNotifier(false);
103 104
104 /// Returns whether the device has a torch. 105 /// Returns whether the device has a torch.
105 /// 106 ///
@@ -210,8 +211,9 @@ class MobileScannerController { @@ -210,8 +211,9 @@ class MobileScannerController {
210 ); 211 );
211 } 212 }
212 213
213 - _hasTorch = startResult['torchable'] as bool? ?? false;  
214 - if (_hasTorch! && torchEnabled) { 214 + final hasTorch = startResult['torchable'] as bool? ?? false;
  215 + hasTorchState.value = hasTorch;
  216 + if (hasTorch && torchEnabled) {
215 torchState.value = TorchState.on; 217 torchState.value = TorchState.on;
216 } 218 }
217 219
@@ -223,7 +225,7 @@ class MobileScannerController { @@ -223,7 +225,7 @@ class MobileScannerController {
223 startResult['videoHeight'] as double? ?? 0, 225 startResult['videoHeight'] as double? ?? 0,
224 ) 226 )
225 : toSize(startResult['size'] as Map? ?? {}), 227 : toSize(startResult['size'] as Map? ?? {}),
226 - hasTorch: _hasTorch!, 228 + hasTorch: hasTorch,
227 textureId: kIsWeb ? null : startResult['textureId'] as int?, 229 textureId: kIsWeb ? null : startResult['textureId'] as int?,
228 webId: kIsWeb ? startResult['ViewID'] as String? : null, 230 webId: kIsWeb ? startResult['ViewID'] as String? : null,
229 ); 231 );
@@ -244,7 +246,7 @@ class MobileScannerController { @@ -244,7 +246,7 @@ class MobileScannerController {
244 /// 246 ///
245 /// Throws if the controller was not initialized. 247 /// Throws if the controller was not initialized.
246 Future<void> toggleTorch() async { 248 Future<void> toggleTorch() async {
247 - final hasTorch = _hasTorch; 249 + final hasTorch = hasTorchState.value;
248 250
249 if (hasTorch == null) { 251 if (hasTorch == null) {
250 throw const MobileScannerException( 252 throw const MobileScannerException(
@@ -98,8 +98,7 @@ mixin InternalStreamCreation on WebBarcodeReaderBase { @@ -98,8 +98,7 @@ mixin InternalStreamCreation on WebBarcodeReaderBase {
98 98
99 /// Mixin for libraries that don't have built-in torch support 99 /// Mixin for libraries that don't have built-in torch support
100 mixin InternalTorchDetection on InternalStreamCreation { 100 mixin InternalTorchDetection on InternalStreamCreation {
101 - @override  
102 - Future<bool> hasTorch() async { 101 + Future<List<String>> getSupportedTorchStates() async {
103 try { 102 try {
104 final track = localMediaStream?.getVideoTracks(); 103 final track = localMediaStream?.getVideoTracks();
105 if (track != null) { 104 if (track != null) {
@@ -107,13 +106,21 @@ mixin InternalTorchDetection on InternalStreamCreation { @@ -107,13 +106,21 @@ mixin InternalTorchDetection on InternalStreamCreation {
107 final photoCapabilities = await promiseToFuture<PhotoCapabilities>( 106 final photoCapabilities = await promiseToFuture<PhotoCapabilities>(
108 imageCapture.getPhotoCapabilities(), 107 imageCapture.getPhotoCapabilities(),
109 ); 108 );
110 - return photoCapabilities.fillLightMode != null; 109 + final fillLightMode = photoCapabilities.fillLightMode;
  110 + if (fillLightMode != null) {
  111 + return fillLightMode;
  112 + }
111 } 113 }
112 } catch (e) { 114 } catch (e) {
113 // ImageCapture is not supported by some browsers: 115 // ImageCapture is not supported by some browsers:
114 // https://developer.mozilla.org/en-US/docs/Web/API/ImageCapture#browser_compatibility 116 // https://developer.mozilla.org/en-US/docs/Web/API/ImageCapture#browser_compatibility
115 } 117 }
116 - return false; 118 + return [];
  119 + }
  120 +
  121 + @override
  122 + Future<bool> hasTorch() async {
  123 + return (await getSupportedTorchStates()).isNotEmpty;
117 } 124 }
118 125
119 @override 126 @override