feat: 初始提交(仅核心代码,已排除大文件)

This commit is contained in:
yangxiangyuan
2026-07-08 10:29:50 +08:00
commit be7c5842f1
623 changed files with 332897 additions and 0 deletions
+205
View File
@@ -0,0 +1,205 @@
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import {
ActivityIndicator,
Alert,
StatusBar,
StyleSheet,
Text,
TouchableOpacity,
View,
} from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { Ionicons } from '@expo/vector-icons';
import { orderBoxApi } from './api';
import { theme } from './theme';
import { OrderBoxState } from './types';
import { CardsScreen, HistoryScreen } from './kits/motion_reminder';
const Tab = createBottomTabNavigator();
type ScreenMode = 'hub' | 'motion_reminder';
const HubScreen = ({
onEnterMotionReminder,
loading,
}: {
onEnterMotionReminder: () => void;
loading: boolean;
}) => (
<View style={styles.hubContainer}>
<StatusBar barStyle="light-content" backgroundColor={theme.colors.background} />
<View style={styles.hubHeader}>
<Text style={styles.hubTitle}>框子</Text>
<Text style={styles.hubSubtitle}>kit 聚合壳。当前阶段先落地第一个工具:运动提醒宝。</Text>
</View>
<TouchableOpacity style={styles.kitCard} disabled={loading} onPress={onEnterMotionReminder}>
<View style={styles.kitCardIcon}>
<Ionicons name="barbell-outline" size={28} color={theme.colors.primary} />
</View>
<View style={styles.kitCardBody}>
<Text style={styles.kitCardTitle}>运动提醒宝</Text>
<Text style={styles.kitCardText}>流程卡片、自动切步、语音播报、大字倒计时、下一个动作常驻显示。</Text>
</View>
<Ionicons name="chevron-forward" size={24} color={theme.colors.textSecondary} />
</TouchableOpacity>
</View>
);
function MotionReminderKit({ onExit }: { onExit: () => void }) {
const [serverState, setServerState] = useState<OrderBoxState | null>(null);
const [loading, setLoading] = useState(true);
const refreshData = useCallback(async () => {
try {
const nextState = await orderBoxApi.getState();
setServerState(nextState);
} catch (error) {
const message = error instanceof Error ? error.message : '加载失败';
Alert.alert('加载失败', message);
} finally {
setLoading(false);
}
}, []);
useEffect(() => {
void refreshData();
}, [refreshData]);
return (
<NavigationContainer independent>
<Tab.Navigator
screenOptions={{
headerStyle: { backgroundColor: theme.colors.background },
headerTintColor: theme.colors.text,
tabBarStyle: { backgroundColor: theme.colors.surface, borderTopColor: theme.colors.border },
tabBarActiveTintColor: theme.colors.primary,
tabBarInactiveTintColor: theme.colors.textSecondary,
}}
>
<Tab.Screen
name="Cards"
children={() => <CardsScreen onExit={onExit} serverState={serverState} onRefresh={refreshData} />}
options={{
title: '运动提醒宝',
tabBarLabel: '卡片',
tabBarIcon: ({ color, size }) => <Ionicons name="albums-outline" size={size} color={color} />,
}}
/>
<Tab.Screen
name="History"
children={() => <HistoryScreen onRefresh={refreshData} />}
options={{
title: '执行历史',
tabBarLabel: '历史',
tabBarIcon: ({ color, size }) => <Ionicons name="time-outline" size={size} color={color} />,
}}
/>
</Tab.Navigator>
</NavigationContainer>
);
}
export default function App() {
const [screenMode, setScreenMode] = useState<ScreenMode>('hub');
const [loading, setLoading] = useState(true);
const initialize = useCallback(async () => {
try {
await orderBoxApi.getMeta();
const state = await orderBoxApi.getState();
if (state.activeKit === 'motion_reminder') {
setScreenMode('motion_reminder');
}
} catch (error) {
const message = error instanceof Error ? error.message : '初始化失败';
Alert.alert('初始化失败', message);
} finally {
setLoading(false);
}
}, []);
useEffect(() => {
void initialize();
}, [initialize]);
const enterMotionReminder = async () => {
try {
setLoading(true);
await orderBoxApi.setActiveKit('motion_reminder');
setScreenMode('motion_reminder');
} catch (error) {
const message = error instanceof Error ? error.message : '进入失败';
Alert.alert('进入失败', message);
} finally {
setLoading(false);
}
};
const content = useMemo(() => {
if (screenMode === 'motion_reminder') {
return <MotionReminderKit onExit={() => setScreenMode('hub')} />;
}
return <HubScreen loading={loading} onEnterMotionReminder={() => void enterMotionReminder()} />;
}, [loading, screenMode]);
return <View style={styles.appContainer}>{content}</View>;
}
const styles = StyleSheet.create({
appContainer: {
flex: 1,
backgroundColor: theme.colors.background,
},
hubContainer: {
flex: 1,
backgroundColor: theme.colors.background,
padding: theme.spacing.lg,
paddingTop: 72,
},
hubHeader: {
marginBottom: theme.spacing.xl,
},
hubTitle: {
...theme.typography.h1,
color: theme.colors.text,
marginBottom: theme.spacing.sm,
},
hubSubtitle: {
...theme.typography.body,
color: theme.colors.textSecondary,
lineHeight: 24,
},
kitCard: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: theme.colors.surface,
borderRadius: theme.borderRadius.xl,
padding: theme.spacing.lg,
borderWidth: 1,
borderColor: theme.colors.border,
gap: theme.spacing.md,
},
kitCardIcon: {
width: 56,
height: 56,
borderRadius: 28,
backgroundColor: theme.colors.primarySoft,
justifyContent: 'center',
alignItems: 'center',
},
kitCardBody: {
flex: 1,
},
kitCardTitle: {
...theme.typography.h3,
color: theme.colors.text,
marginBottom: theme.spacing.xs,
},
kitCardText: {
...theme.typography.bodySmall,
color: theme.colors.textSecondary,
lineHeight: 20,
},
});