update: app changes, new frame, and latest APK build

This commit is contained in:
2026-05-31 23:11:17 +02:00
parent b113ee98fe
commit ff1e6dc216
90 changed files with 7192 additions and 402 deletions
+1 -1
View File
@@ -14,7 +14,7 @@ export default function FrameOverlay({ frameAsset }: FrameOverlayProps) {
if (!frameAsset) return null;
return (
<View style={styles.container} pointerEvents="none">
<View style={styles.container} pointerEvents="none" collapsable={false}>
<Image
source={frameAsset}
style={styles.frameImage}
+57 -19
View File
@@ -182,14 +182,12 @@ export default function CameraScreen({
}).filter((s: { pixels: number }) => s.pixels > 0);
parsedSizes.sort((a, b) => a.pixels - b.pixels);
// Find the smallest size that has at least 1920 width or height (approx 2MP)
const optimal = parsedSizes.find((s: { w: number; h: number }) => Math.max(s.w, s.h) >= 1920);
// Find the LARGEST size available to satisfy user request for original size
const optimal = parsedSizes[parsedSizes.length - 1];
if (optimal) {
console.log('Setting optimal pictureSize to prevent OOM:', optimal.size);
console.log('Setting max pictureSize for high-res original:', optimal.size);
setPictureSize(optimal.size);
} else if (parsedSizes.length > 0) {
setPictureSize(parsedSizes[parsedSizes.length - 1].size);
} else {
setPictureSize('fallback');
}
@@ -316,9 +314,28 @@ export default function CameraScreen({
return;
}
// Instead of manipulating the image and risking an OOM or BitmapFactory crash,
// we directly use the captured photo and rely on React Native's Image component
// to safely downsample it during rendering via resizeMethod="resize".
// Auto-save the high-res original raw photo to the gallery
try {
await saveToGallery(capturedUri);
console.log('Auto-saved high-res raw capture to gallery');
} catch (e) {
console.error('Failed to auto-save raw capture:', e);
}
// Downscale for the UI to prevent OutOfMemoryError in React Native Image
try {
console.log('Downscaling photo for PreviewScreen UI...');
const manipResult = await ImageManipulator.manipulateAsync(
capturedUri,
[{ resize: { width: 1920 } }],
{ compress: 0.8, format: ImageManipulator.SaveFormat.JPEG }
);
capturedUri = manipResult.uri;
console.log('Successfully downscaled UI photo.');
} catch (e) {
console.error('Failed to downscale photo, UI might crash:', e);
}
console.log('Photo captured successfully, proceeding to PreviewScreen.');
// Handle burst mode
@@ -415,13 +432,25 @@ export default function CameraScreen({
<FontAwesomeIcon icon={faUserGear} size={22} color={THEME.colors.accent} />
</TouchableOpacity>
{/* Header Event Text */}
<Text style={styles.headerTitle}>{welcomeText}</Text>
{/* Footer Instructions */}
<Text style={styles.footerInstructions}>
ZUM STARTEN TIPPEN Fotos machen Collage Drucken
</Text>
<View style={styles.idleContentArea} pointerEvents="none">
{/* Header Event Text */}
<Text
style={styles.headerTitle}
adjustsFontSizeToFit
numberOfLines={1}
>
{welcomeText}
</Text>
{/* Footer Instructions */}
<Text
style={styles.footerInstructions}
adjustsFontSizeToFit
numberOfLines={1}
>
ZUM STARTEN TIPPEN Fotos machen Collage Drucken
</Text>
</View>
{/* Password Prompt Modal */}
<Modal
@@ -615,6 +644,13 @@ const styles = StyleSheet.create({
right: 0,
bottom: 0,
backgroundColor: 'transparent',
justifyContent: 'center',
alignItems: 'center',
},
idleContentArea: {
height: '100%',
aspectRatio: 3 / 2,
position: 'relative',
},
captureOverlayContainer: {
flex: 1,
@@ -638,9 +674,10 @@ const styles = StyleSheet.create({
headerTitle: {
position: 'absolute',
top: 40,
width: '100%',
left: '2%',
width: '96%',
textAlign: 'center',
fontSize: 48,
fontSize: 80,
fontWeight: '900',
color: THEME.colors.accent,
letterSpacing: 6,
@@ -651,9 +688,10 @@ const styles = StyleSheet.create({
footerInstructions: {
position: 'absolute',
bottom: 40,
width: '100%',
left: '2%',
width: '96%',
textAlign: 'center',
fontSize: 20,
fontSize: 40,
fontWeight: 'bold',
color: THEME.colors.text,
letterSpacing: 2,
+3 -2
View File
@@ -208,8 +208,8 @@ export default function PreviewScreen({
return await viewShotRef.current.capture();
}
return fallbackPhoto;
} catch (e) {
console.error('Failed to capture composite:', e);
} catch (e: any) {
logger.error('Failed to capture composite', e);
return fallbackPhoto;
}
};
@@ -441,6 +441,7 @@ export default function PreviewScreen({
ref={viewShotRef}
options={{ format: 'jpg', quality: 0.95 }}
style={styles.viewShotContainer}
collapsable={false}
>
{renderCollageView()}
+6 -6
View File
@@ -41,14 +41,14 @@ export async function saveToGallery(localUri: string): Promise<string> {
if (!album) {
// 3. If it doesn't exist, create it with our asset
// copyAsset=false MOVES the asset instead of duplicating it
await createAlbumAsync(ALBUM_NAME, asset, false);
console.log(`Created new album "${ALBUM_NAME}" and moved photo.`);
// copyAsset=true completely bypasses the Android 11+ OS prompt!
await createAlbumAsync(ALBUM_NAME, asset, true);
console.log(`Created new album "${ALBUM_NAME}" and copied photo.`);
} else {
// 4. If it exists, add our asset to it
// copyAsset=false MOVES the asset instead of duplicating it
await addAssetsToAlbumAsync([asset], album, false);
console.log(`Moved photo to existing album "${ALBUM_NAME}".`);
// copyAsset=true completely bypasses the Android 11+ OS prompt!
await addAssetsToAlbumAsync([asset], album, true);
console.log(`Copied photo to existing album "${ALBUM_NAME}".`);
}
return asset.uri;