fixxed big ui cavia
Build APK / build (push) Canceled after 0s

This commit is contained in:
2026-08-07 01:06:03 +02:00
parent 3d594670b0
commit ecb7fbefb1
71 changed files with 3989 additions and 1204 deletions
@@ -1,5 +1,5 @@
import React from 'react';
import { View, Text, StyleSheet, TouchableOpacity, ScrollView } from 'react-native';
import React, { useState } from 'react';
import { View, Text, StyleSheet, TouchableOpacity, ScrollView, Modal, Pressable, KeyboardAvoidingView } from 'react-native';
import { useCategories } from '@/hooks/useDatabase';
import { useSettings } from '@/theme';
@@ -12,82 +12,109 @@ interface CategorySelectorProps {
export function CategorySelector({ value, onChange, error }: CategorySelectorProps) {
const categories = useCategories();
const { theme } = useSettings();
const [showModal, setShowModal] = useState(false);
const selectedCategory = categories.find(c => c.id === value);
return (
<View style={styles.container}>
<Text style={[styles.label, { color: theme.text }]}>Category</Text>
<View style={styles.requiredIndicator} />
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={styles.scrollContent}
style={styles.scrollView}
<TouchableOpacity
style={[
styles.selectorButton,
{ backgroundColor: theme.inputBg, borderColor: theme.borderStrong },
]}
onPress={() => setShowModal(true)}
activeOpacity={0.8}
>
{categories.map((category) => (
<TouchableOpacity
key={category.id}
style={[
styles.categoryButton,
{ backgroundColor: theme.card, borderColor: theme.borderStrong },
value === category.id && { borderColor: theme.accent, backgroundColor: theme.accentSoft, borderWidth: 2 },
]}
onPress={() => onChange(category.id)}
activeOpacity={0.8}
>
<View
style={[
styles.colorCircle,
{ backgroundColor: category.color },
value === category.id && styles.colorCircleSelected,
]}
/>
<Text style={[
styles.categoryName,
{ color: theme.textSecondary },
value === category.id && { color: theme.accent, fontWeight: '600' },
]}>
{category.name}
</Text>
</TouchableOpacity>
))}
</ScrollView>
{error && <Text style={styles.errorText}>{error}</Text>}
<View style={styles.selectorContent}>
<View style={styles.selectorRow}>
<View style={[styles.colorCircle, { backgroundColor: selectedCategory?.color || '#9E9E9E' }]} />
<Text style={[styles.selectorValue, { color: theme.text }]}>{selectedCategory?.name || 'Select category'}</Text>
</View>
</View>
<Svg width={20} height={20} viewBox="0 0 24 24">
<Path d="M9 18l6-6-6-6" stroke={theme.textMuted} strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" fill="none" />
</Svg>
</TouchableOpacity>
{error && <Text style={[styles.errorText, { color: '#E53935' }]}>{error}</Text>}
<Modal visible={showModal} transparent animationType="fade" onRequestClose={() => setShowModal(false)}>
<KeyboardAvoidingView
style={[styles.modalOverlay, { backgroundColor: 'rgba(0,0,0,0.5)' }]}
behavior="padding"
>
<Pressable style={styles.modalOverlay} onPress={() => setShowModal(false)}>
<Pressable style={[styles.modalSheet, { backgroundColor: theme.sheetBg }]}>
<View style={styles.modalHeader}>
<Text style={[styles.modalTitle, { color: theme.text }]}>Select Category</Text>
<TouchableOpacity onPress={() => setShowModal(false)} hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}>
<Text style={[styles.closeText, { color: theme.textMuted }]}>✕</Text>
</TouchableOpacity>
</View>
<ScrollView contentContainerStyle={styles.modalContent}>
{categories.map((category) => (
<TouchableOpacity
key={category.id}
style={[
styles.modalOption,
{ backgroundColor: theme.card, borderColor: theme.borderStrong },
value === category.id && { borderColor: theme.accent, backgroundColor: theme.accentSoft, borderWidth: 2 },
]}
onPress={() => { onChange(category.id); setShowModal(false); }}
activeOpacity={0.8}
>
<View style={[styles.colorCircle, { backgroundColor: category.color }, value === category.id && styles.colorCircleSelected]} />
<Text style={[
styles.categoryName,
{ color: theme.textSecondary },
value === category.id && { color: theme.accent, fontWeight: '600' },
]}>
{category.name}
</Text>
{value === category.id && (
<Svg width={20} height={20} viewBox="0 0 24 24">
<Path d="M5 12l5 5 9-10" stroke={theme.accent} strokeWidth={2.5} strokeLinecap="round" strokeLinejoin="round" fill="none" />
</Svg>
)}
</TouchableOpacity>
))}
</ScrollView>
</Pressable>
</Pressable>
</KeyboardAvoidingView>
</Modal>
</View>
);
}
import Svg, { Path } from 'react-native-svg';
const styles = StyleSheet.create({
container: {
gap: 8,
gap: 6,
},
label: {
fontSize: 14,
fontWeight: '600',
},
requiredIndicator: {
position: 'absolute',
top: 0,
right: 0,
color: '#E53935',
fontSize: 14,
},
scrollView: {
paddingVertical: 4,
},
scrollContent: {
paddingHorizontal: 16,
gap: 10,
},
categoryButton: {
paddingHorizontal: 16,
paddingVertical: 10,
borderRadius: 24,
borderWidth: 1,
selectorButton: {
flexDirection: 'row',
alignItems: 'center',
gap: 8,
minWidth: 90,
justifyContent: 'center',
justifyContent: 'space-between',
paddingVertical: 14,
paddingHorizontal: 12,
borderRadius: 12,
borderWidth: 1,
minHeight: 52,
},
selectorContent: {
flex: 1,
},
selectorRow: {
flexDirection: 'row',
alignItems: 'center',
gap: 10,
},
colorCircle: {
width: 12,
@@ -99,13 +126,59 @@ const styles = StyleSheet.create({
height: 14,
borderRadius: 7,
},
categoryName: {
fontSize: 13,
selectorValue: {
fontSize: 15,
fontWeight: '500',
},
errorText: {
fontSize: 12,
color: '#E53935',
marginLeft: 16,
marginLeft: 4,
},
modalOverlay: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
padding: 24,
},
modalSheet: {
width: '100%',
maxWidth: 400,
borderRadius: 20,
overflow: 'hidden',
maxHeight: '80%',
},
modalHeader: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
padding: 20,
borderBottomWidth: 1,
},
modalTitle: {
fontSize: 18,
fontWeight: '700',
},
closeText: {
fontSize: 22,
fontWeight: '300',
},
modalContent: {
padding: 12,
gap: 8,
},
modalOption: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
gap: 12,
paddingVertical: 14,
paddingHorizontal: 16,
borderRadius: 12,
borderWidth: 1,
},
categoryName: {
fontSize: 15,
fontWeight: '500',
flex: 1,
},
});