forked from jsnbuchanan/crowd-funder-for-time-pwa
Merge branch 'qrcode-reboot' of ssh://173.199.124.46:222/trent_larson/crowd-funder-for-time-pwa into qrcode-reboot
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
---
|
||||
description:
|
||||
globs:
|
||||
alwaysApply: true
|
||||
---
|
||||
# Camera Implementation Documentation
|
||||
|
||||
## Overview
|
||||
|
||||
This document describes how camera functionality is implemented across the TimeSafari application. The application uses cameras for two main purposes:
|
||||
|
||||
1. QR Code scanning
|
||||
2. Photo capture
|
||||
|
||||
## 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
|
||||
|
||||
## 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
|
||||
- Falls back to file selection if camera unavailable
|
||||
- Processes captured images for consistent format
|
||||
|
||||
#### 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
|
||||
|
||||
#### ElectronPlatformService
|
||||
|
||||
Desktop implementation (currently unimplemented).
|
||||
|
||||
**Status:**
|
||||
|
||||
- Camera functionality not yet implemented
|
||||
- Planned to use Electron's media APIs
|
||||
|
||||
## Platform-Specific Considerations
|
||||
|
||||
### iOS
|
||||
|
||||
- Requires `NSCameraUsageDescription` in Info.plist
|
||||
- Supports both front and back cameras
|
||||
- Implements proper permission handling
|
||||
|
||||
### Android
|
||||
|
||||
- Requires camera permissions in manifest
|
||||
- Supports both front and back cameras
|
||||
- Handles permission requests through Capacitor
|
||||
|
||||
### Web
|
||||
|
||||
- Requires HTTPS for camera access
|
||||
- Implements fallback mechanisms
|
||||
- Handles browser compatibility issues
|
||||
|
||||
## 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
|
||||
|
||||
### Error Response
|
||||
|
||||
- User-friendly error messages
|
||||
- Troubleshooting tips
|
||||
- Clear instructions for resolution
|
||||
- Platform-specific guidance
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Permission Management
|
||||
|
||||
- Explicit permission requests
|
||||
- Permission state tracking
|
||||
- Graceful handling of denied permissions
|
||||
|
||||
### Data Handling
|
||||
|
||||
- Secure image processing
|
||||
- Proper cleanup of camera resources
|
||||
- No persistent storage of camera data
|
||||
|
||||
## 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
|
||||
|
||||
### User Experience
|
||||
|
||||
1. Clear status indicators
|
||||
2. Intuitive camera controls
|
||||
3. Helpful error messages
|
||||
4. Smooth camera switching
|
||||
5. Responsive UI feedback
|
||||
|
||||
## 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
|
||||
|
||||
### Known Issues
|
||||
|
||||
1. Electron camera implementation pending
|
||||
2. Some browser compatibility limitations
|
||||
3. Platform-specific quirks to address
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Key Packages
|
||||
|
||||
- `@capacitor-mlkit/barcode-scanning`
|
||||
- `qrcode-stream`
|
||||
- `vue-picture-cropper`
|
||||
- Platform-specific camera APIs
|
||||
|
||||
## Testing
|
||||
|
||||
### Test Scenarios
|
||||
|
||||
1. Permission handling
|
||||
2. Camera switching
|
||||
3. Error conditions
|
||||
4. Platform compatibility
|
||||
5. Performance metrics
|
||||
|
||||
### Test Environment
|
||||
|
||||
- Multiple browsers
|
||||
- iOS and Android devices
|
||||
- Desktop platforms
|
||||
- Various network conditions
|
||||
76
BUILDING.md
76
BUILDING.md
@@ -236,21 +236,75 @@ docker run -d \
|
||||
- AppImage: `dist-electron-packages/TimeSafari-x.x.x.AppImage`
|
||||
- DEB: `dist-electron-packages/timesafari_x.x.x_amd64.deb`
|
||||
|
||||
### macOS Build
|
||||
|
||||
1. Build the electron app in production mode:
|
||||
|
||||
```bash
|
||||
npm run build:electron-prod
|
||||
```
|
||||
|
||||
2. Package the Electron app for macOS:
|
||||
|
||||
```bash
|
||||
# For Intel Macs
|
||||
npm run electron:build-mac
|
||||
|
||||
# For Universal build (Intel + Apple Silicon)
|
||||
npm run electron:build-mac-universal
|
||||
```
|
||||
|
||||
3. The packaged applications will be in `dist-electron-packages/`:
|
||||
- `.app` bundle: `TimeSafari.app`
|
||||
- `.dmg` installer: `TimeSafari-x.x.x.dmg`
|
||||
- `.zip` archive: `TimeSafari-x.x.x-mac.zip`
|
||||
|
||||
### Code Signing and Notarization (macOS)
|
||||
|
||||
For public distribution on macOS, you need to code sign and notarize your app:
|
||||
|
||||
1. Set up environment variables:
|
||||
```bash
|
||||
export CSC_LINK=/path/to/your/certificate.p12
|
||||
export CSC_KEY_PASSWORD=your_certificate_password
|
||||
export APPLE_ID=your_apple_id
|
||||
export APPLE_ID_PASSWORD=your_app_specific_password
|
||||
```
|
||||
|
||||
2. Build with signing:
|
||||
```bash
|
||||
npm run electron:build-mac
|
||||
```
|
||||
|
||||
### Running the Packaged App
|
||||
|
||||
- AppImage: Make executable and run
|
||||
- **Linux**:
|
||||
- AppImage: Make executable and run
|
||||
```bash
|
||||
chmod +x dist-electron-packages/TimeSafari-*.AppImage
|
||||
./dist-electron-packages/TimeSafari-*.AppImage
|
||||
```
|
||||
- DEB: Install and run
|
||||
```bash
|
||||
sudo dpkg -i dist-electron-packages/timesafari_*_amd64.deb
|
||||
timesafari
|
||||
```
|
||||
|
||||
```bash
|
||||
chmod +x dist-electron-packages/TimeSafari-*.AppImage
|
||||
./dist-electron-packages/TimeSafari-*.AppImage
|
||||
```
|
||||
- **macOS**:
|
||||
- `.app` bundle: Double-click `TimeSafari.app` in Finder
|
||||
- `.dmg` installer:
|
||||
1. Double-click the `.dmg` file
|
||||
2. Drag the app to your Applications folder
|
||||
3. Launch from Applications
|
||||
- `.zip` archive:
|
||||
1. Extract the `.zip` file
|
||||
2. Move `TimeSafari.app` to your Applications folder
|
||||
3. Launch from Applications
|
||||
|
||||
- DEB: Install and run
|
||||
|
||||
```bash
|
||||
sudo dpkg -i dist-electron-packages/timesafari_*_amd64.deb
|
||||
timesafari
|
||||
```
|
||||
Note: If you get a security warning when running the app:
|
||||
1. Right-click the app
|
||||
2. Select "Open"
|
||||
3. Click "Open" in the security dialog
|
||||
|
||||
### Development Testing
|
||||
|
||||
|
||||
20
build/entitlements.mac.plist
Normal file
20
build/entitlements.mac.plist
Normal file
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.cs.allow-jit</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
|
||||
<true/>
|
||||
<key>com.apple.security.cs.debugger</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.audio-input</key>
|
||||
<true/>
|
||||
<key>com.apple.security.device.camera</key>
|
||||
<true/>
|
||||
<key>com.apple.security.personal-information.addressbook</key>
|
||||
<true/>
|
||||
<key>com.apple.security.personal-information.calendars</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
308
docs/camera-implementation.md
Normal file
308
docs/camera-implementation.md
Normal file
@@ -0,0 +1,308 @@
|
||||
# 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
|
||||
|
||||
### 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
|
||||
|
||||
### 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
|
||||
|
||||
## 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
|
||||
- Falls back to file selection if camera unavailable
|
||||
- Processes captured images for consistent format
|
||||
|
||||
#### 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
|
||||
|
||||
#### ElectronPlatformService
|
||||
|
||||
Desktop implementation (currently unimplemented).
|
||||
|
||||
**Status:**
|
||||
|
||||
- Camera functionality not yet implemented
|
||||
- Planned to use Electron's media APIs
|
||||
|
||||
## 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
|
||||
|
||||
### Image Upload and Processing
|
||||
|
||||
**Implementation:**
|
||||
- Secure server upload
|
||||
- Authentication handling
|
||||
- Image format standardization
|
||||
- Error handling and retry
|
||||
- Progress feedback
|
||||
|
||||
**Flow:**
|
||||
1. Image is prepared for upload
|
||||
2. Authentication token is obtained
|
||||
3. Multipart form data is created
|
||||
4. Upload progress is monitored
|
||||
5. Server URL is returned
|
||||
|
||||
## Platform-Specific Considerations
|
||||
|
||||
### iOS
|
||||
|
||||
- Requires `NSCameraUsageDescription` in Info.plist
|
||||
- Supports both front and back cameras
|
||||
- Implements proper permission handling
|
||||
|
||||
### Android
|
||||
|
||||
- Requires camera permissions in manifest
|
||||
- Supports both front and back cameras
|
||||
- Handles permission requests through Capacitor
|
||||
|
||||
### Web
|
||||
|
||||
- Requires HTTPS for camera access
|
||||
- Implements fallback mechanisms
|
||||
- Handles browser compatibility issues
|
||||
|
||||
## 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
|
||||
|
||||
### Error Response
|
||||
|
||||
- User-friendly error messages
|
||||
- Troubleshooting tips
|
||||
- Clear instructions for resolution
|
||||
- Platform-specific guidance
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Permission Management
|
||||
|
||||
- Explicit permission requests
|
||||
- Permission state tracking
|
||||
- Graceful handling of denied permissions
|
||||
|
||||
### Data Handling
|
||||
|
||||
- Secure image processing
|
||||
- Proper cleanup of camera resources
|
||||
- No persistent storage of camera data
|
||||
|
||||
## 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
|
||||
|
||||
### User Experience
|
||||
|
||||
1. Clear status indicators
|
||||
2. Intuitive camera controls
|
||||
3. Helpful error messages
|
||||
4. Smooth camera switching
|
||||
5. Responsive UI feedback
|
||||
|
||||
## 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
|
||||
|
||||
### Known Issues
|
||||
|
||||
1. Electron camera implementation pending
|
||||
2. Some browser compatibility limitations
|
||||
3. Platform-specific quirks to address
|
||||
|
||||
## Dependencies
|
||||
|
||||
### Key Packages
|
||||
|
||||
- `@capacitor-mlkit/barcode-scanning`
|
||||
- `qrcode-stream`
|
||||
- `vue-picture-cropper`
|
||||
- Platform-specific camera APIs
|
||||
|
||||
## Testing
|
||||
|
||||
### Test Scenarios
|
||||
|
||||
1. Permission handling
|
||||
2. Camera switching
|
||||
3. Error conditions
|
||||
4. Platform compatibility
|
||||
5. Performance metrics
|
||||
|
||||
### Test Environment
|
||||
|
||||
- Multiple browsers
|
||||
- iOS and Android devices
|
||||
- Desktop platforms
|
||||
- Various network conditions
|
||||
4634
package-lock.json
generated
4634
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
29
package.json
29
package.json
@@ -41,7 +41,9 @@
|
||||
"fastlane:ios:beta": "cd ios && fastlane beta",
|
||||
"fastlane:ios:release": "cd ios && fastlane release",
|
||||
"fastlane:android:beta": "cd android && fastlane beta",
|
||||
"fastlane:android:release": "cd android && fastlane release"
|
||||
"fastlane:android:release": "cd android && fastlane release",
|
||||
"electron:build-mac": "npm run build:electron-prod && electron-builder --mac",
|
||||
"electron:build-mac-universal": "npm run build:electron-prod && electron-builder --mac --universal"
|
||||
},
|
||||
"dependencies": {
|
||||
"@capacitor-mlkit/barcode-scanning": "^6.0.0",
|
||||
@@ -185,6 +187,29 @@
|
||||
"category": "Office",
|
||||
"icon": "build/icon.png"
|
||||
},
|
||||
"asar": true
|
||||
"asar": true,
|
||||
"mac": {
|
||||
"target": ["dmg", "zip"],
|
||||
"category": "public.app-category.productivity",
|
||||
"icon": "build/icon.png",
|
||||
"hardenedRuntime": true,
|
||||
"gatekeeperAssess": false,
|
||||
"entitlements": "build/entitlements.mac.plist",
|
||||
"entitlementsInherit": "build/entitlements.mac.plist"
|
||||
},
|
||||
"dmg": {
|
||||
"contents": [
|
||||
{
|
||||
"x": 130,
|
||||
"y": 220
|
||||
},
|
||||
{
|
||||
"x": 410,
|
||||
"y": 220,
|
||||
"type": "link",
|
||||
"path": "/Applications"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -441,8 +441,8 @@ const configureIosProject = async (log) => {
|
||||
try {
|
||||
// Try to run pod install normally first
|
||||
log('🔄 Running "pod install" in ios/App directory...');
|
||||
execSync('cd ios/App && pod install', { stdio: 'inherit' });
|
||||
log('✅ CocoaPods installation completed');
|
||||
execSync('cd ios/App && pod install', { stdio: 'inherit' });
|
||||
log('✅ CocoaPods installation completed');
|
||||
} catch (error) {
|
||||
// If that fails, provide detailed instructions
|
||||
log(`⚠️ CocoaPods installation failed: ${error.message}`);
|
||||
@@ -623,28 +623,28 @@ const runDeeplinkTests = async (log) => {
|
||||
}
|
||||
|
||||
// Now we can safely create the deeplink tests knowing we have valid data
|
||||
const deeplinkTests = [
|
||||
{
|
||||
const deeplinkTests = [
|
||||
{
|
||||
url: `timesafari://claim/${testEnv.CLAIM_ID}`,
|
||||
description: 'Claim view'
|
||||
},
|
||||
{
|
||||
description: 'Claim view'
|
||||
},
|
||||
{
|
||||
url: `timesafari://claim-cert/${testEnv.CERT_ID || testEnv.CLAIM_ID}`,
|
||||
description: 'Claim certificate view'
|
||||
},
|
||||
{
|
||||
description: 'Claim certificate view'
|
||||
},
|
||||
{
|
||||
url: `timesafari://claim-add-raw/${testEnv.RAW_CLAIM_ID || testEnv.CLAIM_ID}`,
|
||||
description: 'Raw claim addition'
|
||||
},
|
||||
{
|
||||
url: 'timesafari://did/test',
|
||||
description: 'DID view with test identifier'
|
||||
},
|
||||
{
|
||||
url: `timesafari://did/${testEnv.CONTACT1_DID}`,
|
||||
description: 'DID view with contact DID'
|
||||
},
|
||||
{
|
||||
description: 'Raw claim addition'
|
||||
},
|
||||
{
|
||||
url: 'timesafari://did/test',
|
||||
description: 'DID view with test identifier'
|
||||
},
|
||||
{
|
||||
url: `timesafari://did/${testEnv.CONTACT1_DID}`,
|
||||
description: 'DID view with contact DID'
|
||||
},
|
||||
{
|
||||
url: (() => {
|
||||
if (!testEnv?.CONTACT1_DID) {
|
||||
throw new Error('Cannot construct contact-edit URL: CONTACT1_DID is missing');
|
||||
@@ -653,13 +653,13 @@ const runDeeplinkTests = async (log) => {
|
||||
log('Created contact-edit URL:', url);
|
||||
return url;
|
||||
})(),
|
||||
description: 'Contact editing'
|
||||
},
|
||||
{
|
||||
url: `timesafari://contacts/import?contacts=${encodeURIComponent(JSON.stringify(contacts))}`,
|
||||
description: 'Contacts import'
|
||||
}
|
||||
];
|
||||
description: 'Contact editing'
|
||||
},
|
||||
{
|
||||
url: `timesafari://contacts/import?contacts=${encodeURIComponent(JSON.stringify(contacts))}`,
|
||||
description: 'Contacts import'
|
||||
}
|
||||
];
|
||||
|
||||
// Log the final test configuration
|
||||
log('\n5. Final Test Configuration:');
|
||||
|
||||
@@ -1,3 +1,14 @@
|
||||
/** * PhotoDialog.vue - Cross-platform photo capture and selection component * *
|
||||
This component provides a unified interface for taking photos and selecting
|
||||
images * across different platforms (web, mobile) using the PlatformService. It
|
||||
supports: * - Taking photos using device camera * - Selecting images from device
|
||||
gallery * - Image cropping functionality * - Image upload to server * - Error
|
||||
handling and user feedback * * Features: * - Responsive design with mobile-first
|
||||
approach * - Cross-platform compatibility through PlatformService * - Image
|
||||
cropping with aspect ratio control * - Progress feedback during upload * -
|
||||
Comprehensive error handling * * @author Matthew Raymer * @version 1.0.0 * @file
|
||||
PhotoDialog.vue */
|
||||
|
||||
<template>
|
||||
<div v-if="visible" class="dialog-overlay z-[60]">
|
||||
<div class="dialog relative">
|
||||
@@ -90,16 +101,6 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
/**
|
||||
* PhotoDialog.vue - Cross-platform photo capture and selection component
|
||||
*
|
||||
* This component provides a unified interface for taking photos and selecting images
|
||||
* across different platforms using the PlatformService.
|
||||
*
|
||||
* @author Matthew Raymer
|
||||
* @file PhotoDialog.vue
|
||||
*/
|
||||
|
||||
import axios from "axios";
|
||||
import { Component, Vue } from "vue-facing-decorator";
|
||||
import VuePictureCropper, { cropper } from "vue-picture-cropper";
|
||||
@@ -113,37 +114,69 @@ import { PlatformServiceFactory } from "../services/PlatformServiceFactory";
|
||||
export default class PhotoDialog extends Vue {
|
||||
$notify!: (notification: NotificationIface, timeout?: number) => void;
|
||||
|
||||
/** Active DID for user authentication */
|
||||
activeDid = "";
|
||||
|
||||
/** Current image blob being processed */
|
||||
blob?: Blob;
|
||||
|
||||
/** Type of claim for the image */
|
||||
claimType = "";
|
||||
|
||||
/** Whether to show cropping interface */
|
||||
crop = false;
|
||||
|
||||
/** Name of the selected file */
|
||||
fileName?: string;
|
||||
|
||||
/** Callback function to set image URL after upload */
|
||||
setImageCallback: (arg: string) => void = () => {};
|
||||
|
||||
/** Whether to show retry button */
|
||||
showRetry = true;
|
||||
|
||||
/** Upload progress state */
|
||||
uploading = false;
|
||||
|
||||
/** Dialog visibility state */
|
||||
visible = false;
|
||||
|
||||
private platformService = PlatformServiceFactory.getInstance();
|
||||
URL = window.URL || window.webkitURL;
|
||||
|
||||
/**
|
||||
* Lifecycle hook: Initializes component and retrieves user settings
|
||||
* @throws {Error} When settings retrieval fails
|
||||
*/
|
||||
async mounted() {
|
||||
try {
|
||||
const settings = await retrieveSettingsForActiveAccount();
|
||||
this.activeDid = settings.activeDid || "";
|
||||
} catch (err: unknown) {
|
||||
logger.error("Error retrieving settings from database:", err);
|
||||
} catch (error: unknown) {
|
||||
logger.error("Error retrieving settings from database:", error);
|
||||
this.$notify(
|
||||
{
|
||||
group: "alert",
|
||||
type: "danger",
|
||||
title: "Error",
|
||||
text: err.message || "There was an error retrieving your settings.",
|
||||
text:
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: "There was an error retrieving your settings.",
|
||||
},
|
||||
-1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the photo dialog with specified configuration
|
||||
* @param setImageFn - Callback function to handle image URL after upload
|
||||
* @param claimType - Type of claim for the image
|
||||
* @param crop - Whether to enable cropping
|
||||
* @param blob - Optional existing image blob
|
||||
* @param inputFileName - Optional filename for the image
|
||||
*/
|
||||
open(
|
||||
setImageFn: (arg: string) => void,
|
||||
claimType: string,
|
||||
@@ -170,6 +203,9 @@ export default class PhotoDialog extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the photo dialog and resets state
|
||||
*/
|
||||
close() {
|
||||
this.visible = false;
|
||||
const bottomNav = document.querySelector("#QuickNav") as HTMLElement;
|
||||
@@ -179,6 +215,10 @@ export default class PhotoDialog extends Vue {
|
||||
this.blob = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures a photo using device camera
|
||||
* @throws {Error} When camera access fails
|
||||
*/
|
||||
async takePhoto() {
|
||||
try {
|
||||
const result = await this.platformService.takePicture();
|
||||
@@ -198,6 +238,10 @@ export default class PhotoDialog extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects an image from device gallery
|
||||
* @throws {Error} When gallery access fails
|
||||
*/
|
||||
async pickPhoto() {
|
||||
try {
|
||||
const result = await this.platformService.pickImage();
|
||||
@@ -217,14 +261,27 @@ export default class PhotoDialog extends Vue {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a blob URL for image preview
|
||||
* @param blob - Image blob to create URL for
|
||||
* @returns {string} Blob URL for the image
|
||||
*/
|
||||
private createBlobURL(blob: Blob): string {
|
||||
return URL.createObjectURL(blob);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the current image selection
|
||||
*/
|
||||
async retryImage() {
|
||||
this.blob = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Uploads the current image to the server
|
||||
* Handles cropping if enabled and manages upload state
|
||||
* @throws {Error} When upload fails or server returns error
|
||||
*/
|
||||
async uploadImage() {
|
||||
this.uploading = true;
|
||||
|
||||
@@ -339,6 +396,7 @@ export default class PhotoDialog extends Vue {
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* Dialog overlay styling */
|
||||
.dialog-overlay {
|
||||
z-index: 60;
|
||||
position: fixed;
|
||||
@@ -353,6 +411,7 @@ export default class PhotoDialog extends Vue {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
/* Dialog container styling */
|
||||
.dialog {
|
||||
background-color: white;
|
||||
padding: 1rem;
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
<template>
|
||||
<!-- CONTENT -->
|
||||
<section id="Content" class="relativew-[100vw] h-[100vh]">
|
||||
<div class="absolute inset-x-0 bottom-0 bg-black/50 p-6">
|
||||
<p class="text-center text-white mb-3">
|
||||
Point your camera at a TimeSafari contact QR code to scan it automatically.
|
||||
</p>
|
||||
<div class="absolute inset-x-0 bottom-0 bg-black/50 p-6">
|
||||
<p class="text-center text-white mb-3">
|
||||
Point your camera at a TimeSafari contact QR code to scan it
|
||||
automatically.
|
||||
</p>
|
||||
|
||||
<p v-if="error" class="text-center text-rose-300 mb-3">{{ error }}</p>
|
||||
<p v-if="error" class="text-center text-rose-300 mb-3">{{ error }}</p>
|
||||
|
||||
<div class="text-center">
|
||||
<button
|
||||
@@ -21,6 +22,8 @@
|
||||
<div class="text-center">
|
||||
|
||||
</div>
|
||||
|
||||
<div class="text-center"></div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
@@ -428,4 +431,4 @@ export default class ContactQRScan extends Vue {
|
||||
.aspect-square {
|
||||
aspect-ratio: 1 / 1;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user