Initialize Schnappix Photo Booth application with custom UVC camera, silent Wi-Fi IPP printing, local gallery storage, and kiosk screen pinning support
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'expo-module-gradle-plugin'
|
||||
apply plugin: 'org.jetbrains.kotlin.android'
|
||||
|
||||
android {
|
||||
namespace "expo.modules.usbcamera"
|
||||
compileSdkVersion findProperty("expo.compileSdkVersion") ?: 34
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 23 // libausbc requires min SDK 23
|
||||
targetSdkVersion findProperty("expo.targetSdkVersion") ?: 34
|
||||
}
|
||||
|
||||
buildFeatures {
|
||||
buildConfig true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.facebook.react:react-android'
|
||||
// AndroidUSBCamera library for USB/UVC Webcams
|
||||
implementation 'com.github.jiangdongguo.AndroidUSBCamera:libausbc:3.3.3'
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package expo.modules.usbcamera
|
||||
|
||||
import expo.modules.kotlin.modules.Module
|
||||
import expo.modules.kotlin.modules.ModuleDefinition
|
||||
import expo.modules.kotlin.Promise
|
||||
|
||||
class UsbCameraModule : Module() {
|
||||
override fun definition() = ModuleDefinition {
|
||||
Name("UsbCamera")
|
||||
|
||||
View(UsbCameraView::class) {
|
||||
Events("onCameraReady")
|
||||
|
||||
AsyncFunction("takePicture") { view: UsbCameraView, savePath: String, promise: Promise ->
|
||||
view.takePicture(savePath, promise)
|
||||
}
|
||||
|
||||
AsyncFunction("isCameraConnected") { view: UsbCameraView, promise: Promise ->
|
||||
promise.resolve(view.isCameraConnected())
|
||||
}
|
||||
|
||||
OnViewDestroys { view ->
|
||||
view.onDestroy()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package expo.modules.usbcamera
|
||||
|
||||
import android.content.Context
|
||||
import android.widget.FrameLayout
|
||||
import android.util.AttributeSet
|
||||
import com.jiangdg.ausbc.CameraClient
|
||||
import com.jiangdg.ausbc.widget.AspectRatioTextureView
|
||||
import com.jiangdg.ausbc.camera.bean.CameraRequest
|
||||
import com.jiangdg.ausbc.camera.CameraUvcStrategy
|
||||
import com.jiangdg.ausbc.callback.ICaptureCallBack
|
||||
import expo.modules.kotlin.views.ExpoView
|
||||
import expo.modules.kotlin.AppContext
|
||||
import expo.modules.kotlin.Promise
|
||||
|
||||
class UsbCameraView(context: Context, appContext: AppContext) : ExpoView(context, appContext) {
|
||||
private val textureView: AspectRatioTextureView
|
||||
private var cameraClient: CameraClient? = null
|
||||
|
||||
init {
|
||||
textureView = AspectRatioTextureView(context)
|
||||
addView(textureView, LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT))
|
||||
|
||||
cameraClient = CameraClient.newBuilder(context)
|
||||
.setCameraStrategy(CameraUvcStrategy(context))
|
||||
.setEnableGLES(true)
|
||||
.build()
|
||||
|
||||
post {
|
||||
startPreview()
|
||||
}
|
||||
}
|
||||
|
||||
private fun startPreview() {
|
||||
try {
|
||||
val cameraRequest = CameraRequest.CameraRequestBuilder()
|
||||
.setPreviewWidth(1280)
|
||||
.setPreviewHeight(720)
|
||||
.create()
|
||||
cameraClient?.openCamera(textureView, cameraRequest)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
fun takePicture(savePath: String, promise: Promise) {
|
||||
val client = cameraClient
|
||||
if (client == null) {
|
||||
promise.reject("ERR_CAMERA_NOT_READY", "Camera client is not initialized", null)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
client.captureImage(object : ICaptureCallBack {
|
||||
override fun onBegin() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
override fun onError(error: String?) {
|
||||
promise.reject("ERR_CAPTURE_FAILED", error ?: "Unknown error", null)
|
||||
}
|
||||
|
||||
override fun onComplete(path: String?) {
|
||||
if (path != null) {
|
||||
promise.resolve(path)
|
||||
} else {
|
||||
promise.reject("ERR_CAPTURE_FAILED", "File path was null", null)
|
||||
}
|
||||
}
|
||||
}, savePath)
|
||||
} catch (e: Exception) {
|
||||
promise.reject("ERR_CAPTURE_EXCEPTION", e.message ?: "Capture threw an exception", e)
|
||||
}
|
||||
}
|
||||
|
||||
fun isCameraConnected(): Boolean {
|
||||
return cameraClient?.isCameraOpened ?: false
|
||||
}
|
||||
|
||||
fun onDestroy() {
|
||||
try {
|
||||
cameraClient?.closeCamera()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
cameraClient = null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"platforms": ["android"],
|
||||
"android": {
|
||||
"modules": [
|
||||
"expo.modules.usbcamera.UsbCameraModule"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
import { requireNativeViewManager } from 'expo-modules-core';
|
||||
import * as React from 'react';
|
||||
import { ViewProps, Platform } from 'react-native';
|
||||
|
||||
const viewName = 'UsbCamera';
|
||||
|
||||
export interface UsbCameraViewProps extends ViewProps {
|
||||
// Add props here if we decide to pass them from JS
|
||||
}
|
||||
|
||||
export interface UsbCameraRef {
|
||||
takePicture(savePath: string): Promise<string>;
|
||||
isCameraConnected(): Promise<boolean>;
|
||||
}
|
||||
|
||||
// Export the native view manager component
|
||||
export const UsbCameraView: React.ComponentType<UsbCameraViewProps & { ref?: React.RefObject<any> }> =
|
||||
Platform.OS === 'android'
|
||||
? requireNativeViewManager(viewName)
|
||||
: (() => null) as any;
|
||||
Reference in New Issue
Block a user