10 changed files with 444 additions and 1468 deletions
@ -1,177 +0,0 @@ |
|||
--- |
|||
description: |
|||
globs: |
|||
alwaysApply: true |
|||
--- |
|||
# QR Code Handling Rule |
|||
|
|||
## Architecture Overview |
|||
|
|||
The QR code scanning functionality follows a platform-agnostic design using a factory pattern that provides different implementations for web and mobile platforms. |
|||
|
|||
### Core Components |
|||
|
|||
1. **Factory Pattern** |
|||
- `QRScannerFactory` - Creates appropriate scanner instance based on platform |
|||
- Common interface `QRScannerService` implemented by all scanners |
|||
- Platform detection via Capacitor and build flags |
|||
|
|||
2. **Platform-Specific Implementations** |
|||
- `CapacitorQRScanner` - Native mobile implementation using MLKit |
|||
- `WebInlineQRScanner` - Web browser implementation using MediaDevices API |
|||
- `QRScannerDialog.vue` - Shared UI component |
|||
|
|||
## Mobile Implementation (Capacitor) |
|||
|
|||
### Technology Stack |
|||
- Uses `@capacitor-mlkit/barcode-scanning` plugin |
|||
- Configured in `capacitor.config.ts` |
|||
- Native camera access through platform APIs |
|||
|
|||
### Key Features |
|||
- Direct camera access via native APIs |
|||
- Optimized for mobile performance |
|||
- Supports both iOS and Android |
|||
- Real-time QR code detection |
|||
- Back camera preferred for scanning |
|||
|
|||
### Configuration |
|||
```typescript |
|||
MLKitBarcodeScanner: { |
|||
formats: ['QR_CODE'], |
|||
detectorSize: 1.0, |
|||
lensFacing: 'back', |
|||
googleBarcodeScannerModuleInstallState: true |
|||
} |
|||
``` |
|||
|
|||
### Permissions Handling |
|||
1. Check permissions via `BarcodeScanner.checkPermissions()` |
|||
2. Request permissions if needed |
|||
3. Handle permission states (granted/denied) |
|||
4. Graceful fallbacks for permission issues |
|||
|
|||
## Web Implementation |
|||
|
|||
### Technology Stack |
|||
- Uses browser's MediaDevices API |
|||
- Vue.js components for UI |
|||
- EventEmitter for stream management |
|||
|
|||
### Key Features |
|||
- Browser-based camera access |
|||
- Inline camera preview |
|||
- Responsive design |
|||
- Cross-browser compatibility |
|||
- Progressive enhancement |
|||
|
|||
### Permissions Handling |
|||
1. Uses browser's permission API |
|||
2. MediaDevices API for camera access |
|||
3. Handles secure context requirements |
|||
4. Provides user feedback for permission states |
|||
|
|||
## Shared Features |
|||
|
|||
### Error Handling |
|||
1. Permission denied scenarios |
|||
2. Device compatibility checks |
|||
3. Camera access failures |
|||
4. QR code validation |
|||
5. Network connectivity issues |
|||
|
|||
### User Experience |
|||
1. Clear feedback during scanning |
|||
2. Loading states |
|||
3. Error messages |
|||
4. Success confirmations |
|||
5. Camera preview |
|||
|
|||
### Security |
|||
1. HTTPS requirement for web |
|||
2. Permission validation |
|||
3. Data validation |
|||
4. Safe error handling |
|||
|
|||
## Usage Guidelines |
|||
|
|||
### Platform Detection |
|||
```typescript |
|||
const isNative = QRScannerFactory.isNativePlatform(); |
|||
if (isNative) { |
|||
// Use native scanner |
|||
} else { |
|||
// Use web scanner |
|||
} |
|||
``` |
|||
|
|||
### Implementation Example |
|||
```typescript |
|||
const scanner = QRScannerFactory.getInstance(); |
|||
await scanner.checkPermissions(); |
|||
await scanner.startScan(); |
|||
scanner.addListener({ |
|||
onScan: (result) => { |
|||
// Handle scan result |
|||
}, |
|||
onError: (error) => { |
|||
// Handle error |
|||
} |
|||
}); |
|||
``` |
|||
|
|||
### Best Practices |
|||
1. Always check permissions before starting scan |
|||
2. Clean up resources after scanning |
|||
3. Handle all error cases |
|||
4. Provide clear user feedback |
|||
5. Test on multiple devices/browsers |
|||
|
|||
## Platform-Specific Notes |
|||
|
|||
### Mobile (Capacitor) |
|||
1. Use native camera API when available |
|||
2. Handle device rotation |
|||
3. Support both front/back cameras |
|||
4. Manage system permissions properly |
|||
5. Handle app lifecycle events |
|||
|
|||
### Web |
|||
1. Check browser compatibility |
|||
2. Handle secure context requirement |
|||
3. Manage memory usage |
|||
4. Clean up MediaStream |
|||
5. Handle tab visibility changes |
|||
|
|||
## Testing Requirements |
|||
|
|||
1. Test on multiple devices |
|||
2. Verify permission flows |
|||
3. Check error handling |
|||
4. Validate cleanup |
|||
5. Verify cross-platform behavior |
|||
|
|||
## Service Interface |
|||
|
|||
```typescript |
|||
interface QRScannerService { |
|||
checkPermissions(): Promise<boolean>; |
|||
requestPermissions(): Promise<boolean>; |
|||
isSupported(): Promise<boolean>; |
|||
startScan(options?: QRScannerOptions): Promise<void>; |
|||
stopScan(): Promise<void>; |
|||
addListener(listener: ScanListener): void; |
|||
onStream(callback: (stream: MediaStream | null) => void): void; |
|||
cleanup(): Promise<void>; |
|||
} |
|||
|
|||
interface ScanListener { |
|||
onScan: (result: string) => void; |
|||
onError?: (error: Error) => void; |
|||
} |
|||
|
|||
interface QRScannerOptions { |
|||
camera?: "front" | "back"; |
|||
showPreview?: boolean; |
|||
playSound?: boolean; |
|||
} |
@ -1,533 +0,0 @@ |
|||
--- |
|||
description: |
|||
globs: |
|||
alwaysApply: true |
|||
--- |
|||
# QR Code Implementation Guide |
|||
|
|||
## Directory Structure |
|||
|
|||
``` |
|||
src/ |
|||
├── services/ |
|||
│ └── QRScanner/ |
|||
│ ├── types.ts # Core interfaces and types |
|||
│ ├── QRScannerFactory.ts # Factory for creating scanner instances |
|||
│ ├── CapacitorQRScanner.ts # Mobile implementation using MLKit |
|||
│ ├── WebInlineQRScanner.ts # Web implementation using MediaDevices API |
|||
│ └── interfaces.ts # Additional interfaces |
|||
├── components/ |
|||
│ └── QRScanner/ |
|||
│ └── QRScannerDialog.vue # Shared UI component |
|||
``` |
|||
|
|||
## Core Interfaces |
|||
|
|||
```typescript |
|||
// types.ts |
|||
export interface ScanListener { |
|||
onScan: (result: string) => void; |
|||
onError?: (error: Error) => void; |
|||
} |
|||
|
|||
export interface QRScannerOptions { |
|||
camera?: "front" | "back"; |
|||
showPreview?: boolean; |
|||
playSound?: boolean; |
|||
} |
|||
|
|||
export interface QRScannerService { |
|||
checkPermissions(): Promise<boolean>; |
|||
requestPermissions(): Promise<boolean>; |
|||
isSupported(): Promise<boolean>; |
|||
startScan(options?: QRScannerOptions): Promise<void>; |
|||
stopScan(): Promise<void>; |
|||
addListener(listener: ScanListener): void; |
|||
onStream(callback: (stream: MediaStream | null) => void): void; |
|||
cleanup(): Promise<void>; |
|||
} |
|||
``` |
|||
|
|||
## Configuration Files |
|||
|
|||
### Vite Configuration |
|||
```typescript |
|||
// vite.config.common.mts |
|||
export function createBuildConfig(mode: string) { |
|||
return { |
|||
define: { |
|||
'process.env.VITE_PLATFORM': JSON.stringify(mode), |
|||
'process.env.VITE_PWA_ENABLED': JSON.stringify(!isNative), |
|||
__IS_MOBILE__: JSON.stringify(isCapacitor), |
|||
__USE_QR_READER__: JSON.stringify(!isCapacitor) |
|||
} |
|||
}; |
|||
} |
|||
``` |
|||
|
|||
### Capacitor Configuration |
|||
```typescript |
|||
// capacitor.config.ts |
|||
const config: CapacitorConfig = { |
|||
plugins: { |
|||
MLKitBarcodeScanner: { |
|||
formats: ['QR_CODE'], |
|||
detectorSize: 1.0, |
|||
lensFacing: 'back', |
|||
googleBarcodeScannerModuleInstallState: true |
|||
} |
|||
} |
|||
}; |
|||
``` |
|||
|
|||
## Implementation Steps |
|||
|
|||
1. **Install Dependencies** |
|||
```bash |
|||
npm install @capacitor-mlkit/barcode-scanning |
|||
``` |
|||
|
|||
2. **Create Core Types** |
|||
Create the interface files as shown above. |
|||
|
|||
3. **Implement Factory** |
|||
```typescript |
|||
// QRScannerFactory.ts |
|||
export class QRScannerFactory { |
|||
private static instance: QRScannerService | null = null; |
|||
|
|||
private static isNativePlatform(): boolean { |
|||
const capacitorNative = Capacitor.isNativePlatform(); |
|||
const isMobile = typeof __IS_MOBILE__ !== "undefined" ? __IS_MOBILE__ : capacitorNative; |
|||
const platform = Capacitor.getPlatform(); |
|||
|
|||
// Always use native scanner on Android/iOS |
|||
if (platform === "android" || platform === "ios") { |
|||
return true; |
|||
} |
|||
|
|||
// For other platforms, use native if available |
|||
return capacitorNative || isMobile; |
|||
} |
|||
|
|||
static getInstance(): QRScannerService { |
|||
if (!this.instance) { |
|||
const isNative = this.isNativePlatform(); |
|||
|
|||
if (isNative) { |
|||
this.instance = new CapacitorQRScanner(); |
|||
} else { |
|||
this.instance = new WebInlineQRScanner(); |
|||
} |
|||
} |
|||
return this.instance!; |
|||
} |
|||
|
|||
static async cleanup(): Promise<void> { |
|||
if (this.instance) { |
|||
await this.instance.cleanup(); |
|||
this.instance = null; |
|||
} |
|||
} |
|||
} |
|||
``` |
|||
|
|||
4. **Implement Mobile Scanner** |
|||
```typescript |
|||
// CapacitorQRScanner.ts |
|||
export class CapacitorQRScanner implements QRScannerService { |
|||
private scanListener: ScanListener | null = null; |
|||
private isScanning = false; |
|||
private listenerHandles: Array<() => Promise<void>> = []; |
|||
private cleanupPromise: Promise<void> | null = null; |
|||
|
|||
async checkPermissions(): Promise<boolean> { |
|||
try { |
|||
const { camera } = await BarcodeScanner.checkPermissions(); |
|||
return camera === "granted"; |
|||
} catch (error) { |
|||
logger.error("Error checking camera permissions:", error); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
async requestPermissions(): Promise<boolean> { |
|||
try { |
|||
if (await this.checkPermissions()) { |
|||
return true; |
|||
} |
|||
const { camera } = await BarcodeScanner.requestPermissions(); |
|||
return camera === "granted"; |
|||
} catch (error) { |
|||
logger.error("Error requesting camera permissions:", error); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
async isSupported(): Promise<boolean> { |
|||
try { |
|||
const { supported } = await BarcodeScanner.isSupported(); |
|||
return supported; |
|||
} catch (error) { |
|||
logger.error("Error checking scanner support:", error); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
async startScan(options?: QRScannerOptions): Promise<void> { |
|||
if (this.isScanning) return; |
|||
if (this.cleanupPromise) { |
|||
await this.cleanupPromise; |
|||
} |
|||
|
|||
try { |
|||
if (!(await this.checkPermissions())) { |
|||
const granted = await this.requestPermissions(); |
|||
if (!granted) { |
|||
throw new Error("Camera permission denied"); |
|||
} |
|||
} |
|||
|
|||
if (!(await this.isSupported())) { |
|||
throw new Error("QR scanning not supported on this device"); |
|||
} |
|||
|
|||
this.isScanning = true; |
|||
|
|||
const scanOptions: StartScanOptions = { |
|||
formats: [BarcodeFormat.QrCode], |
|||
lensFacing: options?.camera === "front" ? LensFacing.Front : LensFacing.Back, |
|||
}; |
|||
|
|||
const handle = await BarcodeScanner.addListener("barcodeScanned", (result) => { |
|||
if (this.scanListener && result.barcode?.rawValue) { |
|||
this.scanListener.onScan(result.barcode.rawValue); |
|||
} |
|||
}); |
|||
this.listenerHandles.push(handle.remove); |
|||
|
|||
await BarcodeScanner.startScan(scanOptions); |
|||
} catch (error) { |
|||
this.isScanning = false; |
|||
await this.cleanup(); |
|||
this.scanListener?.onError?.(error instanceof Error ? error : new Error(String(error))); |
|||
throw error; |
|||
} |
|||
} |
|||
|
|||
async stopScan(): Promise<void> { |
|||
if (!this.isScanning) return; |
|||
this.isScanning = false; |
|||
|
|||
try { |
|||
await BarcodeScanner.stopScan(); |
|||
} catch (error) { |
|||
logger.error("Error stopping scan:", error); |
|||
throw error; |
|||
} |
|||
} |
|||
|
|||
addListener(listener: ScanListener): void { |
|||
this.scanListener = listener; |
|||
} |
|||
|
|||
onStream(callback: (stream: MediaStream | null) => void): void { |
|||
// No-op for native scanner |
|||
callback(null); |
|||
} |
|||
|
|||
async cleanup(): Promise<void> { |
|||
await this.stopScan(); |
|||
for (const handle of this.listenerHandles) { |
|||
await handle(); |
|||
} |
|||
this.listenerHandles = []; |
|||
this.scanListener = null; |
|||
} |
|||
} |
|||
``` |
|||
|
|||
5. **Implement Web Scanner** |
|||
```typescript |
|||
// WebInlineQRScanner.ts |
|||
export class WebInlineQRScanner implements QRScannerService { |
|||
private scanListener: ScanListener | null = null; |
|||
private isScanning = false; |
|||
private stream: MediaStream | null = null; |
|||
private events = new EventEmitter(); |
|||
|
|||
constructor(private options?: QRScannerOptions) {} |
|||
|
|||
async checkPermissions(): Promise<boolean> { |
|||
try { |
|||
const permissions = await navigator.permissions.query({ |
|||
name: "camera" as PermissionName, |
|||
}); |
|||
return permissions.state === "granted"; |
|||
} catch (error) { |
|||
logger.error("Error checking camera permissions:", error); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
async requestPermissions(): Promise<boolean> { |
|||
try { |
|||
const stream = await navigator.mediaDevices.getUserMedia({ |
|||
video: { |
|||
facingMode: "environment", |
|||
width: { ideal: 1280 }, |
|||
height: { ideal: 720 }, |
|||
}, |
|||
}); |
|||
stream.getTracks().forEach(track => track.stop()); |
|||
return true; |
|||
} catch (error) { |
|||
logger.error("Error requesting camera permissions:", error); |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
async isSupported(): Promise<boolean> { |
|||
return 'mediaDevices' in navigator && 'getUserMedia' in navigator.mediaDevices; |
|||
} |
|||
|
|||
async startScan(): Promise<void> { |
|||
if (this.isScanning) return; |
|||
|
|||
try { |
|||
this.isScanning = true; |
|||
this.stream = await navigator.mediaDevices.getUserMedia({ |
|||
video: { |
|||
facingMode: "environment", |
|||
width: { ideal: 1280 }, |
|||
height: { ideal: 720 }, |
|||
}, |
|||
}); |
|||
this.events.emit("stream", this.stream); |
|||
} catch (error) { |
|||
this.isScanning = false; |
|||
const wrappedError = error instanceof Error ? error : new Error(String(error)); |
|||
this.scanListener?.onError?.(wrappedError); |
|||
throw wrappedError; |
|||
} |
|||
} |
|||
|
|||
async stopScan(): Promise<void> { |
|||
if (!this.isScanning) return; |
|||
|
|||
try { |
|||
if (this.stream) { |
|||
this.stream.getTracks().forEach(track => track.stop()); |
|||
this.stream = null; |
|||
} |
|||
this.events.emit("stream", null); |
|||
} catch (error) { |
|||
logger.error("Error stopping scan:", error); |
|||
throw error; |
|||
} finally { |
|||
this.isScanning = false; |
|||
} |
|||
} |
|||
|
|||
addListener(listener: ScanListener): void { |
|||
this.scanListener = listener; |
|||
} |
|||
|
|||
onStream(callback: (stream: MediaStream | null) => void): void { |
|||
this.events.on("stream", callback); |
|||
} |
|||
|
|||
async cleanup(): Promise<void> { |
|||
try { |
|||
await this.stopScan(); |
|||
this.events.removeAllListeners(); |
|||
} catch (error) { |
|||
logger.error("Error during cleanup:", error); |
|||
} |
|||
} |
|||
} |
|||
``` |
|||
|
|||
## Usage Example |
|||
|
|||
```typescript |
|||
// Example usage in a Vue component |
|||
import { QRScannerFactory } from '@/services/QRScanner/QRScannerFactory'; |
|||
|
|||
export default defineComponent({ |
|||
async mounted() { |
|||
const scanner = QRScannerFactory.getInstance(); |
|||
|
|||
try { |
|||
// Check and request permissions |
|||
if (!(await scanner.checkPermissions())) { |
|||
const granted = await scanner.requestPermissions(); |
|||
if (!granted) { |
|||
throw new Error('Camera permission denied'); |
|||
} |
|||
} |
|||
|
|||
// Add scan listener |
|||
scanner.addListener({ |
|||
onScan: (result) => { |
|||
console.log('QR Code scanned:', result); |
|||
}, |
|||
onError: (error) => { |
|||
console.error('Scan error:', error); |
|||
} |
|||
}); |
|||
|
|||
// Start scanning |
|||
await scanner.startScan({ |
|||
camera: 'back', |
|||
showPreview: true |
|||
}); |
|||
|
|||
// Handle stream for preview |
|||
scanner.onStream((stream) => { |
|||
if (stream) { |
|||
// Update video element with stream |
|||
this.videoElement.srcObject = stream; |
|||
} |
|||
}); |
|||
} catch (error) { |
|||
console.error('Failed to start scanner:', error); |
|||
} |
|||
}, |
|||
|
|||
async beforeUnmount() { |
|||
// Clean up scanner |
|||
await QRScannerFactory.cleanup(); |
|||
} |
|||
}); |
|||
``` |
|||
|
|||
## Best Practices |
|||
|
|||
1. **Error Handling** |
|||
- Always implement error handlers in scan listeners |
|||
- Handle permission denials gracefully |
|||
- Provide user feedback for errors |
|||
- Clean up resources on errors |
|||
|
|||
2. **Resource Management** |
|||
- Always call cleanup when done |
|||
- Stop camera streams properly |
|||
- Remove event listeners |
|||
- Handle component unmounting |
|||
|
|||
3. **Performance** |
|||
- Use appropriate camera resolution |
|||
- Clean up resources promptly |
|||
- Handle platform-specific optimizations |
|||
- Monitor memory usage |
|||
|
|||
4. **Security** |
|||
- Require HTTPS for web implementation |
|||
- Validate scanned data |
|||
- Handle permissions properly |
|||
- Sanitize user input |
|||
|
|||
5. **Testing** |
|||
- Test on multiple devices |
|||
- Verify permission flows |
|||
- Check error scenarios |
|||
- Validate cleanup |
|||
- Test cross-platform behavior |
|||
|
|||
## Platform-Specific Notes |
|||
|
|||
### Mobile (Capacitor) |
|||
- Uses MLKit for optimal performance |
|||
- Handles native permissions |
|||
- Supports both iOS and Android |
|||
- Uses back camera by default |
|||
- Handles device rotation |
|||
- Provides native UI for scanning |
|||
|
|||
### Web |
|||
- Uses MediaDevices API |
|||
- Requires HTTPS for camera access |
|||
- Handles browser compatibility |
|||
- Manages memory and resources |
|||
- Provides fallback UI |
|||
- Uses vue-qrcode-reader for web scanning |
|||
|
|||
## Testing |
|||
|
|||
1. **Unit Tests** |
|||
- Test factory pattern |
|||
- Test platform detection |
|||
- Test error handling |
|||
- Test cleanup procedures |
|||
- Test permission flows |
|||
|
|||
2. **Integration Tests** |
|||
- Test camera access |
|||
- Test QR code detection |
|||
- Test cross-platform behavior |
|||
- Test UI components |
|||
- Test error scenarios |
|||
|
|||
3. **E2E Tests** |
|||
- Test complete scanning flow |
|||
- Test permission handling |
|||
- Test cross-platform compatibility |
|||
- Test error recovery |
|||
- Test cleanup procedures |
|||
|
|||
## Best Practices |
|||
|
|||
1. **Error Handling** |
|||
- Always handle permission errors gracefully |
|||
- Provide clear error messages to users |
|||
- Implement proper cleanup on errors |
|||
- Log errors for debugging |
|||
|
|||
2. **Performance** |
|||
- Clean up resources when not in use |
|||
- Handle device rotation properly |
|||
- Optimize camera usage |
|||
- Manage memory efficiently |
|||
|
|||
3. **Security** |
|||
- Request minimum required permissions |
|||
- Handle sensitive data securely |
|||
- Validate scanned data |
|||
- Implement proper cleanup |
|||
|
|||
4. **User Experience** |
|||
- Provide clear feedback |
|||
- Handle edge cases gracefully |
|||
- Support both platforms seamlessly |
|||
- Implement proper loading states |
|||
|
|||
## Troubleshooting |
|||
|
|||
1. **Common Issues** |
|||
- Camera permissions denied |
|||
- Device not supported |
|||
- Scanner not working |
|||
- Memory leaks |
|||
- UI glitches |
|||
|
|||
2. **Solutions** |
|||
- Check permissions |
|||
- Verify device support |
|||
- Debug scanner implementation |
|||
- Monitor memory usage |
|||
- Test UI components |
|||
|
|||
## Maintenance |
|||
|
|||
1. **Regular Updates** |
|||
- Keep dependencies updated |
|||
- Monitor platform changes |
|||
- Update documentation |
|||
- Review security patches |
|||
|
|||
2. **Performance Monitoring** |
|||
- Track memory usage |
|||
- Monitor camera performance |
|||
- Check error rates |
|||
- Analyze user feedback |
@ -0,0 +1,284 @@ |
|||
# QR Code Implementation Guide |
|||
|
|||
## Overview |
|||
|
|||
This document describes the QR code scanning and generation implementation in the TimeSafari application. The system uses a platform-agnostic design with specific implementations for web and mobile platforms. |
|||
|
|||
## Architecture |
|||
|
|||
### Directory Structure |
|||
``` |
|||
src/ |
|||
├── services/ |
|||
│ └── QRScanner/ |
|||
│ ├── types.ts # Core interfaces and types |
|||
│ ├── QRScannerFactory.ts # Factory for creating scanner instances |
|||
│ ├── CapacitorQRScanner.ts # Mobile implementation using MLKit |
|||
│ ├── WebInlineQRScanner.ts # Web implementation using MediaDevices API |
|||
│ └── interfaces.ts # Additional interfaces |
|||
├── components/ |
|||
│ └── QRScanner/ |
|||
│ └── QRScannerDialog.vue # Shared UI component |
|||
└── views/ |
|||
├── ContactQRScanView.vue # Dedicated scanning view |
|||
└── ContactQRScanShowView.vue # Combined QR display and scanning view |
|||
``` |
|||
|
|||
### Core Components |
|||
|
|||
1. **Factory Pattern** |
|||
- `QRScannerFactory` - Creates appropriate scanner instance based on platform |
|||
- Common interface `QRScannerService` implemented by all scanners |
|||
- Platform detection via Capacitor and build flags |
|||
|
|||
2. **Platform-Specific Implementations** |
|||
- `CapacitorQRScanner` - Native mobile implementation using MLKit |
|||
- `WebInlineQRScanner` - Web browser implementation using MediaDevices API |
|||
- `QRScannerDialog.vue` - Shared UI component |
|||
|
|||
3. **View Components** |
|||
- `ContactQRScanView` - Dedicated view for scanning QR codes |
|||
- `ContactQRScanShowView` - Combined view for displaying and scanning QR codes |
|||
|
|||
## Implementation Details |
|||
|
|||
### Core Interfaces |
|||
|
|||
```typescript |
|||
interface QRScannerService { |
|||
checkPermissions(): Promise<boolean>; |
|||
requestPermissions(): Promise<boolean>; |
|||
isSupported(): Promise<boolean>; |
|||
startScan(options?: QRScannerOptions): Promise<void>; |
|||
stopScan(): Promise<void>; |
|||
addListener(listener: ScanListener): void; |
|||
onStream(callback: (stream: MediaStream | null) => void): void; |
|||
cleanup(): Promise<void>; |
|||
} |
|||
|
|||
interface ScanListener { |
|||
onScan: (result: string) => void; |
|||
onError?: (error: Error) => void; |
|||
} |
|||
|
|||
interface QRScannerOptions { |
|||
camera?: "front" | "back"; |
|||
showPreview?: boolean; |
|||
playSound?: boolean; |
|||
} |
|||
``` |
|||
|
|||
### Platform-Specific Implementations |
|||
|
|||
#### Mobile (Capacitor) |
|||
- Uses `@capacitor-mlkit/barcode-scanning` |
|||
- Native camera access through platform APIs |
|||
- Optimized for mobile performance |
|||
- Supports both iOS and Android |
|||
- Real-time QR code detection |
|||
- Back camera preferred for scanning |
|||
|
|||
Configuration: |
|||
```typescript |
|||
// capacitor.config.ts |
|||
const config: CapacitorConfig = { |
|||
plugins: { |
|||
MLKitBarcodeScanner: { |
|||
formats: ['QR_CODE'], |
|||
detectorSize: 1.0, |
|||
lensFacing: 'back', |
|||
googleBarcodeScannerModuleInstallState: true |
|||
} |
|||
} |
|||
}; |
|||
``` |
|||
|
|||
#### Web |
|||
- Uses browser's MediaDevices API |
|||
- Vue.js components for UI |
|||
- EventEmitter for stream management |
|||
- Browser-based camera access |
|||
- Inline camera preview |
|||
- Responsive design |
|||
- Cross-browser compatibility |
|||
|
|||
### View Components |
|||
|
|||
#### ContactQRScanView |
|||
- Dedicated view for scanning QR codes |
|||
- Full-screen camera interface |
|||
- Simple UI focused on scanning |
|||
- Used primarily on native platforms |
|||
- Streamlined scanning experience |
|||
|
|||
#### ContactQRScanShowView |
|||
- Combined view for QR code display and scanning |
|||
- Shows user's own QR code |
|||
- Handles user registration status |
|||
- Provides options to copy contact information |
|||
- Platform-specific scanning implementation: |
|||
- Native: Button to navigate to ContactQRScanView |
|||
- Web: Built-in scanning functionality |
|||
|
|||
### QR Code Workflow |
|||
|
|||
1. **Initiation** |
|||
- User selects "Scan QR Code" option |
|||
- Platform-specific scanner is initialized |
|||
- Camera permissions are verified |
|||
- Appropriate scanner component is loaded |
|||
|
|||
2. **Platform-Specific Implementation** |
|||
- Web: Uses `qrcode-stream` for real-time scanning |
|||
- Native: Uses `@capacitor-mlkit/barcode-scanning` |
|||
|
|||
3. **Scanning Process** |
|||
- Camera stream initialization |
|||
- Real-time frame analysis |
|||
- QR code detection and decoding |
|||
- Validation of QR code format |
|||
- Processing of contact information |
|||
|
|||
4. **Contact Processing** |
|||
- Decryption of contact data |
|||
- Validation of user information |
|||
- Verification of timestamp |
|||
- Check for duplicate contacts |
|||
- Processing of shared data |
|||
|
|||
## Build Configuration |
|||
|
|||
### Common Vite Configuration |
|||
```typescript |
|||
// vite.config.common.mts |
|||
export async function createBuildConfig(mode: string) { |
|||
const isCapacitor = mode === "capacitor"; |
|||
|
|||
return defineConfig({ |
|||
define: { |
|||
'process.env.VITE_PLATFORM': JSON.stringify(mode), |
|||
'process.env.VITE_PWA_ENABLED': JSON.stringify(!isNative), |
|||
__IS_MOBILE__: JSON.stringify(isCapacitor), |
|||
__USE_QR_READER__: JSON.stringify(!isCapacitor) |
|||
}, |
|||
optimizeDeps: { |
|||
include: [ |
|||
'@capacitor-mlkit/barcode-scanning', |
|||
'vue-qrcode-reader' |
|||
] |
|||
} |
|||
}); |
|||
} |
|||
``` |
|||
|
|||
### Platform-Specific Builds |
|||
```json |
|||
{ |
|||
"scripts": { |
|||
"build:web": "vite build --config vite.config.web.mts", |
|||
"build:capacitor": "vite build --config vite.config.capacitor.mts", |
|||
"build:all": "npm run build:web && npm run build:capacitor" |
|||
} |
|||
} |
|||
``` |
|||
|
|||
## Error Handling |
|||
|
|||
### Common Error Scenarios |
|||
1. No camera found |
|||
2. Permission denied |
|||
3. Camera in use by another application |
|||
4. HTTPS required |
|||
5. Browser compatibility issues |
|||
6. Invalid QR code format |
|||
7. Expired QR codes |
|||
8. Duplicate contact attempts |
|||
9. Network connectivity issues |
|||
|
|||
### Error Response |
|||
- User-friendly error messages |
|||
- Troubleshooting tips |
|||
- Clear instructions for resolution |
|||
- Platform-specific guidance |
|||
|
|||
## Security Considerations |
|||
|
|||
### QR Code Security |
|||
- Encryption of contact data |
|||
- Timestamp validation |
|||
- Version checking |
|||
- User verification |
|||
- Rate limiting for scans |
|||
|
|||
### Data Protection |
|||
- Secure transmission of contact data |
|||
- Validation of QR code authenticity |
|||
- Prevention of duplicate scans |
|||
- Protection against malicious codes |
|||
- Secure storage of contact information |
|||
|
|||
## Best Practices |
|||
|
|||
### Camera Access |
|||
1. Always check for camera availability |
|||
2. Request permissions explicitly |
|||
3. Handle all error conditions |
|||
4. Provide clear user feedback |
|||
5. Implement proper cleanup |
|||
|
|||
### Performance |
|||
1. Optimize camera resolution |
|||
2. Implement proper resource cleanup |
|||
3. Handle camera switching efficiently |
|||
4. Manage memory usage |
|||
5. Battery usage optimization |
|||
|
|||
### User Experience |
|||
1. Clear visual feedback |
|||
2. Camera preview |
|||
3. Scanning status indicators |
|||
4. Error messages |
|||
5. Success confirmations |
|||
6. Intuitive camera controls |
|||
7. Smooth camera switching |
|||
8. Responsive UI feedback |
|||
|
|||
## Testing |
|||
|
|||
### Test Scenarios |
|||
1. Permission handling |
|||
2. Camera switching |
|||
3. Error conditions |
|||
4. Platform compatibility |
|||
5. Performance metrics |
|||
6. QR code detection |
|||
7. Contact processing |
|||
8. Security validation |
|||
|
|||
### Test Environment |
|||
- Multiple browsers |
|||
- iOS and Android devices |
|||
- Various network conditions |
|||
- Different camera configurations |
|||
|
|||
## Dependencies |
|||
|
|||
### Key Packages |
|||
- `@capacitor-mlkit/barcode-scanning` |
|||
- `qrcode-stream` |
|||
- `vue-qrcode-reader` |
|||
- Platform-specific camera APIs |
|||
|
|||
## Maintenance |
|||
|
|||
### Regular Updates |
|||
- Keep dependencies updated |
|||
- Monitor platform changes |
|||
- Update documentation |
|||
- Review security patches |
|||
|
|||
### Performance Monitoring |
|||
- Track memory usage |
|||
- Monitor camera performance |
|||
- Check error rates |
|||
- Analyze user feedback |
@ -1,507 +0,0 @@ |
|||
# Camera Implementation Documentation |
|||
|
|||
## Overview |
|||
|
|||
This document describes how camera functionality is implemented across the TimeSafari application. The application uses cameras for several purposes: |
|||
|
|||
1. QR Code scanning for contact sharing and verification |
|||
2. Photo capture for gift records |
|||
3. Profile photo management |
|||
4. Shared photo handling |
|||
5. Image upload and processing |
|||
|
|||
## Components |
|||
|
|||
### QRScannerDialog.vue |
|||
|
|||
Primary component for QR code scanning in web browsers. |
|||
|
|||
**Key Features:** |
|||
|
|||
- Uses `qrcode-stream` for web-based QR scanning |
|||
- Supports both front and back cameras |
|||
- Provides real-time camera status feedback |
|||
- Implements error handling with user-friendly messages |
|||
- Includes camera switching functionality |
|||
|
|||
**Camera Access Flow:** |
|||
|
|||
1. Checks for camera API availability |
|||
2. Enumerates available video devices |
|||
3. Requests camera permissions |
|||
4. Initializes camera stream with preferred settings |
|||
5. Handles various error conditions with specific messages |
|||
|
|||
### PhotoDialog.vue |
|||
|
|||
Component for photo capture and selection. |
|||
|
|||
**Key Features:** |
|||
|
|||
- Cross-platform photo capture interface |
|||
- Image cropping capabilities |
|||
- File selection fallback |
|||
- Unified interface for different platforms |
|||
- Progress feedback during upload |
|||
- Comprehensive error handling |
|||
|
|||
**Camera Access Flow:** |
|||
|
|||
1. User initiates photo capture |
|||
2. Platform-specific camera access is requested |
|||
3. Image is captured or selected |
|||
4. Optional cropping is performed |
|||
5. Image is processed and uploaded |
|||
6. URL is returned to caller |
|||
|
|||
### ImageMethodDialog.vue |
|||
|
|||
Component for selecting image input method. |
|||
|
|||
**Key Features:** |
|||
- Multiple input methods (camera, file upload, URL) |
|||
- Unified interface for image selection |
|||
- Integration with PhotoDialog for processing |
|||
- Support for image cropping |
|||
- URL-based image handling |
|||
|
|||
**Camera Access Flow:** |
|||
|
|||
1. User selects camera option |
|||
2. PhotoDialog is opened for capture |
|||
3. Captured image is processed |
|||
4. Image is returned to parent component |
|||
|
|||
### SharedPhotoView.vue |
|||
|
|||
Component for handling shared photos. |
|||
|
|||
**Key Features:** |
|||
- Processes incoming shared photos |
|||
- Options to use photo for gifts or profile |
|||
- Image preview and confirmation |
|||
- Server upload integration |
|||
- Temporary storage management |
|||
|
|||
**Photo Processing Flow:** |
|||
|
|||
1. Photo is shared to application |
|||
2. Stored temporarily in IndexedDB |
|||
3. User chooses usage (gift/profile) |
|||
4. Image is processed accordingly |
|||
5. Server upload is performed |
|||
|
|||
### ContactQRScanShowView.vue |
|||
|
|||
Component for QR code scanning in contact sharing. |
|||
|
|||
**Key Features:** |
|||
- QR code scanning interface |
|||
- Camera controls (start/stop) |
|||
- Platform-specific implementations |
|||
- Error handling and status feedback |
|||
|
|||
**Camera Access Flow:** |
|||
|
|||
1. User initiates scanning |
|||
2. Camera permissions are checked |
|||
3. Camera stream is initialized |
|||
4. QR codes are detected in real-time |
|||
5. Results are processed |
|||
|
|||
## Services |
|||
|
|||
### QRScanner Services |
|||
|
|||
#### WebDialogQRScanner |
|||
|
|||
Web-based implementation of QR scanning. |
|||
|
|||
**Key Methods:** |
|||
|
|||
- `checkPermissions()`: Verifies camera permission status |
|||
- `requestPermissions()`: Requests camera access |
|||
- `isSupported()`: Checks for camera API support |
|||
- Handles various error conditions with specific messages |
|||
|
|||
#### CapacitorQRScanner |
|||
|
|||
Native implementation using Capacitor's MLKit. |
|||
|
|||
**Key Features:** |
|||
|
|||
- Uses `@capacitor-mlkit/barcode-scanning` |
|||
- Supports both front and back cameras |
|||
- Implements permission management |
|||
- Provides continuous scanning capability |
|||
|
|||
### Platform Services |
|||
|
|||
#### WebPlatformService |
|||
|
|||
Web-specific implementation of platform features. |
|||
|
|||
**Camera Capabilities:** |
|||
|
|||
- Uses HTML5 file input with capture attribute for mobile |
|||
- Uses getUserMedia API for desktop webcam access |
|||
- Falls back to file selection if camera unavailable |
|||
- Processes captured images for consistent format |
|||
- Handles both mobile and desktop browser environments |
|||
|
|||
#### CapacitorPlatformService |
|||
|
|||
Native implementation using Capacitor. |
|||
|
|||
**Camera Features:** |
|||
|
|||
- Uses `Camera.getPhoto()` for native camera access |
|||
- Supports image editing |
|||
- Configures high-quality image capture |
|||
- Handles base64 image processing |
|||
- Provides native camera UI |
|||
|
|||
#### ElectronPlatformService |
|||
|
|||
Desktop implementation (currently unimplemented). |
|||
|
|||
**Status:** |
|||
|
|||
- Camera functionality not yet implemented |
|||
- Planned to use Electron's media APIs |
|||
- Will support desktop camera access |
|||
|
|||
## Camera Usage Scenarios |
|||
|
|||
### Gift Photo Capture |
|||
|
|||
**Implementation:** |
|||
- Uses PhotoDialog for capture/selection |
|||
- Supports multiple input methods |
|||
- Optional image cropping |
|||
- Server upload with authentication |
|||
- Integration with gift records |
|||
|
|||
**Flow:** |
|||
1. User initiates photo capture from gift details |
|||
2. ImageMethodDialog presents input options |
|||
3. PhotoDialog handles capture/selection |
|||
4. Image is processed and uploaded |
|||
5. URL is attached to gift record |
|||
|
|||
### Profile Photo Management |
|||
|
|||
**Implementation:** |
|||
- Uses same PhotoDialog component |
|||
- Enforces square aspect ratio |
|||
- Requires image cropping |
|||
- Updates user profile settings |
|||
- Handles profile image updates |
|||
|
|||
**Flow:** |
|||
1. User initiates profile photo update |
|||
2. PhotoDialog opens with cropping enabled |
|||
3. Image is captured/selected |
|||
4. User crops to square aspect ratio |
|||
5. Image is uploaded and profile updated |
|||
|
|||
### Shared Photo Processing |
|||
|
|||
**Implementation:** |
|||
- Handles incoming shared photos |
|||
- Temporary storage in IndexedDB |
|||
- Options for photo usage |
|||
- Server upload integration |
|||
- Cleanup after processing |
|||
|
|||
**Flow:** |
|||
1. Photo is shared to application |
|||
2. Stored temporarily in IndexedDB |
|||
3. SharedPhotoView presents options |
|||
4. User chooses usage (gift/profile) |
|||
5. Image is processed accordingly |
|||
|
|||
### QR Code Scanning |
|||
|
|||
**Implementation:** |
|||
- Platform-specific scanning components |
|||
- Real-time camera feed processing |
|||
- QR code detection and validation |
|||
- Contact information processing |
|||
- Error handling and retry |
|||
|
|||
**Flow:** |
|||
1. User initiates QR scanning |
|||
2. Camera permissions are checked |
|||
3. Camera stream is initialized |
|||
4. QR codes are detected |
|||
5. Contact information is processed |
|||
|
|||
### QR Code Workflow |
|||
|
|||
**Implementation Details:** |
|||
|
|||
The QR code scanning workflow is implemented across multiple components and services to provide a seamless experience for contact sharing and verification. The system supports both web-based and native implementations through platform-specific services. |
|||
|
|||
#### QR Code Generation |
|||
|
|||
**Contact QR Codes:** |
|||
- Generated using `qrcode.vue` component |
|||
- Contains encrypted contact information |
|||
- Includes user ID and verification data |
|||
- Supports offline sharing |
|||
- Implements error correction |
|||
|
|||
**QR Code Format:** |
|||
```json |
|||
{ |
|||
"type": "contact", |
|||
"userId": "encrypted_user_id", |
|||
"timestamp": "creation_time", |
|||
"version": "qr_code_version", |
|||
"data": "encrypted_contact_data" |
|||
} |
|||
``` |
|||
|
|||
#### QR Code Scanning Workflow |
|||
|
|||
**1. Initiation:** |
|||
- User selects "Scan QR Code" option |
|||
- Platform-specific scanner is initialized |
|||
- Camera permissions are verified |
|||
- Appropriate scanner component is loaded |
|||
|
|||
**2. Platform-Specific Implementation:** |
|||
|
|||
*Web Implementation:* |
|||
- Uses `qrcode-stream` for real-time scanning |
|||
- Supports both front and back cameras |
|||
- Implements continuous scanning |
|||
- Provides visual feedback for scanning status |
|||
- Handles browser compatibility issues |
|||
|
|||
*Native Implementation (Capacitor):* |
|||
- Uses `@capacitor-mlkit/barcode-scanning` |
|||
- Leverages native camera capabilities |
|||
- Provides optimized scanning performance |
|||
- Supports multiple barcode formats |
|||
- Implements native permission handling |
|||
|
|||
**3. Scanning Process:** |
|||
- Camera stream is initialized |
|||
- Real-time frame analysis begins |
|||
- QR codes are detected and decoded |
|||
- Validation of QR code format |
|||
- Processing of contact information |
|||
|
|||
**4. Contact Processing:** |
|||
- Decryption of contact data |
|||
- Validation of user information |
|||
- Verification of timestamp |
|||
- Check for duplicate contacts |
|||
- Processing of shared data |
|||
|
|||
**5. Error Handling:** |
|||
- Invalid QR code format |
|||
- Expired QR codes |
|||
- Duplicate contact attempts |
|||
- Network connectivity issues |
|||
- Permission denials |
|||
- Camera access problems |
|||
|
|||
**6. Success Flow:** |
|||
- Contact information is extracted |
|||
- User is prompted for confirmation |
|||
- Contact is added to user's list |
|||
- Success notification is displayed |
|||
- Camera resources are cleaned up |
|||
|
|||
#### Security Measures |
|||
|
|||
**QR Code Security:** |
|||
- Encryption of contact data |
|||
- Timestamp validation |
|||
- Version checking |
|||
- User verification |
|||
- Rate limiting for scans |
|||
|
|||
**Data Protection:** |
|||
- Secure transmission of contact data |
|||
- Validation of QR code authenticity |
|||
- Prevention of duplicate scans |
|||
- Protection against malicious codes |
|||
- Secure storage of contact information |
|||
|
|||
#### User Experience |
|||
|
|||
**Scanning Interface:** |
|||
- Clear visual feedback |
|||
- Camera preview |
|||
- Scanning status indicators |
|||
- Error messages |
|||
- Success confirmations |
|||
|
|||
**Accessibility:** |
|||
- Support for different screen sizes |
|||
- Clear instructions |
|||
- Error recovery options |
|||
- Alternative input methods |
|||
- Offline capability |
|||
|
|||
#### Performance Considerations |
|||
|
|||
**Optimization:** |
|||
- Efficient camera resource usage |
|||
- Quick QR code detection |
|||
- Minimal processing overhead |
|||
- Battery usage optimization |
|||
- Memory management |
|||
|
|||
**Platform-Specific Optimizations:** |
|||
- Web: Optimized for browser performance |
|||
- Native: Leverages device capabilities |
|||
- Desktop: Efficient resource usage |
|||
- Mobile: Battery and performance balance |
|||
|
|||
## Platform-Specific Considerations |
|||
|
|||
### iOS |
|||
|
|||
- Requires `NSCameraUsageDescription` in Info.plist |
|||
- Supports both front and back cameras |
|||
- Implements proper permission handling |
|||
- Uses native camera UI through Capacitor |
|||
- Handles photo library access |
|||
|
|||
### Android |
|||
|
|||
- Requires camera permissions in manifest |
|||
- Supports both front and back cameras |
|||
- Handles permission requests through Capacitor |
|||
- Uses native camera UI |
|||
- Manages photo library access |
|||
|
|||
### Web |
|||
|
|||
- Requires HTTPS for camera access |
|||
- Implements fallback mechanisms |
|||
- Handles browser compatibility issues |
|||
- Uses getUserMedia API on desktop |
|||
- Uses file input with capture on mobile |
|||
- Supports multiple input methods |
|||
|
|||
## Error Handling |
|||
|
|||
### Common Error Scenarios |
|||
|
|||
1. No camera found |
|||
2. Permission denied |
|||
3. Camera in use by another application |
|||
4. HTTPS required |
|||
5. Browser compatibility issues |
|||
6. Upload failures |
|||
7. Image processing errors |
|||
|
|||
### Error Response |
|||
|
|||
- User-friendly error messages |
|||
- Troubleshooting tips |
|||
- Clear instructions for resolution |
|||
- Platform-specific guidance |
|||
- Graceful fallbacks |
|||
|
|||
## Security Considerations |
|||
|
|||
### Permission Management |
|||
|
|||
- Explicit permission requests |
|||
- Permission state tracking |
|||
- Graceful handling of denied permissions |
|||
- Platform-specific permission handling |
|||
- Secure permission storage |
|||
|
|||
### Data Handling |
|||
|
|||
- Secure image processing |
|||
- Proper cleanup of camera resources |
|||
- No persistent storage of camera data |
|||
- Secure server upload |
|||
- Temporary storage management |
|||
|
|||
## Best Practices |
|||
|
|||
### Camera Access |
|||
|
|||
1. Always check for camera availability |
|||
2. Request permissions explicitly |
|||
3. Handle all error conditions |
|||
4. Provide clear user feedback |
|||
5. Implement proper cleanup |
|||
6. Use platform-specific optimizations |
|||
|
|||
### Performance |
|||
|
|||
1. Optimize camera resolution |
|||
2. Implement proper resource cleanup |
|||
3. Handle camera switching efficiently |
|||
4. Manage memory usage |
|||
5. Optimize image processing |
|||
6. Handle upload efficiently |
|||
|
|||
### User Experience |
|||
|
|||
1. Clear status indicators |
|||
2. Intuitive camera controls |
|||
3. Helpful error messages |
|||
4. Smooth camera switching |
|||
5. Responsive UI feedback |
|||
6. Platform-appropriate UI |
|||
|
|||
## Future Improvements |
|||
|
|||
### Planned Enhancements |
|||
|
|||
1. Implement Electron camera support |
|||
2. Add advanced camera features |
|||
3. Improve error handling |
|||
4. Enhance user feedback |
|||
5. Optimize performance |
|||
6. Add image compression options |
|||
|
|||
### Known Issues |
|||
|
|||
1. Electron camera implementation pending |
|||
2. Some browser compatibility limitations |
|||
3. Platform-specific quirks to address |
|||
4. Mobile browser camera access limitations |
|||
5. Image upload performance on slow connections |
|||
|
|||
## Dependencies |
|||
|
|||
### Key Packages |
|||
|
|||
- `@capacitor-mlkit/barcode-scanning` |
|||
- `qrcode-stream` |
|||
- `vue-picture-cropper` |
|||
- `@capacitor/camera` |
|||
- Platform-specific camera APIs |
|||
|
|||
## Testing |
|||
|
|||
### Test Scenarios |
|||
|
|||
1. Permission handling |
|||
2. Camera switching |
|||
3. Error conditions |
|||
4. Platform compatibility |
|||
5. Performance metrics |
|||
6. Upload scenarios |
|||
7. Image processing |
|||
|
|||
### Test Environment |
|||
|
|||
- Multiple browsers |
|||
- iOS and Android devices |
|||
- Desktop platforms |
|||
- Various network conditions |
|||
- Different camera configurations |
@ -1,156 +0,0 @@ |
|||
## Build Configuration |
|||
|
|||
### Common Vite Configuration |
|||
```typescript |
|||
// vite.config.common.mts |
|||
export async function createBuildConfig(mode: string) { |
|||
const isCapacitor = mode === "capacitor"; |
|||
|
|||
return defineConfig({ |
|||
build: { |
|||
rollupOptions: { |
|||
output: { |
|||
manualChunks: { |
|||
'vue-vendor': ['vue', 'vue-router', 'vue-facing-decorator'] |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
define: { |
|||
__USE_QR_READER__: JSON.stringify(!isCapacitor), |
|||
__IS_MOBILE__: JSON.stringify(isCapacitor), |
|||
}, |
|||
optimizeDeps: { |
|||
include: [ |
|||
'@capacitor-mlkit/barcode-scanning', |
|||
'vue-qrcode-reader' |
|||
] |
|||
}, |
|||
resolve: { |
|||
alias: { |
|||
'@capacitor/app': path.resolve(__dirname, 'node_modules/@capacitor/app') |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
``` |
|||
|
|||
### Web-Specific Configuration |
|||
```typescript |
|||
// vite.config.web.mts |
|||
import { defineConfig, mergeConfig } from "vite"; |
|||
import { createBuildConfig } from "./vite.config.common.mts"; |
|||
|
|||
export default defineConfig(async () => { |
|||
const baseConfig = await createBuildConfig('web'); |
|||
|
|||
return mergeConfig(baseConfig, { |
|||
define: { |
|||
__USE_QR_READER__: true, |
|||
__IS_MOBILE__: false, |
|||
} |
|||
}); |
|||
}); |
|||
``` |
|||
|
|||
### Capacitor-Specific Configuration |
|||
```typescript |
|||
// vite.config.capacitor.mts |
|||
import { defineConfig, mergeConfig } from "vite"; |
|||
import { createBuildConfig } from "./vite.config.common.mts"; |
|||
|
|||
export default defineConfig(async () => { |
|||
const baseConfig = await createBuildConfig('capacitor'); |
|||
|
|||
return mergeConfig(baseConfig, { |
|||
define: { |
|||
__USE_QR_READER__: false, |
|||
__IS_MOBILE__: true, |
|||
}, |
|||
build: { |
|||
rollupOptions: { |
|||
external: ['vue-qrcode-reader'], // Exclude web QR reader from mobile builds |
|||
output: { |
|||
entryFileNames: '[name]-mobile.js', |
|||
chunkFileNames: '[name]-mobile.js', |
|||
assetFileNames: '[name]-mobile.[ext]' |
|||
} |
|||
} |
|||
} |
|||
}); |
|||
}); |
|||
``` |
|||
|
|||
### Build Scripts |
|||
Add these scripts to your `package.json`: |
|||
```json |
|||
{ |
|||
"scripts": { |
|||
"build:web": "vite build --config vite.config.web.mts", |
|||
"build:capacitor": "vite build --config vite.config.capacitor.mts", |
|||
"build:all": "npm run build:web && npm run build:capacitor" |
|||
} |
|||
} |
|||
``` |
|||
|
|||
### Environment Variables |
|||
Create a `.env` file: |
|||
```bash |
|||
# QR Scanner Configuration |
|||
VITE_QR_SCANNER_ENABLED=true |
|||
VITE_DEFAULT_CAMERA=back |
|||
``` |
|||
|
|||
### Build Process |
|||
|
|||
1. **Web Build** |
|||
```bash |
|||
npm run build:web |
|||
``` |
|||
This will: |
|||
- Include vue-qrcode-reader |
|||
- Set __USE_QR_READER__ to true |
|||
- Set __IS_MOBILE__ to false |
|||
- Build for web browsers |
|||
|
|||
2. **Capacitor Build** |
|||
```bash |
|||
npm run build:capacitor |
|||
``` |
|||
This will: |
|||
- Exclude vue-qrcode-reader |
|||
- Set __USE_QR_READER__ to false |
|||
- Set __IS_MOBILE__ to true |
|||
- Build for mobile platforms |
|||
|
|||
3. **Build Both** |
|||
```bash |
|||
npm run build:all |
|||
``` |
|||
|
|||
### Important Notes |
|||
|
|||
1. **Dependencies** |
|||
- Ensure all QR-related dependencies are properly listed in package.json |
|||
- Use exact versions to avoid compatibility issues |
|||
- Consider using peer dependencies for shared libraries |
|||
|
|||
2. **Bundle Size** |
|||
- Web build includes vue-qrcode-reader (~100KB) |
|||
- Mobile build includes @capacitor-mlkit/barcode-scanning (~50KB) |
|||
- Consider using dynamic imports for lazy loading |
|||
|
|||
3. **Platform Detection** |
|||
- Build flags determine which implementation to use |
|||
- Runtime checks provide fallback options |
|||
- Environment variables can override defaults |
|||
|
|||
4. **Performance** |
|||
- Mobile builds optimize for native performance |
|||
- Web builds include necessary polyfills |
|||
- Chunk splitting improves load times |
|||
|
|||
5. **Debugging** |
|||
- Source maps are enabled for development |
|||
- Build artifacts are properly named for identification |
|||
- Console logs help track initialization |
Loading…
Reference in new issue