Initialize Schnappix Photo Booth application with custom UVC camera, silent Wi-Fi IPP printing, local gallery storage, and kiosk screen pinning support
This commit is contained in:
@@ -0,0 +1,261 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
StyleSheet,
|
||||
Text,
|
||||
View,
|
||||
TouchableOpacity,
|
||||
Modal,
|
||||
TextInput,
|
||||
TouchableWithoutFeedback,
|
||||
} from 'react-native';
|
||||
import { THEME } from '../styles/theme';
|
||||
|
||||
interface HomeScreenProps {
|
||||
onStart: () => void;
|
||||
onNavigateToAdmin: () => void;
|
||||
adminPassword?: string;
|
||||
}
|
||||
|
||||
export default function HomeScreen({ onStart, onNavigateToAdmin, adminPassword = '1234' }: HomeScreenProps) {
|
||||
const [passwordModalVisible, setPasswordModalVisible] = useState(false);
|
||||
const [enteredPassword, setEnteredPassword] = useState('');
|
||||
const [errorText, setErrorText] = useState('');
|
||||
|
||||
const handleSettingsTap = () => {
|
||||
setEnteredPassword('');
|
||||
setErrorText('');
|
||||
setPasswordModalVisible(true);
|
||||
};
|
||||
|
||||
const handlePasswordSubmit = () => {
|
||||
if (enteredPassword === adminPassword) {
|
||||
setPasswordModalVisible(false);
|
||||
onNavigateToAdmin();
|
||||
} else {
|
||||
setErrorText('Incorrect Password');
|
||||
setEnteredPassword('');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<TouchableWithoutFeedback onPress={onStart}>
|
||||
<View style={styles.container}>
|
||||
{/* Settings button in the top-right corner */}
|
||||
<TouchableOpacity
|
||||
style={styles.settingsButton}
|
||||
onPress={handleSettingsTap}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<Text style={styles.settingsIcon}>⚙️</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<View style={styles.content}>
|
||||
<Text style={styles.logo}>SCHNAPPIX</Text>
|
||||
<Text style={styles.title}>Welcome to our celebration!</Text>
|
||||
|
||||
<View style={styles.divider} />
|
||||
|
||||
<View style={styles.startButton}>
|
||||
<Text style={styles.startButtonText}>TAP ANYWHERE TO START</Text>
|
||||
</View>
|
||||
|
||||
<Text style={styles.footer}>Take photos • Create a collage • Print instantly</Text>
|
||||
</View>
|
||||
|
||||
{/* Password Prompt Modal */}
|
||||
<Modal
|
||||
visible={passwordModalVisible}
|
||||
transparent={true}
|
||||
animationType="fade"
|
||||
onRequestClose={() => setPasswordModalVisible(false)}
|
||||
>
|
||||
<View style={styles.modalOverlay}>
|
||||
<View style={styles.modalContent}>
|
||||
<Text style={styles.modalTitle}>Admin Access</Text>
|
||||
<Text style={styles.modalSub}>Enter password to open settings</Text>
|
||||
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
secureTextEntry
|
||||
placeholder="Enter password"
|
||||
placeholderTextColor={THEME.colors.textMuted}
|
||||
value={enteredPassword}
|
||||
onChangeText={setEnteredPassword}
|
||||
keyboardType="numeric"
|
||||
autoFocus
|
||||
/>
|
||||
|
||||
{errorText ? <Text style={styles.error}>{errorText}</Text> : null}
|
||||
|
||||
<View style={styles.modalButtons}>
|
||||
<TouchableOpacity
|
||||
style={[styles.button, styles.cancelButton]}
|
||||
onPress={() => setPasswordModalVisible(false)}
|
||||
>
|
||||
<Text style={styles.buttonText}>Cancel</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={[styles.button, styles.confirmButton]}
|
||||
onPress={handlePasswordSubmit}
|
||||
>
|
||||
<Text style={styles.buttonText}>Open</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
</View>
|
||||
</TouchableWithoutFeedback>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: THEME.colors.background,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
settingsButton: {
|
||||
position: 'absolute',
|
||||
top: 24,
|
||||
right: 24,
|
||||
width: 50,
|
||||
height: 50,
|
||||
borderRadius: THEME.borderRadius.round,
|
||||
backgroundColor: THEME.colors.surfaceSecondary,
|
||||
borderWidth: 1,
|
||||
borderColor: THEME.colors.border,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
zIndex: 999,
|
||||
},
|
||||
settingsIcon: {
|
||||
fontSize: 24,
|
||||
color: THEME.colors.text,
|
||||
},
|
||||
content: {
|
||||
alignItems: 'center',
|
||||
padding: THEME.spacing.xl,
|
||||
borderRadius: THEME.borderRadius.lg,
|
||||
backgroundColor: THEME.colors.surface,
|
||||
borderWidth: 1,
|
||||
borderColor: THEME.colors.border,
|
||||
width: '60%',
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 10 },
|
||||
shadowOpacity: 0.3,
|
||||
shadowRadius: 20,
|
||||
elevation: 10,
|
||||
},
|
||||
logo: {
|
||||
fontSize: 54,
|
||||
fontWeight: '900',
|
||||
color: THEME.colors.primary,
|
||||
letterSpacing: 8,
|
||||
marginBottom: THEME.spacing.sm,
|
||||
},
|
||||
title: {
|
||||
fontSize: 22,
|
||||
color: THEME.colors.text,
|
||||
textAlign: 'center',
|
||||
marginBottom: THEME.spacing.lg,
|
||||
letterSpacing: 1,
|
||||
},
|
||||
divider: {
|
||||
width: 60,
|
||||
height: 3,
|
||||
backgroundColor: THEME.colors.accent,
|
||||
marginBottom: THEME.spacing.xl,
|
||||
borderRadius: THEME.borderRadius.sm,
|
||||
},
|
||||
startButton: {
|
||||
paddingVertical: THEME.spacing.md,
|
||||
paddingHorizontal: THEME.spacing.xl,
|
||||
backgroundColor: THEME.colors.primary,
|
||||
borderRadius: THEME.borderRadius.round,
|
||||
marginBottom: THEME.spacing.xl,
|
||||
},
|
||||
startButtonText: {
|
||||
color: THEME.colors.text,
|
||||
fontSize: 18,
|
||||
fontWeight: 'bold',
|
||||
letterSpacing: 2,
|
||||
},
|
||||
footer: {
|
||||
fontSize: 14,
|
||||
color: THEME.colors.textMuted,
|
||||
letterSpacing: 1,
|
||||
},
|
||||
modalOverlay: {
|
||||
flex: 1,
|
||||
backgroundColor: THEME.colors.overlay,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
modalContent: {
|
||||
width: 320,
|
||||
padding: THEME.spacing.lg,
|
||||
borderRadius: THEME.borderRadius.md,
|
||||
backgroundColor: THEME.colors.surfaceSecondary,
|
||||
borderWidth: 1,
|
||||
borderColor: THEME.colors.border,
|
||||
alignItems: 'center',
|
||||
},
|
||||
modalTitle: {
|
||||
fontSize: 20,
|
||||
fontWeight: 'bold',
|
||||
color: THEME.colors.text,
|
||||
marginBottom: THEME.spacing.xs,
|
||||
},
|
||||
modalSub: {
|
||||
fontSize: 14,
|
||||
color: THEME.colors.textMuted,
|
||||
marginBottom: THEME.spacing.md,
|
||||
},
|
||||
input: {
|
||||
width: '100%',
|
||||
height: 50,
|
||||
backgroundColor: THEME.colors.surface,
|
||||
borderColor: THEME.colors.border,
|
||||
borderWidth: 1,
|
||||
borderRadius: THEME.borderRadius.sm,
|
||||
color: THEME.colors.text,
|
||||
paddingHorizontal: THEME.spacing.md,
|
||||
fontSize: 16,
|
||||
textAlign: 'center',
|
||||
marginBottom: THEME.spacing.sm,
|
||||
},
|
||||
error: {
|
||||
color: THEME.colors.error,
|
||||
fontSize: 14,
|
||||
marginBottom: THEME.spacing.sm,
|
||||
},
|
||||
modalButtons: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
width: '100%',
|
||||
marginTop: THEME.spacing.sm,
|
||||
},
|
||||
button: {
|
||||
flex: 1,
|
||||
height: 45,
|
||||
borderRadius: THEME.borderRadius.sm,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginHorizontal: THEME.spacing.xs,
|
||||
},
|
||||
cancelButton: {
|
||||
backgroundColor: 'transparent',
|
||||
borderWidth: 1,
|
||||
borderColor: THEME.colors.border,
|
||||
},
|
||||
confirmButton: {
|
||||
backgroundColor: THEME.colors.primary,
|
||||
},
|
||||
buttonText: {
|
||||
color: THEME.colors.text,
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user