Navaron Bracke

reimplement flashlight delegate & use media capabilities which is more supported

  1 +import 'dart:js_interop';
  2 +
  3 +import 'package:mobile_scanner/src/enums/torch_state.dart';
  4 +import 'package:web/web.dart';
  5 +
  6 +/// This class represents a flashlight delegate for the web platform.
  7 +///
  8 +/// It provides an interface to query and update the flashlight state of a [MediaStream].
  9 +final class FlashlightDelegate {
  10 + /// Returns a list of supported flashlight modes for the given [mediaStream].
  11 + ///
  12 + /// The [TorchState.off] mode is always supported, regardless of the return value.
  13 + Future<List<TorchState>> getSupportedFlashlightModes(MediaStream? mediaStream) async {
  14 + if (mediaStream == null) {
  15 + return [];
  16 + }
  17 +
  18 + final List<JSAny?> tracks = mediaStream.getVideoTracks().toDart;
  19 +
  20 + if (tracks.isEmpty) {
  21 + return [];
  22 + }
  23 +
  24 + final MediaStreamTrack? track = tracks.first as MediaStreamTrack?;
  25 +
  26 + if (track == null) {
  27 + return [];
  28 + }
  29 +
  30 + try {
  31 + final MediaTrackCapabilities capabilities = track.getCapabilities();
  32 +
  33 + return [
  34 + if (capabilities.torch) TorchState.on,
  35 + ];
  36 + } catch (_) {
  37 + // Firefox does not support getCapabilities() yet.
  38 + // https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamTrack/getCapabilities#browser_compatibility
  39 +
  40 + return [];
  41 + }
  42 + }
  43 +
  44 + /// Returns whether the given [mediaStream] has a flashlight.
  45 + Future<bool> hasFlashlight(MediaStream? mediaStream) async {
  46 + return (await getSupportedFlashlightModes(mediaStream)).isNotEmpty;
  47 + }
  48 +
  49 + /// Set the flashlight state of the given [mediaStream] to the given [value].
  50 + Future<void> setFlashlightState(MediaStream? mediaStream, TorchState value) async {
  51 + if (mediaStream == null) {
  52 + return;
  53 + }
  54 +
  55 + if (await hasFlashlight(mediaStream)) {
  56 + final List<JSAny?> tracks = mediaStream.getVideoTracks().toDart;
  57 +
  58 + if (tracks.isEmpty) {
  59 + return;
  60 + }
  61 +
  62 + final bool flashlightEnabled = switch (value) {
  63 + TorchState.on => true,
  64 + TorchState.off || TorchState.unavailable => false,
  65 + };
  66 +
  67 + final MediaStreamTrack? track = tracks.first as MediaStreamTrack?;
  68 +
  69 + final MediaTrackConstraints constraints = MediaTrackConstraints(
  70 + advanced: [
  71 + {'torch': flashlightEnabled}.jsify(),
  72 + ].toJS,
  73 + );
  74 +
  75 + await track?.applyConstraints(constraints).toDart;
  76 + }
  77 + }
  78 +}