Untitled

 avatar
unknown
plain_text
10 months ago
6.5 kB
11
Indexable
import React, { useState, useEffect, useRef } from 'react';
try {
const photo = await cameraRef.current.takePictureAsync({ quality: 0.5, base64: false });
// save to local app folder (demo). In production: upload to cloud storage and set TTL in DB.
const filename = `${FileSystem.documentDirectory}snap_${Date.now()}.jpg`;
await FileSystem.copyAsync({ from: photo.uri, to: filename });


const newSnap = {
id: `${Date.now()}`,
uri: filename,
createdAt: Date.now(),
// snaps expire after 10 seconds in this demo; change as desired
expiresAt: Date.now() + 10000,
sender: 'You (demo)'
};
setSnaps(prev => [newSnap, ...prev]);


// Optionally save to camera roll
if (hasMediaPermission) {
await MediaLibrary.createAssetAsync(photo.uri);
}


Alert.alert('Snap taken', 'Snap saved locally and will expire in 10s (demo).');
} catch (e) {
console.error(e);
Alert.alert('Error', 'Could not take snap');
}
}


function renderCamera() {
return (
<Camera style={styles.camera} type={cameraType} ref={cameraRef} ratio="16:9">
<View style={styles.cameraControls}>
<TouchableOpacity onPress={() => setCameraType(prev => prev === Camera.Constants.Type.back ? Camera.Constants.Type.front : Camera.Constants.Type.back)} style={styles.controlBtn}>
<Text style={styles.controlText}>Flip</Text>
</TouchableOpacity>
<TouchableOpacity onPress={takeSnap} style={[styles.controlBtn, styles.captureBtn]}>
<Text style={styles.controlText}>SNAP</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => setMode('snaps')} style={styles.controlBtn}>
<Text style={styles.controlText}>My Snaps</Text>
</TouchableOpacity>
</View>
</Camera>
);
}


function renderSnaps() {
return (
<SafeAreaView style={styles.container}>
<Text style={styles.header}>Your Snaps (ephemeral)</Text>
<FlatList
data={snaps}
keyExtractor={item => item.id}
renderItem={({ item }) => (
<View style={styles.snapRow}>
<Image source={{ uri: item.uri }} style={styles.thumb} />
<View style={{ flex: 1 }}>
<Text numberOfLines={1}>{item.sender}</Text>
<Text numberOfLines={1}>Expires in {Math.max(0, Math.ceil((item.expiresAt - Date.now()) / 1000))}s</Text>
</View>
<TouchableOpacity onPress={() => { /* view fullsnap */ viewFullSnap(item); }} style={styles.openBtn}><Text>Open</Text></TouchableOpacity>
</View>
)}
ListEmptyComponent={<Text style={{ padding: 20 }}>No snaps — take one!</Text>}
/>
<View style={styles.bottomBar}>
<TouchableOpacity onPress={() => setMode('camera')} style={styles.navBtn}><Text>Camera</Text></TouchableOpacity>
<TouchableOpacity onPress={() => setMode('games')} style={styles.navBtn}><Text>Games</Text></TouchableOpacity>
</View>
</SafeAreaView>
);
}


function viewFullSnap(snap) {
// for demo: show alert with a full-screen image for the remaining TTL, then remove it after viewing
const remaining = Math.max(0, snap.expiresAt - Date.now());
if (remaining <= 0) {
Alert.alert('Gone', 'This snap has already expired.');
setSnaps(prev => prev.filter(s => s.id !== snap.id));
return;
}
// show simple full-screen view component
Alert.alert('Viewing snap (demo)', `You can view this snap for ${Math.ceil(remaining / 1000)} seconds.`);
// For a real viewer: navigate to a fullscreen screen that counts down and then deletes the snap.
}


function renderGames() {
// A simple HTML5 game embedded via WebView. In production, you can host games, integrate Unity with react-native-unity-view,
// or build native mini-games with react-native-game-engine and multiplayer via WebRTC/socket servers.


const simpleGameHtml = `
<!doctype html>
<html>
<head><meta name="viewport" content="width=device-width, initial-scale=1"></head>
<body style="margin:0;display:flex;align-items:center;justify-content:center;height:100vh;background:#111;color:#fff;">
<div id="app">
<h2>Tap the circle!</h2>
<div id="score">Score: 0</div>
<canvas id="c" width="320" height="320" style="border:1px solid #333;background:#222"></canvas>
</div>
<script>
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
let score = 0;
let circle = {x:160,y:160,r:20};
function draw(){
ctx.clearRect(0,0,320,320);
ctx.beginPath();ctx.arc(circle.x,circle.y,circle.r,0,Math.PI*2);ctx.fillStyle='#0af';ctx.fill();
}
canvas.addEventListener('click',(e)=>{
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left; const y = e.clientY - rect.top;
const dx = x-circle.x, dy = y-circle.y;
if (Math.sqrt(dx*dx+dy*dy) <= circle.r) { score++; document.getElementById('score').innerText='Score: '+score; moveCircle(); }
});
function moveCircle(){ circle.x = 30 + Math.random()*260; circle.y = 30 + Math.random()*260; draw(); }
moveCircle();
</script>
</body>
</html>
`;


return (
<SafeAreaView style={{ flex: 1 }}>
<View style={{ height: 50, justifyContent: 'center', alignItems: 'center', borderBottomWidth: 1 }}>
<Text style={{ fontWeight: '600' }}>Games</Text>
</View>
<WebView
originWhitelist={["*"]}
source={{ html: simpleGameHtml }}
style={{ flex: 1 }}
/>
<View style={styles.bottomBar}>
<TouchableOpacity onPress={() => setMode('camera')} style={styles.navBtn}><Text>Camera</Text></TouchableOpacity>
<TouchableOpacity onPress={() => setMode('snaps')} style={styles.navBtn}><Text>My Snaps</Text></TouchableOpacity>
</View>
</SafeAreaView>
);
}


return (
<View style={{ flex: 1 }}>
{mode === 'camera' && renderCamera()}
{mode === 'snaps' && renderSnaps()}
{mode === 'games' && renderGames()}
</View>
);
}


const styles = StyleSheet.create({
container: { flex: 1 },
center: { flex: 1, alignItems: 'center', justifyContent: 'center' },
camera: { flex: 1, justifyContent: 'flex-end' },
cameraControls: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-around', padding: 12, backgroundColor: 'rgba(0,0,0,0.25)' },
controlBtn: { padding: 10, borderRadius: 8, backgroundColor: 'rgba(255,255,255,0.15)' },
captureBtn: { backgroundColor: 'rgba(255,255,255,0.35)' },
controlText: { color: '#fff', fontWeight: '600' },
header: { fontSize: 20, fontWeight: '700', padding: 12 },
snapRow: { flexDirection: 'row', alignItems: 'center', padding: 12, borderBottomWidth: 1, borderColor: '#eee' },
thumb: { width: 80, height: 80, borderRadius: 8, marginRight: 10 },
openBtn: { padding: 8, backgroundColor: '#ddd', borderRadius: 6 },
bottomBar: { height: 60, flexDirection: 'row', borderTopWidth: 1, justifyContent: 'space-around', alignItems: 'center' },
navBtn: { padding: 10 }
});
Editor is loading...
Leave a Comment