diff --git a/.eas/workflows/create-production-builds.yml b/.eas/workflows/create-production-builds.yml new file mode 100644 index 0000000..7342cd8 --- /dev/null +++ b/.eas/workflows/create-production-builds.yml @@ -0,0 +1,11 @@ +name: Create Production Builds + +jobs: + build_android: + type: build # This job type creates a production build for Android + params: + platform: android + build_ios: + type: build # This job type creates a production build for iOS + params: + platform: ios diff --git a/README.md b/README.md index 48dd63f..c50af91 100644 --- a/README.md +++ b/README.md @@ -1,50 +1,18 @@ -# Welcome to your Expo app 👋 - -This is an [Expo](https://expo.dev) project created with [`create-expo-app`](https://www.npmjs.com/package/create-expo-app). - -## Get started - -1. Install dependencies - - ```bash - npm install - ``` - -2. Start the app - - ```bash - npx expo start - ``` - -In the output, you'll find options to open the app in a - -- [development build](https://docs.expo.dev/develop/development-builds/introduction/) -- [Android emulator](https://docs.expo.dev/workflow/android-studio-emulator/) -- [iOS simulator](https://docs.expo.dev/workflow/ios-simulator/) -- [Expo Go](https://expo.dev/go), a limited sandbox for trying out app development with Expo - -You can start developing by editing the files inside the **app** directory. This project uses [file-based routing](https://docs.expo.dev/router/introduction). - -## Get a fresh project - -When you're ready, run: - -```bash -npm run reset-project +## Dependencies +### SQLite +- [SQLite](https://sqlite.org/index.html) +```shell +expo install expo-sqlite +cp node_modules/wa-sqlite/dist/wa-sqlite.wasm node_modules/expo-sqlite/web/wa-sqlite/ ``` -This command will move the starter code to the **app-example** directory and create a blank **app** directory where you can start developing. +## Build +### EAS Build +```shell +eas build --platform android --profile development +``` -## Learn more - -To learn more about developing your project with Expo, look at the following resources: - -- [Expo documentation](https://docs.expo.dev/): Learn fundamentals, or go into advanced topics with our [guides](https://docs.expo.dev/guides). -- [Learn Expo tutorial](https://docs.expo.dev/tutorial/introduction/): Follow a step-by-step tutorial where you'll create a project that runs on Android, iOS, and the web. - -## Join the community - -Join our community of developers creating universal apps. - -- [Expo on GitHub](https://github.com/expo/expo): View our open source platform and contribute. -- [Discord community](https://chat.expo.dev): Chat with Expo users and ask questions. +### EAS Workflow +```shell +npx eas-cli@latest workflow:run create-production-builds.yml +``` \ No newline at end of file diff --git a/app.json b/app.json index f1fb0fb..bf8aaf7 100644 --- a/app.json +++ b/app.json @@ -15,7 +15,11 @@ "NSPhotoLibraryAddUsageDescription": "需要保存图片到相册", "NSLocationWhenInUseUsageDescription": "Allow $(PRODUCT_NAME) to access your location to get photo location data.", "ITSAppUsesNonExemptEncryption": false, - "UIBackgroundModes": ["fetch", "location", "audio"] + "UIBackgroundModes": [ + "fetch", + "location", + "audio" + ] }, "bundleIdentifier": "com.memowake.app" }, @@ -48,8 +52,9 @@ }, "plugins": [ "expo-router", - "expo-secure-store", [ - "expo-background-fetch", + "expo-secure-store", + [ + "expo-background-task", { "minimumInterval": 15 } @@ -68,15 +73,6 @@ "locationWhenInUsePermission": "允许 $(PRODUCT_NAME) 访问您的位置" } ], - // [ - // "expo-notifications", - // { - // "color": "#ffffff", - // "defaultChannel": "default", - // "enableBackgroundRemoteNotifications": false, - // "mode": "client" - // } - // ], [ "expo-audio", { @@ -90,7 +86,8 @@ "savePhotosPermission": "Allow $(PRODUCT_NAME) to save photos.", "isAccessMediaLocationEnabled": true } - ] + ], + "expo-sqlite" ], "experiments": { "typedRoutes": true diff --git a/app/(tabs)/_layout.tsx b/app/(tabs)/_layout.tsx index 2f5e889..324e9f3 100644 --- a/app/(tabs)/_layout.tsx +++ b/app/(tabs)/_layout.tsx @@ -1,4 +1,5 @@ import { HapticTab } from '@/components/HapticTab'; +import { TabBarIcon } from '@/components/navigation/TabBarIcon'; import TabBarBackground from '@/components/ui/TabBarBackground'; import { Colors } from '@/constants/Colors'; import { useColorScheme } from '@/hooks/useColorScheme'; @@ -279,6 +280,19 @@ export default function TabLayout() { tabBarStyle: { display: 'none' } // 确保在标签栏中不显示 }} /> - + + {/* Debug Screen - only in development */} + {process.env.NODE_ENV === 'development' && ( + ( + + ), + }} + /> + )} + ); } diff --git a/app/(tabs)/ask.tsx b/app/(tabs)/ask.tsx index 25cedb6..a50f7b2 100644 --- a/app/(tabs)/ask.tsx +++ b/app/(tabs)/ask.tsx @@ -3,6 +3,7 @@ import Chat from "@/components/ask/chat"; import AskHello from "@/components/ask/hello"; import SendMessage from "@/components/ask/send"; import { ThemedText } from "@/components/ThemedText"; +import { checkAuthStatus } from '@/lib/auth'; import { fetchApi } from "@/lib/server-api-util"; import { Message } from "@/types/ask"; import { router, useLocalSearchParams } from "expo-router"; @@ -20,6 +21,10 @@ import { useSafeAreaInsets } from "react-native-safe-area-context"; export default function AskScreen() { const insets = useSafeAreaInsets(); + useEffect(() => { + checkAuthStatus(router); + }, []); + // 在组件内部添加 ref const scrollViewRef = useRef(null); const [isHello, setIsHello] = useState(true); const [conversationId, setConversationId] = useState(null); diff --git a/app/(tabs)/debug.tsx b/app/(tabs)/debug.tsx new file mode 100644 index 0000000..315ce75 --- /dev/null +++ b/app/(tabs)/debug.tsx @@ -0,0 +1,132 @@ +import React, { useState } from 'react'; +import { View, TextInput, Button, Text, StyleSheet, ScrollView, SafeAreaView, ActivityIndicator, KeyboardAvoidingView, Platform } from 'react-native'; +import { executeSql } from '@/lib/db'; +import { ThemedView } from '@/components/ThemedView'; +import { ThemedText } from '@/components/ThemedText'; + +const DebugScreen = () => { + const [sql, setSql] = useState('SELECT * FROM upload_tasks;'); + const [results, setResults] = useState(null); + const [loading, setLoading] = useState(false); + + const handleExecuteSql = async (query: string) => { + if (!query) return; + setLoading(true); + setResults(null); + try { + const result = await executeSql(query); + setResults(result); + } catch (error) { + setResults({ error: (error as Error).message }); + } finally { + setLoading(false); + } + }; + + const presetQueries = [ + { title: 'All Uploads', query: 'SELECT * FROM upload_tasks;' }, + { title: 'Delete All Uploads', query: 'DELETE FROM upload_tasks;' }, + { title: 'Show Tables', query: "SELECT name FROM sqlite_master WHERE type='table';" }, + ]; + + return ( + + + + SQL Debugger + + +