Compare commits
5 Commits
10a3408ff6
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 54bf84b19b | |||
| 9ef9233797 | |||
| b48cce06f4 | |||
| 230191f181 | |||
| 0f1f775605 |
30
README.md
@@ -301,17 +301,17 @@ rn-demo/
|
|||||||
|
|
||||||
项目已安装并配置好以下工具库:
|
项目已安装并配置好以下工具库:
|
||||||
|
|
||||||
| 类别 | 工具库 | 用途 | 状态 |
|
| 类别 | 工具库 | 用途 | 状态 |
|
||||||
| ------------ | ----------------------------------------- | ------------------- | ---- |
|
| ------------ | ----------------------------------------- | -------------------- | ---- |
|
||||||
| **工具类** | lodash-es | JavaScript 工具函数 | ✅ |
|
| **工具类** | lodash-es | JavaScript 工具函数 | ✅ |
|
||||||
| | dayjs | 日期处理 | ✅ |
|
| | dayjs | 日期处理 | ✅ |
|
||||||
| | axios | HTTP 请求 | ✅ |
|
| | axios | HTTP 请求 | ✅ |
|
||||||
| **状态管理** | zustand | 轻量级状态管理 | ✅ |
|
| **状态管理** | zustand | 轻量级状态管理 | ✅ |
|
||||||
| **表单处理** | react-hook-form | 表单管理 | ✅ |
|
| **表单处理** | react-hook-form | 表单管理 | ✅ |
|
||||||
| | zod | 数据验证 | ✅ |
|
| | zod | 数据验证 | ✅ |
|
||||||
| **原生功能** | @react-native-async-storage/async-storage | 本地存储 | ✅ |
|
| **原生功能** | @react-native-async-storage/async-storage | 本地存储 | ✅ |
|
||||||
| | expo-image | 优化的图片组件 | ✅ |
|
| | expo-image | 优化的图片组件 | ✅ |
|
||||||
| | expo-haptics | 触觉反馈 | ✅ |
|
| | expo-haptics | 触觉反馈 | ✅ |
|
||||||
| **UI 组件** | react-native-paper | Material Design 组件 | ✅ |
|
| **UI 组件** | react-native-paper | Material Design 组件 | ✅ |
|
||||||
|
|
||||||
### 快速开始
|
### 快速开始
|
||||||
@@ -325,7 +325,13 @@ rn-demo/
|
|||||||
import { Storage, SessionStorage, StorageManager, formatDate } from '@/utils';
|
import { Storage, SessionStorage, StorageManager, formatDate } from '@/utils';
|
||||||
import { useUser, useTheme, useLanguage } from '@/stores';
|
import { useUser, useTheme, useLanguage } from '@/stores';
|
||||||
import { authService, userService } from '@/services';
|
import { authService, userService } from '@/services';
|
||||||
import { useDebounce, useHaptics, useColorScheme, useThemeColors, useClientOnlyValue } from '@/hooks';
|
import {
|
||||||
|
useDebounce,
|
||||||
|
useHaptics,
|
||||||
|
useColorScheme,
|
||||||
|
useThemeColors,
|
||||||
|
useClientOnlyValue,
|
||||||
|
} from '@/hooks';
|
||||||
import { loginSchema } from '@/schemas';
|
import { loginSchema } from '@/schemas';
|
||||||
|
|
||||||
// ✅ 主题系统:统一从 theme 目录导入 🎯 NEW!
|
// ✅ 主题系统:统一从 theme 目录导入 🎯 NEW!
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import FontAwesome from '@expo/vector-icons/FontAwesome';
|
|||||||
import { Link, Tabs } from 'expo-router';
|
import { Link, Tabs } from 'expo-router';
|
||||||
import { Pressable } from 'react-native';
|
import { Pressable } from 'react-native';
|
||||||
|
|
||||||
import Colors from '@/constants/Colors';
|
import { Colors } from '@/theme';
|
||||||
import { useColorScheme, useClientOnlyValue } from '@/hooks';
|
import { useColorScheme, useClientOnlyValue } from '@/hooks';
|
||||||
|
|
||||||
// You can explore the built-in icon families and icons on the web at https://icons.expo.fyi/
|
// You can explore the built-in icon families and icons on the web at https://icons.expo.fyi/
|
||||||
@@ -29,42 +29,28 @@ export default function TabLayout() {
|
|||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="index"
|
name="index"
|
||||||
options={{
|
options={{
|
||||||
title: 'Tab One',
|
title: '首页',
|
||||||
tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
|
tabBarIcon: ({ color }) => <TabBarIcon name="home" color={color} />,
|
||||||
headerRight: () => (
|
|
||||||
<Link href="/modal" asChild>
|
|
||||||
<Pressable>
|
|
||||||
{({ pressed }) => (
|
|
||||||
<FontAwesome
|
|
||||||
name="info-circle"
|
|
||||||
size={25}
|
|
||||||
color={Colors[colorScheme ?? 'light'].text}
|
|
||||||
style={{ marginRight: 15, opacity: pressed ? 0.5 : 1 }}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</Pressable>
|
|
||||||
</Link>
|
|
||||||
),
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="two"
|
name="two"
|
||||||
options={{
|
options={{
|
||||||
title: 'Tab Two',
|
title: '充值',
|
||||||
tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
|
tabBarIcon: ({ color }) => <TabBarIcon name="code" color={color} />,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="demo"
|
name="demo"
|
||||||
options={{
|
options={{
|
||||||
title: '完整示例',
|
title: '活动',
|
||||||
tabBarIcon: ({ color }) => <TabBarIcon name="rocket" color={color} />,
|
tabBarIcon: ({ color }) => <TabBarIcon name="rocket" color={color} />,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Tabs.Screen
|
<Tabs.Screen
|
||||||
name="paper"
|
name="paper"
|
||||||
options={{
|
options={{
|
||||||
title: 'Paper UI',
|
title: '我的',
|
||||||
tabBarIcon: ({ color }) => <TabBarIcon name="paint-brush" color={color} />,
|
tabBarIcon: ({ color }) => <TabBarIcon name="paint-brush" color={color} />,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -24,13 +24,11 @@ import { useRouter } from 'expo-router';
|
|||||||
|
|
||||||
// 工具函数
|
// 工具函数
|
||||||
import {
|
import {
|
||||||
Storage,
|
storageManager,
|
||||||
STORAGE_KEYS,
|
STORAGE_KEYS,
|
||||||
SessionStorage,
|
|
||||||
SESSION_KEYS,
|
|
||||||
formatDate,
|
formatDate,
|
||||||
formatRelativeTime,
|
formatRelativeTime,
|
||||||
formatChatTime
|
formatChatTime,
|
||||||
} from '@/utils';
|
} from '@/utils';
|
||||||
|
|
||||||
// 状态管理
|
// 状态管理
|
||||||
@@ -42,18 +40,13 @@ import {
|
|||||||
useTheme,
|
useTheme,
|
||||||
useLanguage,
|
useLanguage,
|
||||||
useHapticsEnabled,
|
useHapticsEnabled,
|
||||||
useSettingsActions,
|
|
||||||
useTenantStates,
|
|
||||||
useTenantInfo,
|
|
||||||
} from '@/stores';
|
} from '@/stores';
|
||||||
|
import { useTenantLoad, useTenantInfo } from '@/stores/tenantStore';
|
||||||
|
|
||||||
// 验证规则
|
// 验证规则
|
||||||
import { loginSchema } from '@/schemas';
|
import { loginSchema } from '@/schemas';
|
||||||
import type { LoginFormData } from '@/schemas';
|
import type { LoginFormData } from '@/schemas';
|
||||||
|
|
||||||
// API 服务
|
|
||||||
import { authService } from '@/services';
|
|
||||||
|
|
||||||
// 自定义 Hooks
|
// 自定义 Hooks
|
||||||
import { useDebounce, useThrottle, useHaptics } from '@/hooks';
|
import { useDebounce, useThrottle, useHaptics } from '@/hooks';
|
||||||
|
|
||||||
@@ -71,14 +64,14 @@ export default function DemoScreen() {
|
|||||||
const login = useUserStore((state) => state.login);
|
const login = useUserStore((state) => state.login);
|
||||||
const logout = useUserStore((state) => state.logout);
|
const logout = useUserStore((state) => state.logout);
|
||||||
|
|
||||||
const { tenantLoad } = useTenantStates();
|
const tenantLoad = useTenantLoad();
|
||||||
const tenantInfo = useTenantInfo();
|
const tenantInfo = useTenantInfo();
|
||||||
|
|
||||||
// 设置状态
|
// 设置状态
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const language = useLanguage();
|
const language = useLanguage();
|
||||||
const hapticsEnabled = useHapticsEnabled();
|
const hapticsEnabled = useHapticsEnabled();
|
||||||
const { setTheme, setLanguage, setHapticsEnabled } = useSettingsActions();
|
const { setTheme, setLanguage, setHapticsEnabled } = useSettingsStore();
|
||||||
// const setTheme = useSettingsStore((state) => state.setTheme);
|
// const setTheme = useSettingsStore((state) => state.setTheme);
|
||||||
// const setLanguage = useSettingsStore((state) => state.setLanguage);
|
// const setLanguage = useSettingsStore((state) => state.setLanguage);
|
||||||
// const setHapticsEnabled = useSettingsStore((state) => state.setHapticsEnabled);
|
// const setHapticsEnabled = useSettingsStore((state) => state.setHapticsEnabled);
|
||||||
@@ -189,7 +182,7 @@ export default function DemoScreen() {
|
|||||||
counter,
|
counter,
|
||||||
};
|
};
|
||||||
|
|
||||||
await Storage.setObject(STORAGE_KEYS.USER_PREFERENCES, testData);
|
storageManager.session.setItem(STORAGE_KEYS.USER_PREFERENCES, testData);
|
||||||
haptics.success();
|
haptics.success();
|
||||||
Alert.alert('成功', '数据已保存到本地存储');
|
Alert.alert('成功', '数据已保存到本地存储');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -201,7 +194,7 @@ export default function DemoScreen() {
|
|||||||
const handleLoadFromStorage = async () => {
|
const handleLoadFromStorage = async () => {
|
||||||
try {
|
try {
|
||||||
haptics.light();
|
haptics.light();
|
||||||
const data = await Storage.getObject<any>(STORAGE_KEYS.USER_PREFERENCES);
|
const data = storageManager.session.getItem(STORAGE_KEYS.USER_PREFERENCES);
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
setStorageValue(JSON.stringify(data, null, 2));
|
setStorageValue(JSON.stringify(data, null, 2));
|
||||||
@@ -229,7 +222,7 @@ export default function DemoScreen() {
|
|||||||
counter: Math.floor(Math.random() * 100),
|
counter: Math.floor(Math.random() * 100),
|
||||||
};
|
};
|
||||||
|
|
||||||
SessionStorage.setObject(SESSION_KEYS.FORM_DRAFT, testData);
|
storageManager.session.setItem(STORAGE_KEYS.FORM_DRAFT, testData);
|
||||||
haptics.success();
|
haptics.success();
|
||||||
Alert.alert('成功', '数据已保存到会话存储(应用重启后会丢失)');
|
Alert.alert('成功', '数据已保存到会话存储(应用重启后会丢失)');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -241,7 +234,7 @@ export default function DemoScreen() {
|
|||||||
const handleLoadFromSession = () => {
|
const handleLoadFromSession = () => {
|
||||||
try {
|
try {
|
||||||
haptics.light();
|
haptics.light();
|
||||||
const data = SessionStorage.getObject<any>(SESSION_KEYS.FORM_DRAFT);
|
const data = storageManager.session.getItem(STORAGE_KEYS.FORM_DRAFT);
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
setSessionValue(JSON.stringify(data, null, 2));
|
setSessionValue(JSON.stringify(data, null, 2));
|
||||||
@@ -259,7 +252,7 @@ export default function DemoScreen() {
|
|||||||
const handleClearSession = () => {
|
const handleClearSession = () => {
|
||||||
try {
|
try {
|
||||||
haptics.light();
|
haptics.light();
|
||||||
SessionStorage.clear();
|
storageManager.session.clear();
|
||||||
setSessionValue('');
|
setSessionValue('');
|
||||||
haptics.success();
|
haptics.success();
|
||||||
Alert.alert('成功', '会话存储已清空');
|
Alert.alert('成功', '会话存储已清空');
|
||||||
@@ -273,7 +266,7 @@ export default function DemoScreen() {
|
|||||||
const handleThemeChange = () => {
|
const handleThemeChange = () => {
|
||||||
haptics.selection();
|
haptics.selection();
|
||||||
const themes: Array<'light' | 'dark' | 'auto'> = ['light', 'dark', 'auto'];
|
const themes: Array<'light' | 'dark' | 'auto'> = ['light', 'dark', 'auto'];
|
||||||
const currentIndex = themes.indexOf(theme);
|
const currentIndex = themes.indexOf(theme as 'light' | 'dark' | 'auto');
|
||||||
const nextTheme = themes[(currentIndex + 1) % themes.length];
|
const nextTheme = themes[(currentIndex + 1) % themes.length];
|
||||||
setTheme(nextTheme);
|
setTheme(nextTheme);
|
||||||
};
|
};
|
||||||
@@ -303,9 +296,7 @@ export default function DemoScreen() {
|
|||||||
>
|
>
|
||||||
<Text style={styles.buttonText}>跳转到测试页面 →</Text>
|
<Text style={styles.buttonText}>跳转到测试页面 →</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<Text style={styles.infoText}>
|
<Text style={styles.infoText}>测试页面是一个独立的业务页面示例,不包含底部 tabs</Text>
|
||||||
测试页面是一个独立的业务页面示例,不包含底部 tabs
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[styles.button, { backgroundColor: '#9333ea', marginTop: 12 }]}
|
style={[styles.button, { backgroundColor: '#9333ea', marginTop: 12 }]}
|
||||||
@@ -316,9 +307,7 @@ export default function DemoScreen() {
|
|||||||
>
|
>
|
||||||
<Text style={styles.buttonText}>🎨 主题测试页面 →</Text>
|
<Text style={styles.buttonText}>🎨 主题测试页面 →</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<Text style={styles.infoText}>
|
<Text style={styles.infoText}>专门的主题测试页面,可以清楚地看到主题切换效果</Text>
|
||||||
专门的主题测试页面,可以清楚地看到主题切换效果
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[styles.button, { backgroundColor: '#06b6d4', marginTop: 12 }]}
|
style={[styles.button, { backgroundColor: '#06b6d4', marginTop: 12 }]}
|
||||||
@@ -329,26 +318,18 @@ export default function DemoScreen() {
|
|||||||
>
|
>
|
||||||
<Text style={styles.buttonText}>📚 主题系统示例 →</Text>
|
<Text style={styles.buttonText}>📚 主题系统示例 →</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
<Text style={styles.infoText}>
|
<Text style={styles.infoText}>展示四种主题样式使用方式(类似 CSS 类名)</Text>
|
||||||
展示四种主题样式使用方式(类似 CSS 类名)
|
|
||||||
</Text>
|
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
{/* 租户信息显示 */}
|
{/* 租户信息显示 */}
|
||||||
<View style={styles.section}>
|
<View style={styles.section}>
|
||||||
<Text style={styles.sectionTitle}>🏢 租户信息</Text>
|
<Text style={styles.sectionTitle}>🏢 租户信息</Text>
|
||||||
<Text style={styles.infoText}>
|
<Text style={styles.infoText}>状态: {tenantLoad ? '✅ 已加载' : '❌ 未加载'}</Text>
|
||||||
状态: {tenantLoad ? '✅ 已加载' : '❌ 未加载'}
|
|
||||||
</Text>
|
|
||||||
{tenantInfo ? (
|
{tenantInfo ? (
|
||||||
<>
|
<>
|
||||||
<Text style={styles.infoText}>TID: {tenantInfo.tid || '无'}</Text>
|
<Text style={styles.infoText}>TID: {tenantInfo.tid || '无'}</Text>
|
||||||
<Text style={styles.infoText}>
|
<Text style={styles.infoText}>创建时间: {tenantInfo.create_time || '无'}</Text>
|
||||||
创建时间: {tenantInfo.create_time || '无'}
|
<Text style={styles.infoText}>域名: {tenantInfo.domain_addr || '无'}</Text>
|
||||||
</Text>
|
|
||||||
<Text style={styles.infoText}>
|
|
||||||
域名: {tenantInfo.domain_addr || '无'}
|
|
||||||
</Text>
|
|
||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -1,187 +1,23 @@
|
|||||||
import { useState, useEffect } from 'react';
|
/**
|
||||||
import { StyleSheet, TouchableOpacity, Alert, ActivityIndicator } from 'react-native';
|
* 首页 - 游戏大厅
|
||||||
import * as Updates from 'expo-updates';
|
*
|
||||||
|
* 重构自 xinyong-web 项目的首页
|
||||||
|
* 支持浅色/深色主题,包含轮播图、分类菜单、游戏大厅等功能
|
||||||
|
*/
|
||||||
|
|
||||||
import { Text, View } from '@/components/Themed';
|
import { Stack } from 'expo-router';
|
||||||
|
import HomeScreen from '@/pages/HomeScreen';
|
||||||
export default function TabOneScreen() {
|
|
||||||
const [isChecking, setIsChecking] = useState(false);
|
|
||||||
const [updateInfo, setUpdateInfo] = useState<string>('');
|
|
||||||
|
|
||||||
const checkForUpdates = async () => {
|
|
||||||
if (__DEV__) {
|
|
||||||
Alert.alert('提示', '开发模式下无法检查更新,请使用生产构建测试热更新功能');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsChecking(true);
|
|
||||||
setUpdateInfo('正在检查更新...');
|
|
||||||
|
|
||||||
try {
|
|
||||||
const update = await Updates.checkForUpdateAsync();
|
|
||||||
|
|
||||||
if (update.isAvailable) {
|
|
||||||
setUpdateInfo('发现新版本,正在下载...');
|
|
||||||
await Updates.fetchUpdateAsync();
|
|
||||||
|
|
||||||
Alert.alert('更新完成', '新版本已下载完成,是否立即重启应用?', [
|
|
||||||
{
|
|
||||||
text: '稍后',
|
|
||||||
style: 'cancel',
|
|
||||||
onPress: () => setUpdateInfo('更新已下载,稍后重启应用即可应用'),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: '立即重启',
|
|
||||||
onPress: async () => {
|
|
||||||
await Updates.reloadAsync();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
} else {
|
|
||||||
setUpdateInfo('当前已是最新版本');
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
setUpdateInfo('检查更新失败: ' + (error as Error).message);
|
|
||||||
Alert.alert('错误', '检查更新失败,请稍后重试');
|
|
||||||
} finally {
|
|
||||||
setIsChecking(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const getUpdateInfo = () => {
|
|
||||||
const { isEmbeddedLaunch, isEmergencyLaunch, updateId, channel, runtimeVersion } =
|
|
||||||
Updates.useUpdates();
|
|
||||||
|
|
||||||
return `
|
|
||||||
运行模式: ${__DEV__ ? '开发模式' : '生产模式'}
|
|
||||||
是否为内嵌启动: ${isEmbeddedLaunch ? '是' : '否'}
|
|
||||||
是否为紧急启动: ${isEmergencyLaunch ? '是' : '否'}
|
|
||||||
更新 ID: ${updateId || '无'}
|
|
||||||
更新通道: ${channel || '无'}
|
|
||||||
运行时版本: ${runtimeVersion || '无'}
|
|
||||||
`.trim();
|
|
||||||
};
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
console.log('=== TabOneScreen 组件已渲染 ===');
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
|
export default function TabHoneScreen() {
|
||||||
return (
|
return (
|
||||||
<View style={styles.container}>
|
<>
|
||||||
<Text style={styles.title}>🚀 热更新演示</Text>
|
<Stack.Screen
|
||||||
<View style={styles.separator} lightColor="#eee" darkColor="rgba(255,255,255,0.1)" />
|
options={{
|
||||||
|
title: '首页',
|
||||||
<View style={styles.infoContainer}>
|
headerShown: false,
|
||||||
<Text style={styles.infoTitle}>当前版本信息:</Text>
|
}}
|
||||||
<Text style={styles.infoText}>{getUpdateInfo()}</Text>
|
/>
|
||||||
</View>
|
<HomeScreen />
|
||||||
|
</>
|
||||||
<TouchableOpacity
|
|
||||||
style={[styles.button, isChecking && styles.buttonDisabled]}
|
|
||||||
onPress={checkForUpdates}
|
|
||||||
disabled={isChecking}
|
|
||||||
>
|
|
||||||
{isChecking ? (
|
|
||||||
<ActivityIndicator color="#fff" />
|
|
||||||
) : (
|
|
||||||
<Text style={styles.buttonText}>检查更新</Text>
|
|
||||||
)}
|
|
||||||
</TouchableOpacity>
|
|
||||||
|
|
||||||
{updateInfo ? (
|
|
||||||
<View style={styles.updateInfoContainer}>
|
|
||||||
<Text style={styles.updateInfoText}>{updateInfo}</Text>
|
|
||||||
</View>
|
|
||||||
) : null}
|
|
||||||
|
|
||||||
<View style={styles.instructionsContainer}>
|
|
||||||
<Text style={styles.instructionsTitle}>📝 使用说明:</Text>
|
|
||||||
<Text style={styles.instructionsText}>
|
|
||||||
1. 使用 EAS Build 构建生产版本{'\n'}
|
|
||||||
2. 修改代码后运行 eas update 发布更新{'\n'}
|
|
||||||
3. 打开应用点击"检查更新"按钮{'\n'}
|
|
||||||
4. 应用会自动下载并提示重启
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const styles = StyleSheet.create({
|
|
||||||
container: {
|
|
||||||
flex: 1,
|
|
||||||
alignItems: 'center',
|
|
||||||
justifyContent: 'center',
|
|
||||||
padding: 20,
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
fontSize: 28,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
marginBottom: 10,
|
|
||||||
},
|
|
||||||
separator: {
|
|
||||||
marginVertical: 20,
|
|
||||||
height: 1,
|
|
||||||
width: '80%',
|
|
||||||
},
|
|
||||||
infoContainer: {
|
|
||||||
backgroundColor: 'rgba(0, 122, 255, 0.1)',
|
|
||||||
padding: 15,
|
|
||||||
borderRadius: 10,
|
|
||||||
marginBottom: 20,
|
|
||||||
width: '100%',
|
|
||||||
},
|
|
||||||
infoTitle: {
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
marginBottom: 10,
|
|
||||||
},
|
|
||||||
infoText: {
|
|
||||||
fontSize: 12,
|
|
||||||
fontFamily: 'monospace',
|
|
||||||
lineHeight: 18,
|
|
||||||
},
|
|
||||||
button: {
|
|
||||||
backgroundColor: '#007AFF',
|
|
||||||
paddingHorizontal: 30,
|
|
||||||
paddingVertical: 15,
|
|
||||||
borderRadius: 10,
|
|
||||||
marginBottom: 20,
|
|
||||||
minWidth: 200,
|
|
||||||
alignItems: 'center',
|
|
||||||
},
|
|
||||||
buttonDisabled: {
|
|
||||||
backgroundColor: '#999',
|
|
||||||
},
|
|
||||||
buttonText: {
|
|
||||||
color: '#fff',
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
},
|
|
||||||
updateInfoContainer: {
|
|
||||||
backgroundColor: 'rgba(52, 199, 89, 0.1)',
|
|
||||||
padding: 15,
|
|
||||||
borderRadius: 10,
|
|
||||||
marginBottom: 20,
|
|
||||||
width: '100%',
|
|
||||||
},
|
|
||||||
updateInfoText: {
|
|
||||||
fontSize: 14,
|
|
||||||
textAlign: 'center',
|
|
||||||
},
|
|
||||||
instructionsContainer: {
|
|
||||||
backgroundColor: 'rgba(255, 149, 0, 0.1)',
|
|
||||||
padding: 15,
|
|
||||||
borderRadius: 10,
|
|
||||||
width: '100%',
|
|
||||||
},
|
|
||||||
instructionsTitle: {
|
|
||||||
fontSize: 16,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
marginBottom: 10,
|
|
||||||
},
|
|
||||||
instructionsText: {
|
|
||||||
fontSize: 13,
|
|
||||||
lineHeight: 20,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -82,7 +82,11 @@ export default function PaperDemo() {
|
|||||||
🔘 按钮
|
🔘 按钮
|
||||||
</Text>
|
</Text>
|
||||||
<View style={styles.buttonRow}>
|
<View style={styles.buttonRow}>
|
||||||
<Button mode="contained" onPress={() => setSnackbarVisible(true)} style={{ marginRight: 8 }}>
|
<Button
|
||||||
|
mode="contained"
|
||||||
|
onPress={() => setSnackbarVisible(true)}
|
||||||
|
style={{ marginRight: 8 }}
|
||||||
|
>
|
||||||
Contained
|
Contained
|
||||||
</Button>
|
</Button>
|
||||||
<Button mode="outlined" onPress={() => setSnackbarVisible(true)}>
|
<Button mode="outlined" onPress={() => setSnackbarVisible(true)}>
|
||||||
@@ -90,7 +94,11 @@ export default function PaperDemo() {
|
|||||||
</Button>
|
</Button>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.buttonRow}>
|
<View style={styles.buttonRow}>
|
||||||
<Button mode="text" onPress={() => setSnackbarVisible(true)} style={{ marginRight: 8 }}>
|
<Button
|
||||||
|
mode="text"
|
||||||
|
onPress={() => setSnackbarVisible(true)}
|
||||||
|
style={{ marginRight: 8 }}
|
||||||
|
>
|
||||||
Text
|
Text
|
||||||
</Button>
|
</Button>
|
||||||
<Button mode="elevated" onPress={() => setSnackbarVisible(true)} icon="camera">
|
<Button mode="elevated" onPress={() => setSnackbarVisible(true)} icon="camera">
|
||||||
@@ -140,10 +148,21 @@ export default function PaperDemo() {
|
|||||||
<Chip icon="star" onPress={() => {}} style={{ marginRight: 8, marginBottom: 8 }}>
|
<Chip icon="star" onPress={() => {}} style={{ marginRight: 8, marginBottom: 8 }}>
|
||||||
收藏
|
收藏
|
||||||
</Chip>
|
</Chip>
|
||||||
<Chip icon="heart" mode="outlined" onPress={() => {}} style={{ marginRight: 8, marginBottom: 8 }}>
|
<Chip
|
||||||
|
icon="heart"
|
||||||
|
mode="outlined"
|
||||||
|
onPress={() => {}}
|
||||||
|
style={{ marginRight: 8, marginBottom: 8 }}
|
||||||
|
>
|
||||||
喜欢
|
喜欢
|
||||||
</Chip>
|
</Chip>
|
||||||
<Chip icon="close" onPress={() => {}} onClose={() => {}} closeIcon="close-circle" style={{ marginBottom: 8 }}>
|
<Chip
|
||||||
|
icon="close"
|
||||||
|
onPress={() => {}}
|
||||||
|
onClose={() => {}}
|
||||||
|
closeIcon="close-circle"
|
||||||
|
style={{ marginBottom: 8 }}
|
||||||
|
>
|
||||||
可关闭
|
可关闭
|
||||||
</Chip>
|
</Chip>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ import { PaperProvider, MD3DarkTheme, MD3LightTheme } from 'react-native-paper';
|
|||||||
// ✅ 从 hooks 目录导入
|
// ✅ 从 hooks 目录导入
|
||||||
import { useColorScheme } from '@/hooks';
|
import { useColorScheme } from '@/hooks';
|
||||||
// ✅ 从 stores 目录导入
|
// ✅ 从 stores 目录导入
|
||||||
import { restoreUserState, restoreSettingsState, useTenantActions } from '@/stores';
|
import { restoreUserState, restoreSettingsState } from '@/stores';
|
||||||
|
import { requestTenantInfo } from '@/stores/tenantStore';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
// Catch any errors thrown by the Layout component.
|
// Catch any errors thrown by the Layout component.
|
||||||
@@ -32,7 +33,6 @@ export default function RootLayout() {
|
|||||||
SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),
|
SpaceMono: require('../assets/fonts/SpaceMono-Regular.ttf'),
|
||||||
...FontAwesome.font,
|
...FontAwesome.font,
|
||||||
});
|
});
|
||||||
const { requestTenantInfo } = useTenantActions();
|
|
||||||
|
|
||||||
// Expo Router uses Error Boundaries to catch errors in the navigation tree.
|
// Expo Router uses Error Boundaries to catch errors in the navigation tree.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/**
|
/**
|
||||||
* 主题系统使用示例
|
* 主题系统使用示例
|
||||||
*
|
*
|
||||||
* 展示四种不同的主题样式使用方式
|
* 展示四种不同的主题样式使用方式
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -78,9 +78,7 @@ export default function ThemeExampleScreen() {
|
|||||||
<ScrollView style={s.containerPadded}>
|
<ScrollView style={s.containerPadded}>
|
||||||
{/* 自定义样式示例 */}
|
{/* 自定义样式示例 */}
|
||||||
<View style={custom.header}>
|
<View style={custom.header}>
|
||||||
<Text style={custom.headerText}>
|
<Text style={custom.headerText}>主题系统使用示例</Text>
|
||||||
主题系统使用示例
|
|
||||||
</Text>
|
|
||||||
<Text style={[custom.headerText, { fontSize: 14, marginTop: 8 }]}>
|
<Text style={[custom.headerText, { fontSize: 14, marginTop: 8 }]}>
|
||||||
当前主题: {theme} {isDark ? '🌙' : '☀️'}
|
当前主题: {theme} {isDark ? '🌙' : '☀️'}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -88,9 +86,7 @@ export default function ThemeExampleScreen() {
|
|||||||
|
|
||||||
{/* 方式 1: 使用主题组件 */}
|
{/* 方式 1: 使用主题组件 */}
|
||||||
<View style={custom.section}>
|
<View style={custom.section}>
|
||||||
<Text style={custom.sectionTitle}>
|
<Text style={custom.sectionTitle}>方式 1: 使用主题组件</Text>
|
||||||
方式 1: 使用主题组件
|
|
||||||
</Text>
|
|
||||||
<ThemedView style={{ padding: 12, borderRadius: 6 }}>
|
<ThemedView style={{ padding: 12, borderRadius: 6 }}>
|
||||||
<ThemedText type="title">这是标题</ThemedText>
|
<ThemedText type="title">这是标题</ThemedText>
|
||||||
<ThemedText type="subtitle">这是副标题</ThemedText>
|
<ThemedText type="subtitle">这是副标题</ThemedText>
|
||||||
@@ -109,9 +105,7 @@ export default function ThemeExampleScreen() {
|
|||||||
|
|
||||||
{/* 方式 2: 使用通用样式类 */}
|
{/* 方式 2: 使用通用样式类 */}
|
||||||
<View style={custom.section}>
|
<View style={custom.section}>
|
||||||
<Text style={custom.sectionTitle}>
|
<Text style={custom.sectionTitle}>方式 2: 使用通用样式类(类似 CSS 类名)</Text>
|
||||||
方式 2: 使用通用样式类(类似 CSS 类名)
|
|
||||||
</Text>
|
|
||||||
<View style={s.card}>
|
<View style={s.card}>
|
||||||
<Text style={s.textTitle}>卡片标题</Text>
|
<Text style={s.textTitle}>卡片标题</Text>
|
||||||
<Text style={s.textSecondary}>卡片描述文本</Text>
|
<Text style={s.textSecondary}>卡片描述文本</Text>
|
||||||
@@ -143,9 +137,7 @@ const s = commonStyles[theme];
|
|||||||
|
|
||||||
{/* 方式 3: 使用自定义主题样式 */}
|
{/* 方式 3: 使用自定义主题样式 */}
|
||||||
<View style={custom.section}>
|
<View style={custom.section}>
|
||||||
<Text style={custom.sectionTitle}>
|
<Text style={custom.sectionTitle}>方式 3: 使用自定义主题样式(推荐)</Text>
|
||||||
方式 3: 使用自定义主题样式(推荐)
|
|
||||||
</Text>
|
|
||||||
<View style={{ padding: 12 }}>
|
<View style={{ padding: 12 }}>
|
||||||
<Text style={{ color: colors.text }}>
|
<Text style={{ color: colors.text }}>
|
||||||
本页面的 header 和 section 就是使用自定义主题样式创建的
|
本页面的 header 和 section 就是使用自定义主题样式创建的
|
||||||
@@ -176,14 +168,14 @@ const theme = useColorScheme();
|
|||||||
|
|
||||||
{/* 方式 4: 使用 Hooks + 内联样式 */}
|
{/* 方式 4: 使用 Hooks + 内联样式 */}
|
||||||
<View style={custom.section}>
|
<View style={custom.section}>
|
||||||
<Text style={custom.sectionTitle}>
|
<Text style={custom.sectionTitle}>方式 4: 使用 Hooks + 内联样式(动态场景)</Text>
|
||||||
方式 4: 使用 Hooks + 内联样式(动态场景)
|
<View
|
||||||
</Text>
|
style={{
|
||||||
<View style={{
|
backgroundColor: colors.backgroundSecondary,
|
||||||
backgroundColor: colors.backgroundSecondary,
|
padding: 16,
|
||||||
padding: 16,
|
borderRadius: 8,
|
||||||
borderRadius: 8,
|
}}
|
||||||
}}>
|
>
|
||||||
<Text style={{ color: colors.text, fontSize: 16 }}>
|
<Text style={{ color: colors.text, fontSize: 16 }}>
|
||||||
这是使用 useThemeColors() 动态获取颜色的文本
|
这是使用 useThemeColors() 动态获取颜色的文本
|
||||||
</Text>
|
</Text>
|
||||||
@@ -212,9 +204,7 @@ const colors = useThemeColors();
|
|||||||
|
|
||||||
{/* 颜色展示 */}
|
{/* 颜色展示 */}
|
||||||
<View style={custom.section}>
|
<View style={custom.section}>
|
||||||
<Text style={custom.sectionTitle}>
|
<Text style={custom.sectionTitle}>主题颜色展示</Text>
|
||||||
主题颜色展示
|
|
||||||
</Text>
|
|
||||||
<View style={{ flexDirection: 'row', flexWrap: 'wrap', gap: 8 }}>
|
<View style={{ flexDirection: 'row', flexWrap: 'wrap', gap: 8 }}>
|
||||||
{Object.entries(colors).map(([key, value]) => (
|
{Object.entries(colors).map(([key, value]) => (
|
||||||
<View
|
<View
|
||||||
@@ -228,21 +218,27 @@ const colors = useThemeColors();
|
|||||||
borderColor: colors.border,
|
borderColor: colors.border,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Text style={{
|
<Text
|
||||||
color: key.includes('background') || key.includes('card') || key.includes('input')
|
style={{
|
||||||
? colors.text
|
color:
|
||||||
: '#FFFFFF',
|
key.includes('background') || key.includes('card') || key.includes('input')
|
||||||
fontSize: 10,
|
? colors.text
|
||||||
fontWeight: '600',
|
: '#FFFFFF',
|
||||||
}}>
|
fontSize: 10,
|
||||||
|
fontWeight: '600',
|
||||||
|
}}
|
||||||
|
>
|
||||||
{key}
|
{key}
|
||||||
</Text>
|
</Text>
|
||||||
<Text style={{
|
<Text
|
||||||
color: key.includes('background') || key.includes('card') || key.includes('input')
|
style={{
|
||||||
? colors.textSecondary
|
color:
|
||||||
: '#FFFFFF',
|
key.includes('background') || key.includes('card') || key.includes('input')
|
||||||
fontSize: 8,
|
? colors.textSecondary
|
||||||
}}>
|
: '#FFFFFF',
|
||||||
|
fontSize: 8,
|
||||||
|
}}
|
||||||
|
>
|
||||||
{value}
|
{value}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
@@ -256,4 +252,3 @@ const colors = useThemeColors();
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,20 @@
|
|||||||
import { StyleSheet, ScrollView, TouchableOpacity, View, Text, useColorScheme as useSystemColorScheme } from 'react-native';
|
import {
|
||||||
|
StyleSheet,
|
||||||
|
ScrollView,
|
||||||
|
TouchableOpacity,
|
||||||
|
View,
|
||||||
|
Text,
|
||||||
|
useColorScheme as useSystemColorScheme,
|
||||||
|
} from 'react-native';
|
||||||
import { Stack } from 'expo-router';
|
import { Stack } from 'expo-router';
|
||||||
import { useState, useEffect, useMemo } from 'react';
|
import { useState, useEffect, useMemo } from 'react';
|
||||||
import { useTheme, useSettingsActions } from '@/stores';
|
import { useTheme, useSettingsStore } from '@/stores';
|
||||||
import { useHaptics } from '@/hooks';
|
import { useHaptics } from '@/hooks';
|
||||||
import Colors from '@/constants/Colors';
|
import { Colors } from '@/theme';
|
||||||
|
|
||||||
export default function ThemeTestScreen() {
|
export default function ThemeTestScreen() {
|
||||||
const currentTheme = useTheme();
|
const currentTheme = useTheme();
|
||||||
const { setTheme } = useSettingsActions();
|
const { setTheme } = useSettingsStore();
|
||||||
const haptics = useHaptics();
|
const haptics = useHaptics();
|
||||||
const systemColorScheme = useSystemColorScheme();
|
const systemColorScheme = useSystemColorScheme();
|
||||||
|
|
||||||
@@ -17,7 +24,9 @@ export default function ThemeTestScreen() {
|
|||||||
// 直接计算实际应用的主题 - 不使用 useColorScheme hook
|
// 直接计算实际应用的主题 - 不使用 useColorScheme hook
|
||||||
const actualTheme: 'light' | 'dark' = useMemo(() => {
|
const actualTheme: 'light' | 'dark' = useMemo(() => {
|
||||||
return currentTheme === 'auto'
|
return currentTheme === 'auto'
|
||||||
? (systemColorScheme === 'dark' ? 'dark' : 'light')
|
? systemColorScheme === 'dark'
|
||||||
|
? 'dark'
|
||||||
|
: 'light'
|
||||||
: currentTheme;
|
: currentTheme;
|
||||||
}, [currentTheme, systemColorScheme]);
|
}, [currentTheme, systemColorScheme]);
|
||||||
|
|
||||||
@@ -30,7 +39,7 @@ export default function ThemeTestScreen() {
|
|||||||
// 监听主题变化
|
// 监听主题变化
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('🎨 Theme changed:', { currentTheme, systemColorScheme, actualTheme, renderKey });
|
console.log('🎨 Theme changed:', { currentTheme, systemColorScheme, actualTheme, renderKey });
|
||||||
setRenderKey(prev => prev + 1);
|
setRenderKey((prev) => prev + 1);
|
||||||
}, [currentTheme, systemColorScheme, actualTheme]);
|
}, [currentTheme, systemColorScheme, actualTheme]);
|
||||||
|
|
||||||
const handleThemeChange = (newTheme: 'light' | 'dark' | 'auto') => {
|
const handleThemeChange = (newTheme: 'light' | 'dark' | 'auto') => {
|
||||||
@@ -50,14 +59,10 @@ export default function ThemeTestScreen() {
|
|||||||
headerTintColor: colors.text,
|
headerTintColor: colors.text,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<ScrollView
|
<ScrollView style={[styles.container, { backgroundColor: colors.background }]}>
|
||||||
style={[styles.container, { backgroundColor: colors.background }]}
|
|
||||||
>
|
|
||||||
{/* 主题信息 */}
|
{/* 主题信息 */}
|
||||||
<View style={[styles.section, { backgroundColor: colors.backgroundSecondary }]}>
|
<View style={[styles.section, { backgroundColor: colors.backgroundSecondary }]}>
|
||||||
<Text style={[styles.title, { color: colors.text }]}>
|
<Text style={[styles.title, { color: colors.text }]}>当前主题信息</Text>
|
||||||
当前主题信息
|
|
||||||
</Text>
|
|
||||||
<Text style={[styles.infoText, { color: colors.textSecondary }]}>
|
<Text style={[styles.infoText, { color: colors.textSecondary }]}>
|
||||||
用户设置: {currentTheme}
|
用户设置: {currentTheme}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -74,24 +79,25 @@ export default function ThemeTestScreen() {
|
|||||||
|
|
||||||
{/* 主题切换按钮 */}
|
{/* 主题切换按钮 */}
|
||||||
<View style={[styles.section, { backgroundColor: colors.backgroundSecondary }]}>
|
<View style={[styles.section, { backgroundColor: colors.backgroundSecondary }]}>
|
||||||
<Text style={[styles.title, { color: colors.text }]}>
|
<Text style={[styles.title, { color: colors.text }]}>切换主题</Text>
|
||||||
切换主题
|
|
||||||
</Text>
|
|
||||||
<View style={styles.buttonRow}>
|
<View style={styles.buttonRow}>
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
style={[
|
style={[
|
||||||
styles.themeButton,
|
styles.themeButton,
|
||||||
{
|
{
|
||||||
backgroundColor: currentTheme === 'light' ? colors.primary : colors.backgroundTertiary,
|
backgroundColor:
|
||||||
|
currentTheme === 'light' ? colors.primary : colors.backgroundTertiary,
|
||||||
borderColor: colors.border,
|
borderColor: colors.border,
|
||||||
}
|
},
|
||||||
]}
|
]}
|
||||||
onPress={() => handleThemeChange('light')}
|
onPress={() => handleThemeChange('light')}
|
||||||
>
|
>
|
||||||
<Text style={[
|
<Text
|
||||||
styles.buttonText,
|
style={[
|
||||||
{ color: currentTheme === 'light' ? '#fff' : colors.text }
|
styles.buttonText,
|
||||||
]}>
|
{ color: currentTheme === 'light' ? '#fff' : colors.text },
|
||||||
|
]}
|
||||||
|
>
|
||||||
☀️ 浅色
|
☀️ 浅色
|
||||||
</Text>
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
@@ -100,16 +106,19 @@ export default function ThemeTestScreen() {
|
|||||||
style={[
|
style={[
|
||||||
styles.themeButton,
|
styles.themeButton,
|
||||||
{
|
{
|
||||||
backgroundColor: currentTheme === 'dark' ? colors.primary : colors.backgroundTertiary,
|
backgroundColor:
|
||||||
|
currentTheme === 'dark' ? colors.primary : colors.backgroundTertiary,
|
||||||
borderColor: colors.border,
|
borderColor: colors.border,
|
||||||
}
|
},
|
||||||
]}
|
]}
|
||||||
onPress={() => handleThemeChange('dark')}
|
onPress={() => handleThemeChange('dark')}
|
||||||
>
|
>
|
||||||
<Text style={[
|
<Text
|
||||||
styles.buttonText,
|
style={[
|
||||||
{ color: currentTheme === 'dark' ? '#fff' : colors.text }
|
styles.buttonText,
|
||||||
]}>
|
{ color: currentTheme === 'dark' ? '#fff' : colors.text },
|
||||||
|
]}
|
||||||
|
>
|
||||||
🌙 深色
|
🌙 深色
|
||||||
</Text>
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
@@ -118,16 +127,19 @@ export default function ThemeTestScreen() {
|
|||||||
style={[
|
style={[
|
||||||
styles.themeButton,
|
styles.themeButton,
|
||||||
{
|
{
|
||||||
backgroundColor: currentTheme === 'auto' ? colors.primary : colors.backgroundTertiary,
|
backgroundColor:
|
||||||
|
currentTheme === 'auto' ? colors.primary : colors.backgroundTertiary,
|
||||||
borderColor: colors.border,
|
borderColor: colors.border,
|
||||||
}
|
},
|
||||||
]}
|
]}
|
||||||
onPress={() => handleThemeChange('auto')}
|
onPress={() => handleThemeChange('auto')}
|
||||||
>
|
>
|
||||||
<Text style={[
|
<Text
|
||||||
styles.buttonText,
|
style={[
|
||||||
{ color: currentTheme === 'auto' ? '#fff' : colors.text }
|
styles.buttonText,
|
||||||
]}>
|
{ color: currentTheme === 'auto' ? '#fff' : colors.text },
|
||||||
|
]}
|
||||||
|
>
|
||||||
🔄 自动
|
🔄 自动
|
||||||
</Text>
|
</Text>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
@@ -136,9 +148,7 @@ export default function ThemeTestScreen() {
|
|||||||
|
|
||||||
{/* 文本颜色展示 */}
|
{/* 文本颜色展示 */}
|
||||||
<View style={[styles.section, { backgroundColor: colors.backgroundSecondary }]}>
|
<View style={[styles.section, { backgroundColor: colors.backgroundSecondary }]}>
|
||||||
<Text style={[styles.title, { color: colors.text }]}>
|
<Text style={[styles.title, { color: colors.text }]}>文本颜色</Text>
|
||||||
文本颜色
|
|
||||||
</Text>
|
|
||||||
<Text style={[styles.colorText, { color: colors.text }]}>
|
<Text style={[styles.colorText, { color: colors.text }]}>
|
||||||
Primary Text - {colors.text}
|
Primary Text - {colors.text}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -152,15 +162,22 @@ export default function ThemeTestScreen() {
|
|||||||
|
|
||||||
{/* 背景颜色展示 */}
|
{/* 背景颜色展示 */}
|
||||||
<View style={[styles.section, { backgroundColor: colors.backgroundSecondary }]}>
|
<View style={[styles.section, { backgroundColor: colors.backgroundSecondary }]}>
|
||||||
<Text style={[styles.title, { color: colors.text }]}>
|
<Text style={[styles.title, { color: colors.text }]}>背景颜色</Text>
|
||||||
背景颜色
|
|
||||||
</Text>
|
|
||||||
<View style={[styles.colorBox, { backgroundColor: colors.background }]}>
|
<View style={[styles.colorBox, { backgroundColor: colors.background }]}>
|
||||||
<Text style={[styles.colorText, { color: colors.text }]}>
|
<Text style={[styles.colorText, { color: colors.text }]}>
|
||||||
Primary Background - {colors.background}
|
Primary Background - {colors.background}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[styles.colorBox, { backgroundColor: colors.backgroundSecondary, borderWidth: 1, borderColor: colors.border }]}>
|
<View
|
||||||
|
style={[
|
||||||
|
styles.colorBox,
|
||||||
|
{
|
||||||
|
backgroundColor: colors.backgroundSecondary,
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: colors.border,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
<Text style={[styles.colorText, { color: colors.text }]}>
|
<Text style={[styles.colorText, { color: colors.text }]}>
|
||||||
Secondary Background - {colors.backgroundSecondary}
|
Secondary Background - {colors.backgroundSecondary}
|
||||||
</Text>
|
</Text>
|
||||||
@@ -174,15 +191,15 @@ export default function ThemeTestScreen() {
|
|||||||
|
|
||||||
{/* 主题颜色展示 */}
|
{/* 主题颜色展示 */}
|
||||||
<View style={[styles.section, { backgroundColor: colors.backgroundSecondary }]}>
|
<View style={[styles.section, { backgroundColor: colors.backgroundSecondary }]}>
|
||||||
<Text style={[styles.title, { color: colors.text }]}>
|
<Text style={[styles.title, { color: colors.text }]}>主题颜色</Text>
|
||||||
主题颜色
|
|
||||||
</Text>
|
|
||||||
<View style={styles.colorGrid}>
|
<View style={styles.colorGrid}>
|
||||||
<View style={[styles.colorBox, { backgroundColor: colors.primary }]}>
|
<View style={[styles.colorBox, { backgroundColor: colors.primary }]}>
|
||||||
<Text style={[styles.colorText, { color: '#fff' }]}>Primary - {colors.primary}</Text>
|
<Text style={[styles.colorText, { color: '#fff' }]}>Primary - {colors.primary}</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[styles.colorBox, { backgroundColor: colors.secondary }]}>
|
<View style={[styles.colorBox, { backgroundColor: colors.secondary }]}>
|
||||||
<Text style={[styles.colorText, { color: '#fff' }]}>Secondary - {colors.secondary}</Text>
|
<Text style={[styles.colorText, { color: '#fff' }]}>
|
||||||
|
Secondary - {colors.secondary}
|
||||||
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
<View style={[styles.colorBox, { backgroundColor: colors.success }]}>
|
<View style={[styles.colorBox, { backgroundColor: colors.success }]}>
|
||||||
<Text style={[styles.colorText, { color: '#fff' }]}>Success - {colors.success}</Text>
|
<Text style={[styles.colorText, { color: '#fff' }]}>Success - {colors.success}</Text>
|
||||||
@@ -201,30 +218,27 @@ export default function ThemeTestScreen() {
|
|||||||
|
|
||||||
{/* UI 元素展示 */}
|
{/* UI 元素展示 */}
|
||||||
<View style={[styles.section, { backgroundColor: colors.backgroundSecondary }]}>
|
<View style={[styles.section, { backgroundColor: colors.backgroundSecondary }]}>
|
||||||
<Text style={[styles.title, { color: colors.text }]}>
|
<Text style={[styles.title, { color: colors.text }]}>UI 元素</Text>
|
||||||
UI 元素
|
|
||||||
</Text>
|
|
||||||
<View style={[styles.card, { backgroundColor: colors.card, borderColor: colors.border }]}>
|
<View style={[styles.card, { backgroundColor: colors.card, borderColor: colors.border }]}>
|
||||||
<Text style={[styles.cardText, { color: colors.text }]}>
|
<Text style={[styles.cardText, { color: colors.text }]}>这是一个卡片组件</Text>
|
||||||
这是一个卡片组件
|
|
||||||
</Text>
|
|
||||||
<Text style={[styles.cardSubtext, { color: colors.textSecondary }]}>
|
<Text style={[styles.cardSubtext, { color: colors.textSecondary }]}>
|
||||||
卡片背景色: {colors.card}
|
卡片背景色: {colors.card}
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View style={[styles.input, { backgroundColor: colors.inputBackground, borderColor: colors.inputBorder }]}>
|
<View
|
||||||
<Text style={[styles.inputText, { color: colors.textSecondary }]}>
|
style={[
|
||||||
输入框样式预览
|
styles.input,
|
||||||
</Text>
|
{ backgroundColor: colors.inputBackground, borderColor: colors.inputBorder },
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Text style={[styles.inputText, { color: colors.textSecondary }]}>输入框样式预览</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<View style={[styles.separator, { backgroundColor: colors.separator }]} />
|
<View style={[styles.separator, { backgroundColor: colors.separator }]} />
|
||||||
|
|
||||||
<TouchableOpacity style={[styles.button, { backgroundColor: colors.buttonPrimary }]}>
|
<TouchableOpacity style={[styles.button, { backgroundColor: colors.buttonPrimary }]}>
|
||||||
<Text style={[styles.buttonText, { color: '#fff' }]}>
|
<Text style={[styles.buttonText, { color: '#fff' }]}>按钮示例</Text>
|
||||||
按钮示例
|
|
||||||
</Text>
|
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
</View>
|
</View>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
@@ -314,4 +328,3 @@ const styles = StyleSheet.create({
|
|||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
BIN
assets/images/game/blockThird/color_1390.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
assets/images/game/blockThird/color_1391.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
assets/images/game/blockThird/color_1392.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
assets/images/game/blockThird/color_1560.png
Normal file
|
After Width: | Height: | Size: 146 KiB |
BIN
assets/images/game/blockThird/h_1390.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
assets/images/game/blockThird/h_1391.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
assets/images/game/blockThird/h_1391.webp
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
BIN
assets/images/game/blockThird/h_1392.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
assets/images/game/blockThird/h_1560.png
Normal file
|
After Width: | Height: | Size: 146 KiB |
BIN
assets/images/game/blockThird/m_1390.png
Normal file
|
After Width: | Height: | Size: 71 KiB |
BIN
assets/images/game/blockThird/m_1390.webp
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
assets/images/game/blockThird/m_1391.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
assets/images/game/blockThird/m_1391.webp
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
assets/images/game/blockThird/m_1392.png
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
assets/images/game/blockThird/m_1392.webp
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
assets/images/game/blockThird/m_1560.png
Normal file
|
After Width: | Height: | Size: 130 KiB |
BIN
assets/images/game/chess/color_1033.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
assets/images/game/chess/color_1036.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
assets/images/game/chess/color_1383.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
assets/images/game/chess/color_1537.png
Normal file
|
After Width: | Height: | Size: 7.0 KiB |
BIN
assets/images/game/chess/color_1537.webp
Normal file
|
After Width: | Height: | Size: 4.7 KiB |
BIN
assets/images/game/chess/color_297.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
assets/images/game/chess/color_299.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
assets/images/game/chess/color_382.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
assets/images/game/chess/color_388.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
assets/images/game/chess/color_393.png
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
assets/images/game/chess/color_394.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
assets/images/game/chess/color_401.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
assets/images/game/chess/color_404.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
assets/images/game/chess/color_417.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
assets/images/game/chess/color_506.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
assets/images/game/chess/color_709.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
assets/images/game/chess/color_744.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
assets/images/game/chess/color_745.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
assets/images/game/chess/color_746.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
assets/images/game/chess/color_927.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
assets/images/game/chess/color_928.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
assets/images/game/chess/dark_1383.png
Normal file
|
After Width: | Height: | Size: 981 B |
BIN
assets/images/game/chess/dark_297.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
assets/images/game/chess/dark_299.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
assets/images/game/chess/dark_382.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
assets/images/game/chess/dark_388.png
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
assets/images/game/chess/dark_388.webp
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
assets/images/game/chess/dark_393.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
BIN
assets/images/game/chess/dark_394.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
assets/images/game/chess/dark_401.png
Normal file
|
After Width: | Height: | Size: 940 B |
BIN
assets/images/game/chess/dark_404.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
assets/images/game/chess/dark_417.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
assets/images/game/chess/dark_506.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
assets/images/game/chess/dark_709.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
assets/images/game/chess/dark_744.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
assets/images/game/chess/dark_745.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
assets/images/game/chess/dark_746.png
Normal file
|
After Width: | Height: | Size: 4.8 KiB |
BIN
assets/images/game/chess/dark_927.png
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
assets/images/game/chess/dark_928.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
assets/images/game/chess/h_1036.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
assets/images/game/chess/h_1036.webp
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
BIN
assets/images/game/chess/h_1383.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
assets/images/game/chess/h_1383.webp
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
assets/images/game/chess/h_1537.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
assets/images/game/chess/h_1537.webp
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
assets/images/game/chess/h_297.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
assets/images/game/chess/h_297.webp
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
assets/images/game/chess/h_299.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
assets/images/game/chess/h_299.webp
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
assets/images/game/chess/h_382.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
assets/images/game/chess/h_382.webp
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
assets/images/game/chess/h_388.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
assets/images/game/chess/h_388.webp
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
assets/images/game/chess/h_393.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
assets/images/game/chess/h_393.webp
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
assets/images/game/chess/h_394.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
assets/images/game/chess/h_394.webp
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
assets/images/game/chess/h_401.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
assets/images/game/chess/h_401.webp
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
assets/images/game/chess/h_404.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
assets/images/game/chess/h_404.webp
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
assets/images/game/chess/h_506.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
assets/images/game/chess/h_506.webp
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
assets/images/game/chess/h_709.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
assets/images/game/chess/h_709.webp
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
assets/images/game/chess/h_744.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
assets/images/game/chess/h_744.webp
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
assets/images/game/chess/h_745.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
assets/images/game/chess/h_745.webp
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
assets/images/game/chess/h_746.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
assets/images/game/chess/h_746.webp
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
assets/images/game/chess/h_927.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
assets/images/game/chess/h_927.webp
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
assets/images/game/chess/h_928.png
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
assets/images/game/chess/h_928.webp
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
assets/images/game/chess/light_1383.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |