Update camera screens, configuration, and build setup
This commit is contained in:
+49
-31
@@ -1,6 +1,6 @@
|
||||
import ipp from 'ipp-encoder';
|
||||
import { Buffer } from 'buffer';
|
||||
import * as FileSystem from 'expo-file-system/legacy';
|
||||
import { File } from 'expo-file-system';
|
||||
|
||||
export interface PrintOptions {
|
||||
ipAddress: string;
|
||||
@@ -23,9 +23,8 @@ export async function printImageLocal(imageUri: string, options: PrintOptions):
|
||||
}
|
||||
|
||||
// 1. Read the image file from local storage as Base64 and convert to binary Buffer
|
||||
const base64Data = await FileSystem.readAsStringAsync(imageUri, {
|
||||
encoding: FileSystem.EncodingType.Base64,
|
||||
});
|
||||
const file = new File(imageUri);
|
||||
const base64Data = await file.base64();
|
||||
const imageBuffer = Buffer.from(base64Data, 'base64');
|
||||
|
||||
// 2. Build the IPP Print-Job request structure
|
||||
@@ -57,36 +56,55 @@ export async function printImageLocal(imageUri: string, options: PrintOptions):
|
||||
// 5. Send the POST request to the printer via standard HTTP on port 631
|
||||
const printerUrl = `http://${ipAddress}:631/ipp/print`;
|
||||
|
||||
console.log(`Sending silent print job to ${printerUrl}...`);
|
||||
|
||||
const response = await fetch(printerUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/ipp',
|
||||
},
|
||||
// Pass as Uint8Array to ensure React Native fetch treats it as raw binary
|
||||
body: new Uint8Array(finalPayload),
|
||||
});
|
||||
const maxRetries = 3;
|
||||
let delay = 1000;
|
||||
let lastError: any = null;
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Drucker antwortete mit HTTP-Status ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
||||
try {
|
||||
console.log(`Sending silent print job to ${printerUrl} (Attempt ${attempt}/${maxRetries})...`);
|
||||
|
||||
const response = await fetch(printerUrl, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/ipp',
|
||||
},
|
||||
// Pass as Uint8Array to ensure React Native fetch treats it as raw binary
|
||||
body: new Uint8Array(finalPayload),
|
||||
});
|
||||
|
||||
// 6. Read and decode the response from the printer to verify success
|
||||
const responseArrayBuffer = await response.arrayBuffer();
|
||||
const responseBuffer = Buffer.from(responseArrayBuffer);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Drucker antwortete mit HTTP-Status ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
try {
|
||||
const decodedResponse = ipp.response.decode(responseBuffer);
|
||||
const statusCode = decodedResponse.statusCode;
|
||||
|
||||
// IPP success status is 0x0000 (successful-ok)
|
||||
if (statusCode !== 0x0000) {
|
||||
throw new Error(`Drucker lieferte IPP-Fehlercode: 0x${statusCode.toString(16)}`);
|
||||
// 6. Read and decode the response from the printer to verify success
|
||||
const responseArrayBuffer = await response.arrayBuffer();
|
||||
const responseBuffer = Buffer.from(responseArrayBuffer);
|
||||
|
||||
try {
|
||||
const decodedResponse = ipp.response.decode(responseBuffer);
|
||||
const statusCode = decodedResponse.statusCode;
|
||||
|
||||
// IPP success status is 0x0000 (successful-ok)
|
||||
if (statusCode !== 0x0000) {
|
||||
throw new Error(`Drucker lieferte IPP-Fehlercode: 0x${statusCode.toString(16)}`);
|
||||
}
|
||||
console.log('Silent print job accepted successfully!');
|
||||
} catch (e: any) {
|
||||
// If decoding fails, we still assume success since the network request completed successfully
|
||||
console.warn('Failed to parse IPP response, but network request succeeded:', e.message);
|
||||
}
|
||||
|
||||
return; // Success, exit retry loop
|
||||
} catch (error: any) {
|
||||
console.warn(`Print attempt ${attempt} failed: ${error.message}`);
|
||||
lastError = error;
|
||||
if (attempt < maxRetries) {
|
||||
await new Promise((resolve) => setTimeout(resolve, delay));
|
||||
delay *= 2; // exponential backoff
|
||||
}
|
||||
}
|
||||
console.log('Silent print job accepted successfully!');
|
||||
} catch (e: any) {
|
||||
// If decoding fails, we still assume success since the network request completed successfully
|
||||
console.warn('Failed to parse IPP response, but network request succeeded:', e.message);
|
||||
}
|
||||
|
||||
throw new Error(`Druckauftrag nach ${maxRetries} Versuchen fehlgeschlagen. Letzter Fehler: ${lastError?.message}`);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import * as FileSystem from 'expo-file-system/legacy';
|
||||
import { File, Paths } from 'expo-file-system';
|
||||
|
||||
export interface AppSettings {
|
||||
countdownDuration: number; // in seconds
|
||||
@@ -7,7 +7,7 @@ export interface AppSettings {
|
||||
kioskModeEnabled: boolean;
|
||||
}
|
||||
|
||||
const SETTINGS_FILE = `${FileSystem.documentDirectory}settings.json`;
|
||||
const settingsFile = new File(Paths.document, 'settings.json');
|
||||
|
||||
const DEFAULT_SETTINGS: AppSettings = {
|
||||
countdownDuration: 3,
|
||||
@@ -21,9 +21,8 @@ const DEFAULT_SETTINGS: AppSettings = {
|
||||
*/
|
||||
export async function loadSettings(): Promise<AppSettings> {
|
||||
try {
|
||||
const fileInfo = await FileSystem.getInfoAsync(SETTINGS_FILE);
|
||||
if (fileInfo.exists) {
|
||||
const content = await FileSystem.readAsStringAsync(SETTINGS_FILE);
|
||||
if (settingsFile.exists) {
|
||||
const content = await settingsFile.text();
|
||||
const parsed = JSON.parse(content);
|
||||
return { ...DEFAULT_SETTINGS, ...parsed };
|
||||
}
|
||||
@@ -39,7 +38,7 @@ export async function loadSettings(): Promise<AppSettings> {
|
||||
export async function saveSettings(settings: AppSettings): Promise<void> {
|
||||
try {
|
||||
const content = JSON.stringify(settings, null, 2);
|
||||
await FileSystem.writeAsStringAsync(SETTINGS_FILE, content);
|
||||
settingsFile.write(content);
|
||||
console.log('Settings saved successfully:', content);
|
||||
} catch (e) {
|
||||
console.error('Failed to save settings:', e);
|
||||
|
||||
+14
-10
@@ -1,5 +1,4 @@
|
||||
import * as MediaLibrary from 'expo-media-library/legacy';
|
||||
import { Platform } from 'react-native';
|
||||
import { Asset, Album, getPermissionsAsync, requestPermissionsAsync } from 'expo-media-library';
|
||||
|
||||
const ALBUM_NAME = 'Schnappix';
|
||||
|
||||
@@ -8,13 +7,13 @@ const ALBUM_NAME = 'Schnappix';
|
||||
* @returns Promise<boolean> True if permissions are granted.
|
||||
*/
|
||||
export async function requestStoragePermission(): Promise<boolean> {
|
||||
const { status, canAskAgain } = await MediaLibrary.getPermissionsAsync();
|
||||
const { status, canAskAgain } = await getPermissionsAsync();
|
||||
if (status === 'granted') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (canAskAgain) {
|
||||
const { status: newStatus } = await MediaLibrary.requestPermissionsAsync();
|
||||
const { status: newStatus } = await requestPermissionsAsync();
|
||||
return newStatus === 'granted';
|
||||
}
|
||||
|
||||
@@ -34,25 +33,30 @@ export async function saveToGallery(localUri: string): Promise<string> {
|
||||
}
|
||||
|
||||
// 1. Create a media asset from the local file
|
||||
const asset = await MediaLibrary.createAssetAsync(localUri);
|
||||
const asset = await Asset.create(localUri);
|
||||
|
||||
try {
|
||||
// 2. Check if the "Schnappix" album already exists
|
||||
let album = await MediaLibrary.getAlbumAsync(ALBUM_NAME);
|
||||
const album = await Album.get(ALBUM_NAME);
|
||||
|
||||
if (!album) {
|
||||
// 3. If it doesn't exist, create it with our asset
|
||||
await MediaLibrary.createAlbumAsync(ALBUM_NAME, asset, false);
|
||||
await Album.create(ALBUM_NAME, [asset], false);
|
||||
console.log(`Created new album "${ALBUM_NAME}" and saved photo.`);
|
||||
} else {
|
||||
// 4. If it exists, add our asset to it
|
||||
await MediaLibrary.addAssetsToAlbumAsync([asset], album, false);
|
||||
await album.add(asset);
|
||||
console.log(`Saved photo to existing album "${ALBUM_NAME}".`);
|
||||
}
|
||||
|
||||
return asset.uri;
|
||||
const assetUri = await asset.getUri();
|
||||
return assetUri;
|
||||
} catch (e: any) {
|
||||
console.error('Error saving asset to album, returning fallback asset URI:', e);
|
||||
return asset.uri;
|
||||
try {
|
||||
return await asset.getUri();
|
||||
} catch {
|
||||
return asset.id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user