Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,29 +25,29 @@ apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'

android {
compileSdk 33
compileSdk 35

sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig {
// minSdkVersion is determined by Native View.
minSdkVersion 20
targetSdkVersion 33
targetSdkVersion 34
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
multiDexEnabled true
}

kotlinOptions {
jvmTarget = '11'
jvmTarget = '17'
}

compileOptions {
// Flag to enable support for the new language APIs
coreLibraryDesugaringEnabled true
// Sets Java compatibility to Java 11
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
sourceCompatibility JavaVersion.VERSION_17
targetCompatibility JavaVersion.VERSION_17
}
if (project.android.hasProperty('namespace')) {
namespace 'net.touchcapture.qr.flutterqr'
Expand All @@ -61,3 +61,7 @@ dependencies {
implementation 'com.google.zxing:core:3.5.2'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
}

kotlin {
jvmToolchain(17)
}
44 changes: 8 additions & 36 deletions lib/src/web/flutter_qr_web.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import 'dart:async';
import 'dart:core';
import 'dart:html' as html;
import 'dart:js_util';
import 'dart:ui' as ui;
import 'dart:ui_web' as ui show platformViewRegistry;

import 'package:flutter/material.dart';

Expand Down Expand Up @@ -39,11 +39,9 @@ class WebQrView extends StatefulWidget {
static Future<bool> cameraAvailable() async {
final sources =
await html.window.navigator.mediaDevices!.enumerateDevices();
// List<String> vidIds = [];
var hasCam = false;
for (final e in sources) {
if (e.kind == 'videoinput') {
// vidIds.add(e['deviceId']);
hasCam = true;
}
}
Expand All @@ -53,15 +51,12 @@ class WebQrView extends StatefulWidget {

class _WebQrViewState extends State<WebQrView> {
html.MediaStream? _localStream;
// html.CanvasElement canvas;
// html.CanvasRenderingContext2D ctx;
bool _currentlyProcessing = false;

QRViewControllerWeb? _controller;

late Size _size = const Size(0, 0);
Timer? timer;
String? code;
String? _errorMsg;
html.VideoElement video = html.VideoElement();
String viewID = 'QRVIEW-' + DateTime.now().millisecondsSinceEpoch.toString();
Expand All @@ -78,12 +73,12 @@ class _WebQrViewState extends State<WebQrView> {

facing = widget.cameraFacing ?? CameraFacing.front;

// video = html.VideoElement();
WebQrView.vidDiv.children = [video];
// ignore: UNDEFINED_PREFIXED_NAME

// 👇 اینجا مشکل حل شد
ui.platformViewRegistry
.registerViewFactory(viewID, (int id) => WebQrView.vidDiv);
// giving JavaScipt some time to process the DOM changes

Timer(const Duration(milliseconds: 500), () {
start();
});
Expand Down Expand Up @@ -114,7 +109,6 @@ 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;
Expand All @@ -125,10 +119,7 @@ class _WebQrViewState extends State<WebQrView> {
video: VideoOptions(
facingMode: (facing == CameraFacing.front ? 'user' : 'environment'),
));
// dart style, not working properly:
// var stream =
// await html.window.navigator.mediaDevices.getUserMedia(constraints);
// straight JS:

if (_controller == null) {
_controller = QRViewControllerWeb(this);
widget.onPlatformViewCreated(_controller!);
Expand All @@ -137,8 +128,7 @@ class _WebQrViewState extends State<WebQrView> {
widget.onPermissionSet?.call(_controller!, true);
_localStream = stream;
video.srcObject = _localStream;
video.setAttribute('playsinline',
'true'); // required to tell iOS safari we don't want fullscreen
video.setAttribute('playsinline', 'true');
await video.play();
} catch (e) {
cancel();
Expand All @@ -159,17 +149,13 @@ class _WebQrViewState extends State<WebQrView> {

Future<void> _stopStream() async {
try {
// await _localStream.dispose();
_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) {}
}

Expand All @@ -180,8 +166,6 @@ class _WebQrViewState extends State<WebQrView> {
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!);

Expand All @@ -195,15 +179,12 @@ class _WebQrViewState extends State<WebQrView> {

try {
final code = jsQR(imgData.data, canvas.width, canvas.height);
// ignore: unnecessary_null_comparison
if (code != null && code.data != null) {
_scanUpdateController
.add(Barcode(code.data, BarcodeFormat.qrcode, code.data.codeUnits));
}
} on NoSuchMethodError {
// Do nothing, this exception occurs continously in web release when no
// code is found.
// NoSuchMethodError: method not found: 'get$data' on null
// ignore: avoid_print
}
}

Expand Down Expand Up @@ -246,7 +227,7 @@ class _WebQrViewState extends State<WebQrView> {
);
}

void _setCanvasSize(ui.Size size) {
void _setCanvasSize(Size size) {
setState(() {
_size = size;
});
Expand All @@ -262,7 +243,6 @@ class QRViewControllerWeb implements QRViewController {

@override
Future<CameraFacing> flipCamera() async {
// TODO: improve error handling
_state.facing = _state.facing == CameraFacing.front
? CameraFacing.back
: CameraFacing.front;
Expand All @@ -277,29 +257,24 @@ class QRViewControllerWeb implements QRViewController {

@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();
}

Expand All @@ -308,19 +283,16 @@ class QRViewControllerWeb implements QRViewController {

@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();
}
}
Expand Down