This commit is contained in:
2026-03-14 19:45:08 -03:00
parent 9ac83ad823
commit 74adc35b53
23 changed files with 1082 additions and 150 deletions
+67 -29
View File
@@ -1,6 +1,6 @@
import React, { useState } from 'react';
import {
View, Text, ScrollView, TouchableOpacity, TextInput, StyleSheet, Alert,
View, Text, ScrollView, TouchableOpacity, TextInput, StyleSheet, Alert, Modal, KeyboardAvoidingView, Platform,
} from 'react-native';
import { useLocalSearchParams, useRouter } from 'expo-router';
import { useForm, Controller } from 'react-hook-form';
@@ -50,7 +50,8 @@ export default function EditFilamentScreen(): React.ReactElement {
const [selectedMaterial, setSelectedMaterial] = useState<Material>((filament?.material as Material) ?? 'PLA');
const [selectedPresetId, setSelectedPresetId] = useState<string | null>(filament?.spoolPresetId ?? systemPresets[0]?.id ?? null);
const [isLoading, setIsLoading] = useState(false);
const [isOpeningColorPicker, setIsOpeningColorPicker] = useState(false);
const [isColorPickerOpen, setIsColorPickerOpen] = useState(false);
const [colorInputValue, setColorInputValue] = useState('');
const { control, handleSubmit, watch, formState: { errors } } = useForm<FormData>({
resolver: zodResolver(schema),
@@ -86,31 +87,29 @@ export default function EditFilamentScreen(): React.ReactElement {
}
const handleOpenColorPicker = (): void => {
if (isOpeningColorPicker) return;
setIsOpeningColorPicker(true);
Alert.prompt(
'Cor Customizada',
'Digite um código de cor hexadecimal (ex: #FF5733)',
[
{ text: 'Cancelar', style: 'cancel', onPress: () => setIsOpeningColorPicker(false) },
{
text: 'Confirmar',
onPress: (value) => {
setIsOpeningColorPicker(false);
if (!value) return;
const normalized = normalizeHex(value.trim());
if (isValidHex(normalized)) {
setSelectedColor(normalized);
setHexInput(normalized);
} else {
Alert.alert('Erro', 'Código hexadecimal inválido. Use o formato #RRGGBB ou #RGB.');
}
},
},
],
'plain-text',
selectedColor,
);
setColorInputValue(selectedColor);
setIsColorPickerOpen(true);
};
const handleConfirmColor = (): void => {
if (!colorInputValue) {
Alert.alert('Erro', 'Digite um código hexadecimal');
return;
}
const normalized = normalizeHex(colorInputValue.trim());
if (isValidHex(normalized)) {
setSelectedColor(normalized);
setHexInput(normalized);
setIsColorPickerOpen(false);
setColorInputValue('');
} else {
Alert.alert('Erro', 'Código hexadecimal inválido. Use o formato #RRGGBB ou #RGB.');
}
};
const handleCancelColor = (): void => {
setIsColorPickerOpen(false);
setColorInputValue('');
};
const handleDelete = async (): Promise<void> => {
@@ -183,7 +182,34 @@ export default function EditFilamentScreen(): React.ReactElement {
}
return (
<SafeAreaView style={styles.safe}>
<>
<Modal visible={isColorPickerOpen} transparent animationType="fade">
<View style={styles.modalOverlay}>
<KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : 'height'} style={styles.modalContent}>
<View style={styles.modalCard}>
<Text style={styles.modalTitle}>Código Hexadecimal</Text>
<TextInput
style={styles.modalInput}
placeholder="#FF5733"
placeholderTextColor={colors.textSecondary}
value={colorInputValue}
onChangeText={setColorInputValue}
autoFocus
/>
<View style={styles.modalButtons}>
<TouchableOpacity onPress={handleCancelColor} style={styles.modalBtnCancel}>
<Text style={styles.modalBtnTextCancel}>Cancelar</Text>
</TouchableOpacity>
<TouchableOpacity onPress={handleConfirmColor} style={styles.modalBtnConfirm}>
<Text style={styles.modalBtnTextConfirm}>Confirmar</Text>
</TouchableOpacity>
</View>
</View>
</KeyboardAvoidingView>
</View>
</Modal>
<SafeAreaView style={styles.safe}>
<ScrollView showsVerticalScrollIndicator={false} keyboardShouldPersistTaps="handled">
{/* Header */}
<View style={styles.header}>
@@ -203,7 +229,7 @@ export default function EditFilamentScreen(): React.ReactElement {
<View style={styles.colorPreviewRow}>
<View style={[styles.colorSquare, { backgroundColor: selectedColor }]} />
<Text style={styles.hexValue}>{hexInput}</Text>
<TouchableOpacity><Ionicons name="pencil-outline" size={18} color={colors.textSecondary} /></TouchableOpacity>
<TouchableOpacity onPress={handleOpenColorPicker}><Ionicons name="pencil-outline" size={18} color={colors.textSecondary} /></TouchableOpacity>
</View>
<View style={styles.colorPalette}>
{PRESET_COLORS.map((c) => (
@@ -371,6 +397,7 @@ export default function EditFilamentScreen(): React.ReactElement {
/>
</View>
</SafeAreaView>
</>
);
}
@@ -421,4 +448,15 @@ const styles = StyleSheet.create({
resultDot: { width: 8, height: 8, borderRadius: radius.full },
resultPct: { fontFamily: typography.fontFamily.ui, fontSize: typography.fontSize.sm, fontWeight: typography.fontWeight.bold, color: colors.accent },
footer: { padding: spacing[5], borderTopWidth: 1, borderTopColor: colors.border, backgroundColor: colors.bgBase },
// Modal styles
modalOverlay: { flex: 1, backgroundColor: 'rgba(0, 0, 0, 0.5)', justifyContent: 'center', alignItems: 'center' },
modalContent: { width: '85%', maxWidth: 320 },
modalCard: { backgroundColor: colors.bgSurface, borderRadius: radius.lg, padding: spacing[5], gap: spacing[4] },
modalTitle: { fontFamily: typography.fontFamily.ui, fontSize: typography.fontSize.base, fontWeight: typography.fontWeight.semibold, color: colors.textPrimary },
modalInput: { backgroundColor: colors.bgBase, borderWidth: 1, borderColor: colors.border, borderRadius: radius.md, paddingHorizontal: spacing[3], paddingVertical: spacing[2], fontFamily: typography.fontFamily.mono, fontSize: typography.fontSize.base, color: colors.textPrimary },
modalButtons: { flexDirection: 'row', gap: spacing[3] },
modalBtnCancel: { flex: 1, backgroundColor: colors.bgHover, paddingVertical: spacing[3], borderRadius: radius.md, alignItems: 'center' },
modalBtnTextCancel: { fontFamily: typography.fontFamily.ui, fontSize: typography.fontSize.sm, fontWeight: typography.fontWeight.semibold, color: colors.textPrimary },
modalBtnConfirm: { flex: 1, backgroundColor: colors.accent, paddingVertical: spacing[3], borderRadius: radius.md, alignItems: 'center' },
modalBtnTextConfirm: { fontFamily: typography.fontFamily.ui, fontSize: typography.fontSize.sm, fontWeight: typography.fontWeight.semibold, color: colors.bgBase },
});