Skip to content

Commit 30fd123

Browse files
Merge branch 'develop' into flutter_view_barcode_corners
2 parents 2bbd396 + 0ae802a commit 30fd123

27 files changed

+361
-89
lines changed

.github/workflows/code-coverage.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
steps:
1515
# Checkout the Repository
1616
- name: 📥 Checkout Repository
17-
uses: actions/checkout@v4
17+
uses: actions/checkout@v5
1818

1919
# Setup Flutter SDK with Cache
2020
- name: ⚡ Set Up Flutter

.github/workflows/code-quality.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616

1717
steps:
1818
- name: 📥 Checkout Code
19-
uses: actions/checkout@v4
19+
uses: actions/checkout@v5
2020

2121
- name: ⚡ Set Up Flutter
2222
uses: subosito/flutter-action@v2
@@ -50,7 +50,7 @@ jobs:
5050

5151
steps:
5252
- name: 📥 Checkout Code
53-
uses: actions/checkout@v4
53+
uses: actions/checkout@v5
5454

5555
- name: ⚡ Set Up Flutter
5656
uses: subosito/flutter-action@v2

.github/workflows/release-please.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
release-please:
88
runs-on: ubuntu-latest
99
steps:
10-
- uses: GoogleCloudPlatform/release-please-action@v4.2.0
10+
- uses: GoogleCloudPlatform/release-please-action@v4.3.0
1111
with:
1212
token: ${{ secrets.GITHUB_TOKEN }}
1313
release-type: simple

.github/workflows/semantic-pr.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,6 @@ jobs:
1212
name: Validate PR title
1313
runs-on: ubuntu-latest
1414
steps:
15-
- uses: amannn/action-semantic-pull-request@v5
15+
- uses: amannn/action-semantic-pull-request@v6
1616
env:
1717
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

CHANGELOG.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
1-
## 7.0.2
1+
## NEXT
22

3+
**BREAKING CHANGES**
4+
5+
* [iOS] Increased minimum iOS level to 13 due to Flutter requirements.
6+
7+
**Highlights**
8+
9+
* [Apple & Android] Added tap to focus functionality. You can enable it in the `MobileScanner` widget.
10+
* [Apple & Android] You can now set the initial zoom factor using the `initialZoom` parameter in the `startOptions`.
11+
12+
**Bug Fixes and Improvements**
13+
14+
* [Android] Update to Java 17, and update other dependencies.
15+
* [Apple] Improved fallback for when camera is not found.
316
* Added a `Barcode.scaleCorners()` method.
417

518
## 7.0.1
@@ -10,7 +23,7 @@
1023

1124
This version finalizes all changes from the beta and release candidate cycles and introduces major improvements, bug fixes, and breaking changes.
1225

13-
**BREAKING CHANGES:**
26+
**BREAKING CHANGES**
1427

1528
* Requires Flutter 3.29.0 or higher.
1629
* The initial camera facing direction in `MobileScannerState` is now `CameraFacing.unknown`.

android/build.gradle

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ buildscript {
99
}
1010

1111
dependencies {
12-
classpath 'com.android.tools.build:gradle:8.10.1'
12+
classpath 'com.android.tools.build:gradle:8.13.0'
1313
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
1414
}
1515
}
@@ -29,15 +29,15 @@ android {
2929
namespace 'dev.steenbakker.mobile_scanner'
3030
}
3131

32-
compileSdk 35
32+
compileSdk 36
3333

3434
compileOptions {
35-
sourceCompatibility JavaVersion.VERSION_1_8
36-
targetCompatibility JavaVersion.VERSION_1_8
35+
sourceCompatibility JavaVersion.VERSION_17
36+
targetCompatibility JavaVersion.VERSION_17
3737
}
3838

3939
kotlinOptions {
40-
jvmTarget = '1.8'
40+
jvmTarget = '17'
4141
}
4242

4343
sourceSets {
@@ -73,10 +73,10 @@ dependencies {
7373
implementation 'com.google.mlkit:barcode-scanning:17.3.0'
7474
}
7575

76-
implementation 'androidx.camera:camera-lifecycle:1.4.2'
77-
implementation 'androidx.camera:camera-camera2:1.4.2'
78-
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
76+
implementation 'androidx.camera:camera-lifecycle:1.5.0'
77+
implementation 'androidx.camera:camera-camera2:1.5.0'
78+
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.10.2'
7979

8080
testImplementation 'org.jetbrains.kotlin:kotlin-test'
81-
testImplementation 'org.mockito:mockito-core:5.18.0'
81+
testImplementation 'org.mockito:mockito-core:5.19.0'
8282
}

android/src/main/kotlin/dev/steenbakker/mobile_scanner/MobileScanner.kt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,13 @@ import androidx.camera.core.CameraSelector
2323
import androidx.camera.core.CameraXConfig
2424
import androidx.camera.core.ExperimentalGetImage
2525
import androidx.camera.core.ExperimentalLensFacing
26+
import androidx.camera.core.FocusMeteringAction
2627
import androidx.camera.core.ImageAnalysis
2728
import androidx.camera.core.ImageProxy
29+
import androidx.camera.core.MeteringPoint
30+
import androidx.camera.core.MeteringPointFactory
2831
import androidx.camera.core.Preview
32+
import androidx.camera.core.SurfaceOrientedMeteringPointFactory
2933
import androidx.camera.core.SurfaceRequest
3034
import androidx.camera.core.TorchState
3135
import androidx.camera.core.resolutionselector.ResolutionSelector
@@ -343,6 +347,7 @@ class MobileScanner(
343347
detectionTimeout: Long,
344348
cameraResolutionWanted: Size?,
345349
invertImage: Boolean,
350+
initialZoom: Double,
346351
) {
347352
this.detectionSpeed = detectionSpeed
348353
this.detectionTimeout = detectionTimeout
@@ -471,6 +476,18 @@ class MobileScanner(
471476
if (it.cameraInfo.hasFlashUnit()) {
472477
it.cameraControl.enableTorch(torch)
473478
}
479+
480+
try {
481+
if (initialZoom in 0.0..1.0) {
482+
it.cameraControl.setLinearZoom(initialZoom.toFloat())
483+
} else {
484+
it.cameraControl.setZoomRatio(initialZoom.toFloat())
485+
}
486+
} catch (e: Exception) {
487+
mobileScannerErrorCallback(ZoomNotInRange())
488+
489+
return@addListener
490+
}
474491
}
475492

476493
val resolution = analysis.resolutionInfo!!.resolution
@@ -701,6 +718,23 @@ class MobileScanner(
701718
camera?.cameraControl?.setZoomRatio(1f)
702719
}
703720

721+
fun setFocus(x: Float, y: Float) {
722+
val cam = camera ?: throw ZoomWhenStopped()
723+
724+
// Ensure x,y are normalized (0f..1f)
725+
if (x !in 0f..1f || y !in 0f..1f) {
726+
throw IllegalArgumentException("Focus coordinates must be between 0.0 and 1.0")
727+
}
728+
729+
val factory: MeteringPointFactory = SurfaceOrientedMeteringPointFactory(1f, 1f)
730+
val afPoint: MeteringPoint = factory.createPoint(x, y)
731+
732+
val action = FocusMeteringAction.Builder(afPoint, FocusMeteringAction.FLAG_AF)
733+
.build()
734+
735+
cam.cameraControl.startFocusAndMetering(action)
736+
}
737+
704738
/**
705739
* Dispose of this scanner instance.
706740
*/

android/src/main/kotlin/dev/steenbakker/mobile_scanner/MobileScannerHandler.kt

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ class MobileScannerHandler(
151151
"setScale" -> setScale(call, result)
152152
"resetScale" -> resetScale(result)
153153
"updateScanWindow" -> updateScanWindow(call, result)
154+
"setFocus" -> setFocus(call, result)
154155
else -> result.notImplemented()
155156
}
156157
}
@@ -172,6 +173,7 @@ class MobileScannerHandler(
172173
null
173174
}
174175
val invertImage: Boolean = call.argument<Boolean>("invertImage") ?: false
176+
val initialZoom: Double = call.argument<Double>("initialZoom") ?: 1.0
175177

176178
val barcodeScannerOptions: BarcodeScannerOptions? = buildBarcodeScannerOptions(formats, autoZoom)
177179

@@ -243,6 +245,7 @@ class MobileScannerHandler(
243245
timeout.toLong(),
244246
cameraResolution,
245247
invertImage,
248+
initialZoom
246249
)
247250
}
248251

@@ -327,7 +330,7 @@ class MobileScannerHandler(
327330
private fun buildBarcodeScannerOptions(formats: List<Int>?, autoZoom: Boolean): BarcodeScannerOptions? {
328331
val builder : BarcodeScannerOptions.Builder?
329332
if (formats == null) {
330-
builder = BarcodeScannerOptions.Builder()
333+
builder = BarcodeScannerOptions.Builder()
331334
} else {
332335
val formatsList: MutableList<Int> = mutableListOf()
333336

@@ -374,4 +377,36 @@ class MobileScannerHandler(
374377
}
375378
return maxZoom
376379
}
380+
381+
private fun setFocus(call: MethodCall, result: MethodChannel.Result) {
382+
val dx = call.argument<Double>("dx")?.toFloat()
383+
val dy = call.argument<Double>("dy")?.toFloat()
384+
385+
if (dx == null || dy == null || dx !in 0f..1f || dy !in 0f..1f) {
386+
result.error(
387+
MobileScannerErrorCodes.INVALID_FOCUS_POINT,
388+
MobileScannerErrorCodes.INVALID_FOCUS_POINT_MESSAGE,
389+
null
390+
)
391+
return
392+
}
393+
394+
try {
395+
mobileScanner?.setFocus(dx, dy)
396+
result.success(null)
397+
} catch (e: ZoomWhenStopped) {
398+
result.error(
399+
MobileScannerErrorCodes.GENERIC_ERROR,
400+
"Cannot set focus when camera is stopped.",
401+
null
402+
)
403+
} catch (e: Exception) {
404+
result.error(
405+
MobileScannerErrorCodes.GENERIC_ERROR,
406+
MobileScannerErrorCodes.GENERIC_ERROR_MESSAGE,
407+
e.localizedMessage
408+
)
409+
}
410+
}
411+
377412
}

android/src/main/kotlin/dev/steenbakker/mobile_scanner/objects/MobileScannerErrorCodes.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,7 @@ class MobileScannerErrorCodes {
2323
const val SET_SCALE_WHEN_STOPPED_ERROR = "MOBILE_SCANNER_SET_SCALE_WHEN_STOPPED_ERROR"
2424
const val SET_SCALE_WHEN_STOPPED_ERROR_MESSAGE = "The zoom scale cannot be changed when the camera is stopped."
2525
const val UNSUPPORTED_OPERATION_ERROR = "MOBILE_SCANNER_UNSUPPORTED_OPERATION" // Reserved for future use.
26+
const val INVALID_FOCUS_POINT = "MOBILE_SCANNER_INVALID_FOCUS_POINT"
27+
const val INVALID_FOCUS_POINT_MESSAGE = "The focus coordinates are not valid."
2628
}
2729
}

darwin/mobile_scanner/Sources/mobile_scanner/MobileScannerErrorCodes.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ struct MobileScannerErrorCodes {
2424
static let GENERIC_ERROR_MESSAGE = "An unknown error occurred."
2525
// This message is used with the 'GENERIC_ERROR' error code.
2626
static let INVALID_ZOOM_SCALE_ERROR_MESSAGE = "The zoom scale should be between 0 and 1 (both inclusive)"
27+
static let INVALID_FOCUS_POINT = "MOBILE_SCANNER_INVALID_FOCUS_POINT"
28+
static let INVALID_FOCUS_POINT_MESSAGE = "The focus coordinates are not valid."
2729
static let NO_CAMERA_ERROR = "MOBILE_SCANNER_NO_CAMERA_ERROR"
2830
static let NO_CAMERA_ERROR_MESSAGE = "No cameras available."
2931
static let SET_SCALE_WHEN_STOPPED_ERROR = "MOBILE_SCANNER_SET_SCALE_WHEN_STOPPED_ERROR"

0 commit comments

Comments
 (0)