first release 0.0.0.2
This commit is contained in:
@@ -0,0 +1,258 @@
|
||||
/**
|
||||
* FileUpload - Datei-Auswahl und -Versand
|
||||
*
|
||||
* Oeffnet den Dateimanager des Geraets, zeigt eine Vorschau
|
||||
* und konvertiert die Datei zu Base64 fuer die Uebertragung.
|
||||
*/
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
Image,
|
||||
StyleSheet,
|
||||
ActivityIndicator,
|
||||
} from 'react-native';
|
||||
import DocumentPicker, {
|
||||
DocumentPickerResponse,
|
||||
} from 'react-native-document-picker';
|
||||
|
||||
// --- Typen ---
|
||||
|
||||
export interface FileData {
|
||||
name: string;
|
||||
type: string;
|
||||
size: number;
|
||||
base64: string;
|
||||
uri: string;
|
||||
}
|
||||
|
||||
interface FileUploadProps {
|
||||
onFileSelected: (file: FileData) => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
// Unterstuetzte Dateitypen
|
||||
const SUPPORTED_TYPES = [
|
||||
DocumentPicker.types.images,
|
||||
DocumentPicker.types.pdf,
|
||||
DocumentPicker.types.docx,
|
||||
DocumentPicker.types.plainText,
|
||||
];
|
||||
|
||||
// --- Komponente ---
|
||||
|
||||
const FileUpload: React.FC<FileUploadProps> = ({ onFileSelected, onCancel }) => {
|
||||
const [selectedFile, setSelectedFile] = useState<DocumentPickerResponse | null>(null);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const pickFile = async () => {
|
||||
setError(null);
|
||||
try {
|
||||
const result = await DocumentPicker.pick({
|
||||
type: SUPPORTED_TYPES,
|
||||
copyTo: 'cachesDirectory',
|
||||
});
|
||||
|
||||
if (result.length > 0) {
|
||||
setSelectedFile(result[0]);
|
||||
}
|
||||
} catch (err) {
|
||||
if (DocumentPicker.isCancel(err)) {
|
||||
onCancel();
|
||||
} else {
|
||||
setError('Fehler beim Auswaehlen der Datei');
|
||||
console.error('[FileUpload] Fehler:', err);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const sendFile = async () => {
|
||||
if (!selectedFile) return;
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
// In Produktion: Datei lesen und zu Base64 konvertieren
|
||||
// const base64 = await RNFS.readFile(selectedFile.fileCopyUri || selectedFile.uri, 'base64');
|
||||
const base64Placeholder = '';
|
||||
|
||||
const fileData: FileData = {
|
||||
name: selectedFile.name || 'unbenannt',
|
||||
type: selectedFile.type || 'application/octet-stream',
|
||||
size: selectedFile.size || 0,
|
||||
base64: base64Placeholder,
|
||||
uri: selectedFile.uri,
|
||||
};
|
||||
|
||||
onFileSelected(fileData);
|
||||
} catch (err) {
|
||||
setError('Fehler beim Verarbeiten der Datei');
|
||||
console.error('[FileUpload] Verarbeitungsfehler:', err);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const isImage = selectedFile?.type?.startsWith('image/');
|
||||
const fileSizeFormatted = selectedFile?.size
|
||||
? selectedFile.size > 1024 * 1024
|
||||
? `${(selectedFile.size / (1024 * 1024)).toFixed(1)} MB`
|
||||
: `${(selectedFile.size / 1024).toFixed(0)} KB`
|
||||
: '';
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
{!selectedFile ? (
|
||||
// Datei auswaehlen
|
||||
<TouchableOpacity style={styles.pickButton} onPress={pickFile} activeOpacity={0.7}>
|
||||
<Text style={styles.pickIcon}>{'\uD83D\uDCC1'}</Text>
|
||||
<Text style={styles.pickText}>Datei ausw\u00E4hlen</Text>
|
||||
<Text style={styles.pickHint}>JPG, PNG, PDF, DOCX, TXT</Text>
|
||||
</TouchableOpacity>
|
||||
) : (
|
||||
// Vorschau und Senden
|
||||
<View style={styles.previewContainer}>
|
||||
{isImage ? (
|
||||
<Image source={{ uri: selectedFile.uri }} style={styles.imagePreview} />
|
||||
) : (
|
||||
<View style={styles.filePreview}>
|
||||
<Text style={styles.fileIcon}>{'\uD83D\uDCC4'}</Text>
|
||||
</View>
|
||||
)}
|
||||
|
||||
<Text style={styles.fileName} numberOfLines={1}>
|
||||
{selectedFile.name}
|
||||
</Text>
|
||||
<Text style={styles.fileSize}>{fileSizeFormatted}</Text>
|
||||
|
||||
{error && <Text style={styles.errorText}>{error}</Text>}
|
||||
|
||||
<View style={styles.buttonRow}>
|
||||
<TouchableOpacity
|
||||
style={styles.cancelButton}
|
||||
onPress={() => setSelectedFile(null)}
|
||||
>
|
||||
<Text style={styles.cancelButtonText}>Andere Datei</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.sendButton}
|
||||
onPress={sendFile}
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? (
|
||||
<ActivityIndicator color="#FFFFFF" size="small" />
|
||||
) : (
|
||||
<Text style={styles.sendButtonText}>Senden</Text>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
// --- Styles ---
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: '#1A1A2E',
|
||||
borderRadius: 16,
|
||||
padding: 20,
|
||||
margin: 12,
|
||||
},
|
||||
pickButton: {
|
||||
alignItems: 'center',
|
||||
padding: 30,
|
||||
borderWidth: 2,
|
||||
borderColor: '#2A2A3E',
|
||||
borderStyle: 'dashed',
|
||||
borderRadius: 12,
|
||||
},
|
||||
pickIcon: {
|
||||
fontSize: 40,
|
||||
marginBottom: 10,
|
||||
},
|
||||
pickText: {
|
||||
color: '#FFFFFF',
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
},
|
||||
pickHint: {
|
||||
color: '#666680',
|
||||
fontSize: 12,
|
||||
marginTop: 4,
|
||||
},
|
||||
previewContainer: {
|
||||
alignItems: 'center',
|
||||
},
|
||||
imagePreview: {
|
||||
width: 200,
|
||||
height: 200,
|
||||
borderRadius: 12,
|
||||
marginBottom: 12,
|
||||
resizeMode: 'cover',
|
||||
},
|
||||
filePreview: {
|
||||
width: 80,
|
||||
height: 80,
|
||||
borderRadius: 12,
|
||||
backgroundColor: '#2A2A3E',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginBottom: 12,
|
||||
},
|
||||
fileIcon: {
|
||||
fontSize: 36,
|
||||
},
|
||||
fileName: {
|
||||
color: '#FFFFFF',
|
||||
fontSize: 14,
|
||||
fontWeight: '500',
|
||||
maxWidth: 250,
|
||||
},
|
||||
fileSize: {
|
||||
color: '#666680',
|
||||
fontSize: 12,
|
||||
marginTop: 2,
|
||||
},
|
||||
errorText: {
|
||||
color: '#FF3B30',
|
||||
fontSize: 12,
|
||||
marginTop: 8,
|
||||
},
|
||||
buttonRow: {
|
||||
flexDirection: 'row',
|
||||
marginTop: 16,
|
||||
gap: 12,
|
||||
},
|
||||
cancelButton: {
|
||||
paddingHorizontal: 20,
|
||||
paddingVertical: 10,
|
||||
borderRadius: 8,
|
||||
backgroundColor: '#2A2A3E',
|
||||
},
|
||||
cancelButtonText: {
|
||||
color: '#8888AA',
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
},
|
||||
sendButton: {
|
||||
paddingHorizontal: 28,
|
||||
paddingVertical: 10,
|
||||
borderRadius: 8,
|
||||
backgroundColor: '#0096FF',
|
||||
minWidth: 90,
|
||||
alignItems: 'center',
|
||||
},
|
||||
sendButtonText: {
|
||||
color: '#FFFFFF',
|
||||
fontSize: 14,
|
||||
fontWeight: '700',
|
||||
},
|
||||
});
|
||||
|
||||
export default FileUpload;
|
||||
Reference in New Issue
Block a user