Verbesserungen: Admin-Passwort Hinweis, Mobile Skalierung in PreviewScreen, Rahmen-Menü Toggle, Footer Layout Fix
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
# Versioning & Build Rules Addendum
|
||||||
|
|
||||||
|
## Build Configuration
|
||||||
|
- The app MUST ALWAYS be signed with `schnappix-upload-key.keystore`. This is handled automatically by the custom Expo plugin `withAndroidSigning.js`. Do not modify or remove this plugin.
|
||||||
|
- The `schnappix-upload-key.keystore` file is checked into the Git repository. Do NOT delete it, ignore it in git, or change its password (`#O0he7k00O0he7k00!`).
|
||||||
|
- The Expo Media Library plugin injects `READ_MEDIA_IMAGES` and `READ_MEDIA_VIDEO` permissions into the Android manifest by default. These are rejected by Google Play for this specific app. To prevent this, the `withRemoveMediaPermissions.js` plugin MUST ALWAYS be included in `app.json`. This plugin forcibly strips these permissions using Android's `tools:node="remove"` directive during compilation. Do not remove this plugin.
|
||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
TextInput,
|
TextInput,
|
||||||
TouchableWithoutFeedback,
|
TouchableWithoutFeedback,
|
||||||
PermissionsAndroid,
|
PermissionsAndroid,
|
||||||
|
useWindowDimensions,
|
||||||
} from 'react-native';
|
} from 'react-native';
|
||||||
import { CameraView, useCameraPermissions } from 'expo-camera';
|
import { CameraView, useCameraPermissions } from 'expo-camera';
|
||||||
import * as FileSystem from 'expo-file-system/legacy';
|
import * as FileSystem from 'expo-file-system/legacy';
|
||||||
@@ -110,6 +111,9 @@ export default function CameraScreen({
|
|||||||
const completionTimerRef = useRef<any>(null);
|
const completionTimerRef = useRef<any>(null);
|
||||||
const isCancelledRef = useRef<boolean>(false);
|
const isCancelledRef = useRef<boolean>(false);
|
||||||
|
|
||||||
|
const { width } = useWindowDimensions();
|
||||||
|
const iconSize = width < 768 ? 18 : 32;
|
||||||
|
|
||||||
// Reanimated countdown pulse animation
|
// Reanimated countdown pulse animation
|
||||||
const scale = useSharedValue(1);
|
const scale = useSharedValue(1);
|
||||||
|
|
||||||
@@ -538,9 +542,7 @@ export default function CameraScreen({
|
|||||||
>
|
>
|
||||||
{footerText === 'Display tippen! • Lächeln! • Foto schnappen!' ? (
|
{footerText === 'Display tippen! • Lächeln! • Foto schnappen!' ? (
|
||||||
<Text>
|
<Text>
|
||||||
<FontAwesomeIcon icon={faHandPointer} color={THEME.colors.text} size={32} />ㅤDisplay tippen!ㅤ•ㅤ
|
<FontAwesomeIcon icon={faHandPointer} color={THEME.colors.text} size={iconSize} /> Display tippen! • <FontAwesomeIcon icon={faFaceSmile} color={THEME.colors.text} size={iconSize} /> Lächeln! • <FontAwesomeIcon icon={faCamera} color={THEME.colors.text} size={iconSize} /> Foto schnappen!
|
||||||
<FontAwesomeIcon icon={faFaceSmile} color={THEME.colors.text} size={32} />ㅤLächeln!ㅤ•ㅤ
|
|
||||||
<FontAwesomeIcon icon={faCamera} color={THEME.colors.text} size={32} />ㅤFoto schnappen!
|
|
||||||
</Text>
|
</Text>
|
||||||
) : (
|
) : (
|
||||||
footerText
|
footerText
|
||||||
@@ -559,6 +561,9 @@ export default function CameraScreen({
|
|||||||
<View style={styles.modalContent}>
|
<View style={styles.modalContent}>
|
||||||
<Text style={styles.modalTitle}>Admin-Zugang</Text>
|
<Text style={styles.modalTitle}>Admin-Zugang</Text>
|
||||||
<Text style={styles.modalSub}>Passwort eingeben, um Einstellungen zu öffnen</Text>
|
<Text style={styles.modalSub}>Passwort eingeben, um Einstellungen zu öffnen</Text>
|
||||||
|
<Text style={[styles.modalSub, { color: THEME.colors.error, marginTop: 10, fontSize: 14, fontStyle: 'italic' }]}>
|
||||||
|
Tipp: Standardcode ist 1234. Bitte ändern! Ein Zurücksetzen ist nur durch Neuinstallation der App möglich.
|
||||||
|
</Text>
|
||||||
|
|
||||||
<TextInput
|
<TextInput
|
||||||
style={styles.input}
|
style={styles.input}
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ export default function PreviewScreen({
|
|||||||
|
|
||||||
const { width, height } = useWindowDimensions();
|
const { width, height } = useWindowDimensions();
|
||||||
const isPortrait = height > width;
|
const isPortrait = height > width;
|
||||||
|
const isSmallDevice = width < 768;
|
||||||
|
|
||||||
const [activeUris, setActiveUris] = useState<string[]>([]);
|
const [activeUris, setActiveUris] = useState<string[]>([]);
|
||||||
|
|
||||||
@@ -117,6 +118,7 @@ export default function PreviewScreen({
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
const [showStickerTray, setShowStickerTray] = useState<boolean>(false);
|
const [showStickerTray, setShowStickerTray] = useState<boolean>(false);
|
||||||
|
const [showFrameTray, setShowFrameTray] = useState<boolean>(false);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
logger.log(`PreviewScreen mounted with ${photoUris.length} photos.`);
|
logger.log(`PreviewScreen mounted with ${photoUris.length} photos.`);
|
||||||
@@ -537,10 +539,10 @@ export default function PreviewScreen({
|
|||||||
|
|
||||||
{/* Right panel: Controls */}
|
{/* Right panel: Controls */}
|
||||||
<ScrollView
|
<ScrollView
|
||||||
style={[styles.controlPanel, { flex: isPortrait ? 1 : 0.8 }]}
|
style={[styles.controlPanel, { flex: isPortrait ? 1 : 0.8, padding: isSmallDevice ? THEME.spacing.md : THEME.spacing.xl }]}
|
||||||
contentContainerStyle={{ flexGrow: 1, justifyContent: 'center' }}
|
contentContainerStyle={{ flexGrow: 1, justifyContent: 'center' }}
|
||||||
>
|
>
|
||||||
<Text style={styles.header}>{eventText}</Text>
|
<Text style={[styles.header, isSmallDevice && { fontSize: 18, marginBottom: THEME.spacing.sm }]}>{eventText}</Text>
|
||||||
|
|
||||||
{/* Thumbnail Reel for Photo Selection */}
|
{/* Thumbnail Reel for Photo Selection */}
|
||||||
{photoUris.length > 1 && (
|
{photoUris.length > 1 && (
|
||||||
@@ -581,8 +583,12 @@ export default function PreviewScreen({
|
|||||||
{/* Editing Tools Row */}
|
{/* Editing Tools Row */}
|
||||||
<View style={styles.editToolsRow}>
|
<View style={styles.editToolsRow}>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[styles.editToolBtn, showStickerTray && styles.editToolBtnActive]}
|
style={[styles.editToolBtn, isSmallDevice && { paddingVertical: 8, paddingHorizontal: 12 }, showStickerTray && styles.editToolBtnActive]}
|
||||||
onPress={() => { logger.log(`Action: Toggled sticker tray ${!showStickerTray}`); setShowStickerTray(!showStickerTray); }}
|
onPress={() => {
|
||||||
|
logger.log(`Action: Toggled sticker tray ${!showStickerTray}`);
|
||||||
|
setShowStickerTray(!showStickerTray);
|
||||||
|
if (!showStickerTray) setShowFrameTray(false);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faFaceGrinStars}
|
icon={faFaceGrinStars}
|
||||||
@@ -596,23 +602,19 @@ export default function PreviewScreen({
|
|||||||
|
|
||||||
{frameMode === 'available' && (
|
{frameMode === 'available' && (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[styles.editToolBtn, selectedFrameId !== null && styles.editToolBtnActive]}
|
style={[styles.editToolBtn, isSmallDevice && { paddingVertical: 8, paddingHorizontal: 12 }, showFrameTray && styles.editToolBtnActive]}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
if (selectedFrameId !== null) {
|
logger.log(`Action: Toggled frame tray ${!showFrameTray}`);
|
||||||
logger.log('Action: Removed frame');
|
setShowFrameTray(!showFrameTray);
|
||||||
setSelectedFrameId(null);
|
if (!showFrameTray) setShowStickerTray(false);
|
||||||
} else {
|
|
||||||
logger.log('Action: Toggled frame selection');
|
|
||||||
}
|
|
||||||
// FramePicker is shown below
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
icon={faBorderAll}
|
icon={faBorderAll}
|
||||||
size={22}
|
size={22}
|
||||||
color={selectedFrameId !== null ? THEME.colors.text : THEME.colors.accent}
|
color={showFrameTray ? THEME.colors.text : THEME.colors.accent}
|
||||||
/>
|
/>
|
||||||
<Text style={[styles.editToolText, selectedFrameId !== null && styles.editToolTextActive]}>
|
<Text style={[styles.editToolText, showFrameTray && styles.editToolTextActive]}>
|
||||||
Rahmen
|
Rahmen
|
||||||
</Text>
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
@@ -620,7 +622,7 @@ export default function PreviewScreen({
|
|||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* Frame Picker (when mode = available) */}
|
{/* Frame Picker (when mode = available) */}
|
||||||
{frameMode === 'available' && (
|
{frameMode === 'available' && showFrameTray && (
|
||||||
<FramePicker
|
<FramePicker
|
||||||
selectedFrameId={selectedFrameId}
|
selectedFrameId={selectedFrameId}
|
||||||
onSelectFrame={(id) => {
|
onSelectFrame={(id) => {
|
||||||
@@ -633,12 +635,12 @@ export default function PreviewScreen({
|
|||||||
|
|
||||||
{/* Action Buttons */}
|
{/* Action Buttons */}
|
||||||
<View style={styles.actions}>
|
<View style={styles.actions}>
|
||||||
<TouchableOpacity style={[styles.actionBtn, styles.printBtn, isProcessing && styles.btnDisabled]} onPress={handlePrint} activeOpacity={0.8} disabled={isProcessing}>
|
<TouchableOpacity style={[styles.actionBtn, styles.printBtn, isProcessing && styles.btnDisabled, isSmallDevice && { marginBottom: THEME.spacing.sm }]} onPress={handlePrint} activeOpacity={0.8} disabled={isProcessing}>
|
||||||
<LinearGradient
|
<LinearGradient
|
||||||
colors={THEME.gradient.primary}
|
colors={THEME.gradient.primary}
|
||||||
start={{ x: 0, y: 0.5 }}
|
start={{ x: 0, y: 0.5 }}
|
||||||
end={{ x: 1, y: 0.5 }}
|
end={{ x: 1, y: 0.5 }}
|
||||||
style={styles.printGradient}
|
style={[styles.printGradient, isSmallDevice && { paddingVertical: THEME.spacing.sm }]}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faPrint} size={18} color={THEME.colors.text} style={{ marginRight: 8 }} />
|
<FontAwesomeIcon icon={faPrint} size={18} color={THEME.colors.text} style={{ marginRight: 8 }} />
|
||||||
<Text style={styles.actionBtnText}>JETZT DRUCKEN</Text>
|
<Text style={styles.actionBtnText}>JETZT DRUCKEN</Text>
|
||||||
@@ -648,7 +650,7 @@ export default function PreviewScreen({
|
|||||||
|
|
||||||
|
|
||||||
{photoUris.length < 4 && (
|
{photoUris.length < 4 && (
|
||||||
<TouchableOpacity style={[styles.actionBtn, styles.addBtn, isProcessing && styles.btnDisabled]} onPress={onAddAnother} disabled={isProcessing}>
|
<TouchableOpacity style={[styles.actionBtn, styles.addBtn, isProcessing && styles.btnDisabled, isSmallDevice && { paddingVertical: THEME.spacing.sm, marginBottom: THEME.spacing.sm }]} onPress={onAddAnother} disabled={isProcessing}>
|
||||||
<FontAwesomeIcon icon={faPlus} size={16} color={THEME.colors.text} style={{ marginRight: 8 }} />
|
<FontAwesomeIcon icon={faPlus} size={16} color={THEME.colors.text} style={{ marginRight: 8 }} />
|
||||||
<Text style={styles.actionBtnText}>Weiteres Foto aufnehmen</Text>
|
<Text style={styles.actionBtnText}>Weiteres Foto aufnehmen</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
|||||||
Reference in New Issue
Block a user