feat:替换组件库为react-native-elements
This commit is contained in:
parent
a4372a12fc
commit
9481c802f1
@ -4,8 +4,11 @@
|
|||||||
"Bash(npm install:*)",
|
"Bash(npm install:*)",
|
||||||
"Bash(mkdir -p:*)",
|
"Bash(mkdir -p:*)",
|
||||||
"Bash(npm install:*)",
|
"Bash(npm install:*)",
|
||||||
"Bash(*:*)"
|
"Bash(*:*)",
|
||||||
|
"Bash(npm uninstall react-native-paper react-native-paper-dropdown)",
|
||||||
|
"Bash(npm uninstall react-native-paper react-native-paper-dropdown --legacy-peer-deps)",
|
||||||
|
"Bash(npx react-native start --reset-cache)"
|
||||||
],
|
],
|
||||||
"deny": []
|
"deny": []
|
||||||
}
|
}
|
||||||
}
|
}
|
6
App.tsx
6
App.tsx
@ -3,16 +3,16 @@ import { NavigationContainer } from '@react-navigation/native';
|
|||||||
import AppNavigator from './src/navigation/AppNavigator';
|
import AppNavigator from './src/navigation/AppNavigator';
|
||||||
|
|
||||||
import { TasksProvider } from './src/context/TasksContext';
|
import { TasksProvider } from './src/context/TasksContext';
|
||||||
import { PaperProvider } from 'react-native-paper';
|
import { ThemeProvider } from '@rneui/themed';
|
||||||
|
|
||||||
export default function App() {
|
export default function App() {
|
||||||
return (
|
return (
|
||||||
<PaperProvider>
|
<ThemeProvider>
|
||||||
<TasksProvider>
|
<TasksProvider>
|
||||||
<NavigationContainer>
|
<NavigationContainer>
|
||||||
<AppNavigator />
|
<AppNavigator />
|
||||||
</NavigationContainer>
|
</NavigationContainer>
|
||||||
</TasksProvider>
|
</TasksProvider>
|
||||||
</PaperProvider>
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
513
package-lock.json
generated
513
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -14,12 +14,12 @@
|
|||||||
"@react-navigation/bottom-tabs": "^7.4.2",
|
"@react-navigation/bottom-tabs": "^7.4.2",
|
||||||
"@react-navigation/native": "^7.1.14",
|
"@react-navigation/native": "^7.1.14",
|
||||||
"@react-navigation/stack": "^7.4.2",
|
"@react-navigation/stack": "^7.4.2",
|
||||||
|
"@rneui/base": "^4.0.0-rc.8",
|
||||||
|
"@rneui/themed": "^4.0.0-rc.8",
|
||||||
"react": "19.1.0",
|
"react": "19.1.0",
|
||||||
"react-native": "0.80.1",
|
"react-native": "0.80.1",
|
||||||
"react-native-gesture-handler": "^2.27.1",
|
"react-native-gesture-handler": "^2.27.1",
|
||||||
"react-native-get-random-values": "^1.11.0",
|
"react-native-get-random-values": "^1.11.0",
|
||||||
"react-native-paper": "^5.14.5",
|
|
||||||
"react-native-paper-dropdown": "^2.3.1",
|
|
||||||
"react-native-safe-area-context": "^5.5.2",
|
"react-native-safe-area-context": "^5.5.2",
|
||||||
"react-native-screens": "^4.13.1",
|
"react-native-screens": "^4.13.1",
|
||||||
"react-native-vector-icons": "^10.2.0",
|
"react-native-vector-icons": "^10.2.0",
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Appbar, useTheme } from 'react-native-paper';
|
import { View, StyleSheet } from 'react-native';
|
||||||
import { StyleSheet } from 'react-native';
|
import { Button, useTheme } from '@rneui/themed';
|
||||||
|
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||||
|
|
||||||
interface BottomActionBarProps {
|
interface BottomActionBarProps {
|
||||||
onRun: () => void;
|
onRun: () => void;
|
||||||
@ -19,16 +20,16 @@ const BottomActionBar: React.FC<BottomActionBarProps> = ({
|
|||||||
onBack,
|
onBack,
|
||||||
isSaveDisabled = true,
|
isSaveDisabled = true,
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme();
|
const { theme } = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Appbar style={[styles.bottom, { backgroundColor: theme.colors.elevation.level2 }]}>
|
<View style={[styles.bottom, { backgroundColor: theme.colors.background }]}>
|
||||||
<Appbar.Action icon="arrow-left" onPress={onBack} />
|
<Button type="clear" onPress={onBack} icon={<Icon name="arrow-left" size={24} color={theme.colors.primary} />} />
|
||||||
<Appbar.Action icon="play" onPress={onRun} />
|
<Button type="clear" onPress={onRun} icon={<Icon name="play" size={24} color={theme.colors.primary} />} />
|
||||||
<Appbar.Action icon="content-save" onPress={onSave} disabled={isSaveDisabled} />
|
<Button type="clear" onPress={onSave} disabled={isSaveDisabled} icon={<Icon name="content-save" size={24} color={isSaveDisabled ? theme.colors.disabled : theme.colors.primary} />} />
|
||||||
<Appbar.Action icon="undo" onPress={onUndo} />
|
<Button type="clear" onPress={onUndo} icon={<Icon name="undo" size={24} color={theme.colors.primary} />} />
|
||||||
<Appbar.Action icon="restore" onPress={onRestore} />
|
<Button type="clear" onPress={onRestore} icon={<Icon name="restore" size={24} color={theme.colors.primary} />} />
|
||||||
</Appbar>
|
</View>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -38,7 +39,11 @@ const styles = StyleSheet.create({
|
|||||||
left: 0,
|
left: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
|
flexDirection: 'row',
|
||||||
justifyContent: 'space-around',
|
justifyContent: 'space-around',
|
||||||
|
paddingVertical: 8,
|
||||||
|
borderTopWidth: 1,
|
||||||
|
borderTopColor: '#e0e0e0',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { StyleSheet } from 'react-native';
|
import { StyleSheet, TouchableOpacity } from 'react-native';
|
||||||
import { Card, Text, Chip, useTheme } from 'react-native-paper';
|
import { Card, Text, Chip, useTheme } from '@rneui/themed';
|
||||||
import { Task, TaskStatus } from '../types/task';
|
import { Task, TaskStatus } from '../types/task';
|
||||||
|
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||||
|
|
||||||
interface TaskCardProps {
|
interface TaskCardProps {
|
||||||
task: Task;
|
task: Task;
|
||||||
@ -16,36 +17,40 @@ const statusColors: Record<TaskStatus, string> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const TaskCard: React.FC<TaskCardProps> = ({ task, onPress }) => {
|
const TaskCard: React.FC<TaskCardProps> = ({ task, onPress }) => {
|
||||||
const theme = useTheme();
|
const { theme } = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card style={styles.card} onPress={() => onPress(task.id)}>
|
<TouchableOpacity onPress={() => onPress(task.id)} style={{ flex: 1, width: '50%' }}>
|
||||||
<Card.Content>
|
<Card containerStyle={styles.card}>
|
||||||
<Text variant="titleMedium" style={styles.title}>
|
<Card.Title style={styles.title}>{task.name}</Card.Title>
|
||||||
{task.name}
|
<Card.Divider />
|
||||||
</Text>
|
|
||||||
<Chip
|
<Chip
|
||||||
icon="information"
|
title={task.status}
|
||||||
mode="outlined"
|
icon={{
|
||||||
selectedColor={statusColors[task.status]}
|
name: 'information',
|
||||||
style={[styles.chip, { backgroundColor: theme.colors.surface }]}
|
type: 'material-community',
|
||||||
textStyle={{ fontSize: 12 }}
|
size: 20,
|
||||||
>
|
color: statusColors[task.status],
|
||||||
{task.status}
|
}}
|
||||||
</Chip>
|
type="outline"
|
||||||
</Card.Content>
|
containerStyle={styles.chip}
|
||||||
</Card>
|
titleStyle={{ color: statusColors[task.status], fontSize: 12 }}
|
||||||
|
buttonStyle={{ borderColor: statusColors[task.status] }}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
</TouchableOpacity>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
card: {
|
card: {
|
||||||
margin: 8,
|
margin: 4,
|
||||||
width: '45%',
|
borderRadius: 8,
|
||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
marginBottom: 12,
|
marginBottom: 12,
|
||||||
minHeight: 50, // Ensure cards have similar height
|
minHeight: 50, // Ensure cards have similar height
|
||||||
|
textAlign: 'left',
|
||||||
},
|
},
|
||||||
chip: {
|
chip: {
|
||||||
alignSelf: 'flex-start',
|
alignSelf: 'flex-start',
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { View, StyleSheet, ScrollView } from 'react-native';
|
import { View, StyleSheet, ScrollView, TouchableOpacity } from 'react-native';
|
||||||
import { TextInput, Menu, Button, Divider, Text } from 'react-native-paper';
|
import { Input, BottomSheet, ListItem, Text } from '@rneui/themed';
|
||||||
import { Task, RobotAction } from '../types/task';
|
import { Task, RobotAction } from '../types/task';
|
||||||
import { LOCATIONS, ROBOT_ACTIONS, PAYLOADS, LOCATIONS_BAYS } from '../data/mockData';
|
import {
|
||||||
|
LOCATIONS,
|
||||||
|
ROBOT_ACTIONS,
|
||||||
|
PAYLOADS,
|
||||||
|
LOCATIONS_BAYS,
|
||||||
|
} from '../data/mockData';
|
||||||
|
|
||||||
interface TaskFormProps {
|
interface TaskFormProps {
|
||||||
task: Task;
|
task: Task;
|
||||||
@ -10,91 +15,117 @@ interface TaskFormProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const TaskForm: React.FC<TaskFormProps> = ({ task, onTaskChange }) => {
|
const TaskForm: React.FC<TaskFormProps> = ({ task, onTaskChange }) => {
|
||||||
const [menuVisible, setMenuVisible] = useState<{ [key: string]: boolean }>({});
|
const [isVisible, setIsVisible] = useState(false);
|
||||||
|
const [currentField, setCurrentField] = useState('');
|
||||||
|
const [currentItems, setCurrentItems] = useState<
|
||||||
|
{ label: string; value: string }[]
|
||||||
|
>([]);
|
||||||
|
|
||||||
const openMenu = (name: string) => setMenuVisible(prev => ({ ...prev, [name]: true }));
|
const handleParamChange = (field: string, value: string | RobotAction) => {
|
||||||
const closeMenu = (name: string) => setMenuVisible(prev => ({ ...prev, [name]: false }));
|
const updatedTask = {
|
||||||
|
...task,
|
||||||
const handleParamChange = (field: string, value: string | RobotAction) => {
|
parameters: {
|
||||||
const updatedTask = {
|
...task.parameters,
|
||||||
...task,
|
[field]: value,
|
||||||
parameters: {
|
},
|
||||||
...task.parameters,
|
|
||||||
[field]: value,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
onTaskChange(updatedTask);
|
|
||||||
};
|
};
|
||||||
|
onTaskChange(updatedTask);
|
||||||
|
};
|
||||||
|
|
||||||
const renderDropdown = (
|
const openBottomSheet = (
|
||||||
name: string,
|
field: string,
|
||||||
label: string,
|
items: { label: string; value: string }[],
|
||||||
value: string,
|
) => {
|
||||||
items: { label: string, value: string }[]
|
setCurrentField(field);
|
||||||
) => (
|
setCurrentItems(items);
|
||||||
<View style={styles.input}>
|
setIsVisible(true);
|
||||||
<Text>{label}</Text>
|
};
|
||||||
<Menu
|
|
||||||
visible={menuVisible[name]}
|
const renderDropdown = (
|
||||||
onDismiss={() => closeMenu(name)}
|
name: string,
|
||||||
anchor={
|
label: string,
|
||||||
<Button onPress={() => openMenu(name)} mode="outlined">
|
value: string,
|
||||||
{value || `选择${label}`}
|
items: { label: string; value: string }[],
|
||||||
</Button>
|
) => (
|
||||||
}
|
<TouchableOpacity onPress={() => openBottomSheet(name, items)}>
|
||||||
|
<Input
|
||||||
|
label={label}
|
||||||
|
value={value}
|
||||||
|
editable={false}
|
||||||
|
rightIcon={{ name: 'arrow-drop-down' }}
|
||||||
|
/>
|
||||||
|
</TouchableOpacity>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ScrollView contentContainerStyle={styles.container}>
|
||||||
|
<Input
|
||||||
|
label="任务名称"
|
||||||
|
value={task.name}
|
||||||
|
onChangeText={text => onTaskChange({ ...task, name: text })}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{renderDropdown(
|
||||||
|
'startLocation',
|
||||||
|
'起点',
|
||||||
|
task.parameters.startLocation,
|
||||||
|
LOCATIONS,
|
||||||
|
)}
|
||||||
|
{renderDropdown(
|
||||||
|
'endLocation',
|
||||||
|
'终点',
|
||||||
|
task.parameters.endLocation,
|
||||||
|
LOCATIONS,
|
||||||
|
)}
|
||||||
|
|
||||||
|
<Input
|
||||||
|
label="途经点 (可选)"
|
||||||
|
value={task.parameters.waypoint || ''}
|
||||||
|
onChangeText={text => handleParamChange('waypoint', text)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{renderDropdown(
|
||||||
|
'robotAction',
|
||||||
|
'机器人动作',
|
||||||
|
task.parameters.robotAction,
|
||||||
|
ROBOT_ACTIONS,
|
||||||
|
)}
|
||||||
|
{renderDropdown('payload', '载荷', task.parameters.payload, PAYLOADS)}
|
||||||
|
{renderDropdown(
|
||||||
|
'locationBay',
|
||||||
|
'库位',
|
||||||
|
task.parameters.locationBay,
|
||||||
|
LOCATIONS_BAYS,
|
||||||
|
)}
|
||||||
|
|
||||||
|
<BottomSheet
|
||||||
|
isVisible={isVisible}
|
||||||
|
onBackdropPress={() => setIsVisible(false)}
|
||||||
|
>
|
||||||
|
<ScrollView>
|
||||||
|
{currentItems.map((item, index) => (
|
||||||
|
<ListItem
|
||||||
|
key={index}
|
||||||
|
onPress={() => {
|
||||||
|
handleParamChange(currentField, item.value);
|
||||||
|
setIsVisible(false);
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<ScrollView style={{ maxHeight: 200 }}>
|
<ListItem.Content>
|
||||||
{items.map(item => (
|
<ListItem.Title>{item.label}</ListItem.Title>
|
||||||
<Menu.Item
|
</ListItem.Content>
|
||||||
key={item.value}
|
</ListItem>
|
||||||
onPress={() => {
|
))}
|
||||||
handleParamChange(name, item.value);
|
|
||||||
closeMenu(name);
|
|
||||||
}}
|
|
||||||
title={item.label}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</ScrollView>
|
|
||||||
</Menu>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ScrollView contentContainerStyle={styles.container}>
|
|
||||||
<TextInput
|
|
||||||
label="任务名称"
|
|
||||||
value={task.name}
|
|
||||||
onChangeText={text => onTaskChange({ ...task, name: text })}
|
|
||||||
style={styles.input}
|
|
||||||
mode="outlined"
|
|
||||||
/>
|
|
||||||
|
|
||||||
{renderDropdown('startLocation', '起点', task.parameters.startLocation, LOCATIONS)}
|
|
||||||
{renderDropdown('endLocation', '终点', task.parameters.endLocation, LOCATIONS)}
|
|
||||||
|
|
||||||
<TextInput
|
|
||||||
label="途经点 (可选)"
|
|
||||||
value={task.parameters.waypoint || ''}
|
|
||||||
onChangeText={text => handleParamChange('waypoint', text)}
|
|
||||||
style={styles.input}
|
|
||||||
mode="outlined"
|
|
||||||
/>
|
|
||||||
|
|
||||||
{renderDropdown('robotAction', '机器人动作', task.parameters.robotAction, ROBOT_ACTIONS)}
|
|
||||||
{renderDropdown('payload', '载荷', task.parameters.payload, PAYLOADS)}
|
|
||||||
{renderDropdown('locationBay', '库位', task.parameters.locationBay, LOCATIONS_BAYS)}
|
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
);
|
</BottomSheet>
|
||||||
|
</ScrollView>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
container: {
|
container: {
|
||||||
padding: 16,
|
padding: 16,
|
||||||
},
|
},
|
||||||
input: {
|
|
||||||
marginBottom: 16,
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export default TaskForm;
|
export default TaskForm;
|
||||||
|
@ -6,7 +6,7 @@ import { useTasks } from '../context/TasksContext';
|
|||||||
import TaskForm from '../components/TaskForm';
|
import TaskForm from '../components/TaskForm';
|
||||||
import BottomActionBar from '../components/BottomActionBar';
|
import BottomActionBar from '../components/BottomActionBar';
|
||||||
import { Task } from '../types/task';
|
import { Task } from '../types/task';
|
||||||
import { ActivityIndicator } from 'react-native-paper';
|
import { Dialog } from '@rneui/themed';
|
||||||
|
|
||||||
type RootStackParamList = {
|
type RootStackParamList = {
|
||||||
TaskEdit: { taskId: string };
|
TaskEdit: { taskId: string };
|
||||||
@ -67,7 +67,11 @@ export default function TaskEditScreen() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!task) {
|
if (!task) {
|
||||||
return <ActivityIndicator animating={true} size="large" style={styles.loader}/>;
|
return (
|
||||||
|
<Dialog isVisible={true}>
|
||||||
|
<Dialog.Loading />
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -89,10 +93,6 @@ const styles = StyleSheet.create({
|
|||||||
container: {
|
container: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
backgroundColor: '#fff',
|
backgroundColor: '#fff',
|
||||||
|
paddingBottom: 60,
|
||||||
},
|
},
|
||||||
loader: {
|
|
||||||
flex: 1,
|
|
||||||
justifyContent: 'center',
|
|
||||||
alignItems: 'center'
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
@ -38,6 +38,5 @@ const styles = StyleSheet.create({
|
|||||||
flex: 1,
|
flex: 1,
|
||||||
},
|
},
|
||||||
list: {
|
list: {
|
||||||
padding: 8,
|
paddingHorizontal: 8,
|
||||||
}
|
}});
|
||||||
});
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user