update: app changes, new frame, and latest APK build
This commit is contained in:
@@ -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}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user