From a8e95400cc30cea1c4c8e516f11cb5aa4f14cb2f Mon Sep 17 00:00:00 2001 From: Mansi Date: Mon, 22 Dec 2025 23:47:58 +0530 Subject: [PATCH] Add CameraPreviewManager and CameraPreviewView for camera functionality --- App.tsx | 111 ++++++++---------- .../icamera/CameraPreviewManager.kt | 39 ++++++ .../lynkeduppro/icamera/CameraPreviewView.kt | 33 ++++++ 3 files changed, 121 insertions(+), 62 deletions(-) create mode 100644 android/app/src/main/java/com/lynkeduppro/icamera/CameraPreviewManager.kt create mode 100644 android/app/src/main/java/com/lynkeduppro/icamera/CameraPreviewView.kt diff --git a/App.tsx b/App.tsx index 0da7b7c..f71d746 100644 --- a/App.tsx +++ b/App.tsx @@ -1,3 +1,4 @@ +import React, { useEffect, useState } from 'react'; import { StatusBar, useColorScheme, @@ -11,7 +12,6 @@ import { ScrollView, } from 'react-native'; import { SafeAreaProvider } from 'react-native-safe-area-context'; -import { useState, useEffect } from 'react'; import Login from './src/components/Login'; import Register from './src/components/Register'; @@ -21,9 +21,10 @@ import { ScannerScreen } from './src/screens/ScannerScreen'; type Screen = 'login' | 'register' | 'home' | 'scanner'; -const { MyNativeModule } = NativeModules; +// ✅ Correct native module +const { ICameraSDK } = NativeModules; -function App() { +function App(): JSX.Element { const isDarkMode = useColorScheme() === 'dark'; const [currentScreen, setCurrentScreen] = useState('login'); @@ -38,10 +39,10 @@ function App() { useEffect(() => { initializeApp(); - console.log('MyNativeModule:', MyNativeModule); - MyNativeModule?.greet?.('John').then((msg: any) => { - console.log(msg); - }); + console.log('ICameraSDK:', ICameraSDK); + ICameraSDK?.greet?.('John') + .then((msg: string) => console.log(msg)) + .catch(console.error); const unsubscribe = networkService.addListener(networkState => { setIsOnline(networkState.isConnected); @@ -53,15 +54,14 @@ function App() { const initializeApp = async () => { try { await authAPI.initialize(); - - const isLoggedIn = await authAPI.isLoggedIn(); - if (isLoggedIn) { + const loggedIn = await authAPI.isLoggedIn(); + if (loggedIn) { const user = await authAPI.getCurrentUser(); setCurrentUser(user); setCurrentScreen('home'); } - } catch (error) { - console.error('Initialization error:', error); + } catch (e) { + console.error(e); } finally { setIsInitialized(true); } @@ -93,7 +93,6 @@ function App() { const handleLogout = async () => { try { await authAPI.logout(); - setQrCode(null); navigateToLogin(); Alert.alert('Success', 'Logged out successfully'); } catch { @@ -101,35 +100,20 @@ function App() { } }; - const showAppStatus = async () => { - try { - const status = await authAPI.getAppStatus(); - Alert.alert( - 'App Status', - `Network: ${status.network.isOnline ? 'Online' : 'Offline'} -Users: ${status.storage.totalUsers} -Current User: ${status.authentication.currentUser || 'None'} -Logged In: ${status.authentication.isLoggedIn ? 'Yes' : 'No'}` - ); - } catch { - Alert.alert('Error', 'Failed to get app status'); - } - }; - const generateQRCode = async () => { - if (!currentUser?.email) { - Alert.alert('Error', 'No user email available'); + if (!currentUser?.email || !ICameraSDK) { + Alert.alert('Error', 'Native QR module not available'); return; } setIsGeneratingQR(true); try { const qrData = `User: ${currentUser.fullName}\nEmail: ${currentUser.email}`; - const base64Image = await MyNativeModule.generateQRCode(qrData, 300, 300); - setQrCode(base64Image); - } catch (error) { - console.error(error); - Alert.alert('Error', 'Failed to generate QR code'); + const base64 = await ICameraSDK.generateQRCode(qrData, 300, 300); + setQrCode(base64); + } catch (e) { + console.error(e); + Alert.alert('Error', 'QR generation failed'); } finally { setIsGeneratingQR(false); } @@ -146,7 +130,7 @@ Logged In: ${status.authentication.isLoggedIn ? 'Yes' : 'No'}` ]); Alert.alert( - 'Scanned Successfully', + 'Scanned', `Code: ${result.code}\nFormat: ${result.format}`, [{ text: 'OK', onPress: () => setCurrentScreen('home') }] ); @@ -181,50 +165,46 @@ Logged In: ${status.authentication.isLoggedIn ? 'Yes' : 'No'}` case 'home': return ( - + Welcome, {currentUser?.fullName || 'User'} - {qrCode && ( - - )} + {qrCode && } - + Scan QR / Barcode - {isGeneratingQR ? 'Generating...' : 'Generate QR Code'} + {isGeneratingQR ? 'Generating...' : 'Generate QR'} - - App Status - - - + Logout ); - - default: - return null; } }; - /* -------------------- LOADING -------------------- */ if (!isInitialized) { return ( - - Initializing... + + Initializing... ); @@ -238,18 +218,25 @@ Logged In: ${status.authentication.isLoggedIn ? 'Yes' : 'No'}` ); } +export default App; + +/* -------------------- STYLES -------------------- */ + const styles = StyleSheet.create({ - loadingContainer: { flex: 1, justifyContent: 'center', alignItems: 'center' }, - loadingText: { fontSize: 18, fontWeight: '600' }, + loading: { flex: 1, justifyContent: 'center', alignItems: 'center' }, homeContainer: { flex: 1 }, scrollContent: { alignItems: 'center', padding: 20 }, welcomeText: { fontSize: 24, fontWeight: '700', marginBottom: 20 }, qrImage: { width: 300, height: 300, marginBottom: 20 }, - scannerButton: { backgroundColor: '#9333ea', padding: 14, borderRadius: 20, marginBottom: 10 }, - qrButton: { backgroundColor: '#10b981', padding: 14, borderRadius: 20, marginBottom: 10 }, - statusButton: { backgroundColor: '#3bb6d8', padding: 14, borderRadius: 20, marginBottom: 10 }, - logoutButton: { backgroundColor: '#ff6b6b', padding: 14, borderRadius: 20 }, + button: { + backgroundColor: '#6366f1', + padding: 14, + borderRadius: 18, + marginBottom: 12, + minWidth: 220, + alignItems: 'center', + }, + qrButton: { backgroundColor: '#10b981' }, + logoutButton: { backgroundColor: '#ef4444' }, buttonText: { color: '#fff', fontWeight: '600' }, }); - -export default App; diff --git a/android/app/src/main/java/com/lynkeduppro/icamera/CameraPreviewManager.kt b/android/app/src/main/java/com/lynkeduppro/icamera/CameraPreviewManager.kt new file mode 100644 index 0000000..ff2b8d5 --- /dev/null +++ b/android/app/src/main/java/com/lynkeduppro/icamera/CameraPreviewManager.kt @@ -0,0 +1,39 @@ +package com.lynkeduppro.camera + +import com.facebook.react.uimanager.SimpleViewManager +import com.facebook.react.uimanager.ThemedReactContext +import com.facebook.react.uimanager.annotations.ReactProp +import com.facebook.react.bridge.LifecycleEventListener + +class CameraPreviewManager : + SimpleViewManager(), + LifecycleEventListener { + + private var previewView: CameraPreviewView? = null + + override fun getName(): String = "CameraPreviewView" + + override fun createViewInstance(reactContext: ThemedReactContext): CameraPreviewView { + previewView = CameraPreviewView(reactContext) + reactContext.addLifecycleEventListener(this) + return previewView!! + } + + @ReactProp(name = "active") + fun setActive(view: CameraPreviewView, active: Boolean) { + if (active && reactContext is androidx.lifecycle.LifecycleOwner) { + view.startCamera(reactContext as androidx.lifecycle.LifecycleOwner) + } + } + + override fun onHostResume() { + previewView?.let { + if (reactContext is androidx.lifecycle.LifecycleOwner) { + it.startCamera(reactContext as androidx.lifecycle.LifecycleOwner) + } + } + } + + override fun onHostPause() {} + override fun onHostDestroy() {} +} diff --git a/android/app/src/main/java/com/lynkeduppro/icamera/CameraPreviewView.kt b/android/app/src/main/java/com/lynkeduppro/icamera/CameraPreviewView.kt new file mode 100644 index 0000000..9b80722 --- /dev/null +++ b/android/app/src/main/java/com/lynkeduppro/icamera/CameraPreviewView.kt @@ -0,0 +1,33 @@ +package com.lynkeduppro.camera + +import android.content.Context +import androidx.camera.core.CameraSelector +import androidx.camera.core.Preview +import androidx.camera.lifecycle.ProcessCameraProvider +import androidx.camera.view.PreviewView +import androidx.core.content.ContextCompat +import androidx.lifecycle.LifecycleOwner + +class CameraPreviewView(context: Context) : PreviewView(context) { + + fun startCamera(lifecycleOwner: LifecycleOwner) { + val cameraProviderFuture = ProcessCameraProvider.getInstance(context) + + cameraProviderFuture.addListener({ + val cameraProvider = cameraProviderFuture.get() + + val preview = Preview.Builder().build().also { + it.setSurfaceProvider(surfaceProvider) + } + + val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA + + cameraProvider.unbindAll() + cameraProvider.bindToLifecycle( + lifecycleOwner, + cameraSelector, + preview + ) + }, ContextCompat.getMainExecutor(context)) + } +}