diff --git a/.claude/settings.local.json b/.claude/settings.local.json
new file mode 100644
index 0000000..ff18b0c
--- /dev/null
+++ b/.claude/settings.local.json
@@ -0,0 +1,11 @@
+{
+ "permissions": {
+ "allow": [
+ "Bash(npm install:*)",
+ "Bash(mkdir -p:*)",
+ "Bash(npm install:*)",
+ "Bash(*:*)"
+ ],
+ "deny": []
+ }
+}
diff --git a/App.tsx b/App.tsx
index d091223..f1e3eb1 100644
--- a/App.tsx
+++ b/App.tsx
@@ -1,28 +1,15 @@
-/**
- * Sample React Native App
- * https://github.com/facebook/react-native
- *
- * @format
- */
+import React from 'react';
+import { NavigationContainer } from '@react-navigation/native';
+import AppNavigator from './src/navigation/AppNavigator';
-import { NewAppScreen } from '@react-native/new-app-screen';
-import { StatusBar, StyleSheet, useColorScheme, View } from 'react-native';
-
-function App() {
- const isDarkMode = useColorScheme() === 'dark';
+import { PaperProvider } from 'react-native-paper';
+export default function App() {
return (
-
-
-
-
+
+
+
+
+
);
}
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- },
-});
-
-export default App;
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 351e25c..fe7aaa1 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -107,6 +107,8 @@ android {
}
}
+apply from: file("../../node_modules/react-native-vector-icons/fonts.gradle")
+
dependencies {
// The version of react-native is set by the React Native Gradle Plugin
implementation("com.facebook.react:react-android")
diff --git a/index.js b/index.js
index 9b73932..6011123 100644
--- a/index.js
+++ b/index.js
@@ -1,3 +1,5 @@
+import 'react-native-get-random-values';
+import 'react-native-gesture-handler';
/**
* @format
*/
diff --git a/package-lock.json b/package-lock.json
index f220a1b..6678b0c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -9,8 +9,18 @@
"version": "0.0.1",
"dependencies": {
"@react-native/new-app-screen": "0.80.1",
+ "@react-navigation/bottom-tabs": "^7.4.2",
+ "@react-navigation/native": "^7.1.14",
+ "@react-navigation/stack": "^7.4.2",
"react": "19.1.0",
- "react-native": "0.80.1"
+ "react-native": "0.80.1",
+ "react-native-gesture-handler": "^2.27.1",
+ "react-native-get-random-values": "^1.11.0",
+ "react-native-paper": "^5.14.5",
+ "react-native-safe-area-context": "^5.5.2",
+ "react-native-screens": "^4.13.1",
+ "react-native-vector-icons": "^10.2.0",
+ "uuid": "^11.1.0"
},
"devDependencies": {
"@babel/core": "^7.25.2",
@@ -26,6 +36,7 @@
"@types/jest": "^29.5.13",
"@types/react": "^19.1.0",
"@types/react-test-renderer": "^19.1.0",
+ "@types/uuid": "^10.0.0",
"eslint": "^8.19.0",
"jest": "^29.6.3",
"prettier": "2.8.8",
@@ -1995,6 +2006,40 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/@callstack/react-theme-provider": {
+ "version": "3.0.9",
+ "resolved": "https://registry.npmmirror.com/@callstack/react-theme-provider/-/react-theme-provider-3.0.9.tgz",
+ "integrity": "sha512-tTQ0uDSCL0ypeMa8T/E9wAZRGKWj8kXP7+6RYgPTfOPs9N07C9xM8P02GJ3feETap4Ux5S69D9nteq9mEj86NA==",
+ "license": "MIT",
+ "dependencies": {
+ "deepmerge": "^3.2.0",
+ "hoist-non-react-statics": "^3.3.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.3.0"
+ }
+ },
+ "node_modules/@callstack/react-theme-provider/node_modules/deepmerge": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmmirror.com/deepmerge/-/deepmerge-3.3.0.tgz",
+ "integrity": "sha512-GRQOafGHwMHpjPx9iCvTgpu9NojZ49q794EEL94JVEw6VaeA8XTUyBKvAkOOjBX9oJNiV6G3P+T+tihFjo2TqA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/@egjs/hammerjs": {
+ "version": "2.0.17",
+ "resolved": "https://registry.npmmirror.com/@egjs/hammerjs/-/hammerjs-2.0.17.tgz",
+ "integrity": "sha512-XQsZgjm2EcVUiZQf11UBJQfmZeEmOW8DpI1gsFeln6w0ae0ii4dMQEQ0kjl6DspdWX1aGY1/loyXnP0JS06e/A==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/hammerjs": "^2.0.36"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
"node_modules/@eslint-community/eslint-utils": {
"version": "4.7.0",
"resolved": "https://registry.npmmirror.com/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz",
@@ -3297,6 +3342,114 @@
}
}
},
+ "node_modules/@react-navigation/bottom-tabs": {
+ "version": "7.4.2",
+ "resolved": "https://registry.npmmirror.com/@react-navigation/bottom-tabs/-/bottom-tabs-7.4.2.tgz",
+ "integrity": "sha512-jyBux5l3qqEucY5M/ZWxVvfA8TQu7DVl2gK+xB6iKqRUfLf7dSumyVxc7HemDwGFoz3Ug8dVZFvSMEs+mfrieQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@react-navigation/elements": "^2.5.2",
+ "color": "^4.2.3"
+ },
+ "peerDependencies": {
+ "@react-navigation/native": "^7.1.14",
+ "react": ">= 18.2.0",
+ "react-native": "*",
+ "react-native-safe-area-context": ">= 4.0.0",
+ "react-native-screens": ">= 4.0.0"
+ }
+ },
+ "node_modules/@react-navigation/core": {
+ "version": "7.12.1",
+ "resolved": "https://registry.npmmirror.com/@react-navigation/core/-/core-7.12.1.tgz",
+ "integrity": "sha512-ir6s25CDkReufi0vQhSIAe+AAHHJN9zTgGlS6iDS1yqbwgl2MiBAZzpaOL1T5llYujie2jF/bODeLz2j4k80zw==",
+ "license": "MIT",
+ "dependencies": {
+ "@react-navigation/routers": "^7.4.1",
+ "escape-string-regexp": "^4.0.0",
+ "nanoid": "^3.3.11",
+ "query-string": "^7.1.3",
+ "react-is": "^19.1.0",
+ "use-latest-callback": "^0.2.4",
+ "use-sync-external-store": "^1.5.0"
+ },
+ "peerDependencies": {
+ "react": ">= 18.2.0"
+ }
+ },
+ "node_modules/@react-navigation/core/node_modules/react-is": {
+ "version": "19.1.0",
+ "resolved": "https://registry.npmmirror.com/react-is/-/react-is-19.1.0.tgz",
+ "integrity": "sha512-Oe56aUPnkHyyDxxkvqtd7KkdQP5uIUfHxd5XTb3wE9d/kRnZLmKbDB0GWk919tdQ+mxxPtG6EAs6RMT6i1qtHg==",
+ "license": "MIT"
+ },
+ "node_modules/@react-navigation/elements": {
+ "version": "2.5.2",
+ "resolved": "https://registry.npmmirror.com/@react-navigation/elements/-/elements-2.5.2.tgz",
+ "integrity": "sha512-aGC3ukF5+lXuiF5bK7bJyRuWCE+Tk4MZ3GoQpAb7u7+m0KmsquliDhj4UCWEUU5kUoCeoRAUvv+1lKcYKf+WTQ==",
+ "license": "MIT",
+ "dependencies": {
+ "color": "^4.2.3",
+ "use-latest-callback": "^0.2.4",
+ "use-sync-external-store": "^1.5.0"
+ },
+ "peerDependencies": {
+ "@react-native-masked-view/masked-view": ">= 0.2.0",
+ "@react-navigation/native": "^7.1.14",
+ "react": ">= 18.2.0",
+ "react-native": "*",
+ "react-native-safe-area-context": ">= 4.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@react-native-masked-view/masked-view": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@react-navigation/native": {
+ "version": "7.1.14",
+ "resolved": "https://registry.npmmirror.com/@react-navigation/native/-/native-7.1.14.tgz",
+ "integrity": "sha512-X233/CNx41FpshlWe4uEAUN8CNem3ju4t5pnVKcdhDR0cTQT1rK6P0ZwjSylD9zXdnHvJttFjBhKTot6TcvSqA==",
+ "license": "MIT",
+ "dependencies": {
+ "@react-navigation/core": "^7.12.1",
+ "escape-string-regexp": "^4.0.0",
+ "fast-deep-equal": "^3.1.3",
+ "nanoid": "^3.3.11",
+ "use-latest-callback": "^0.2.4"
+ },
+ "peerDependencies": {
+ "react": ">= 18.2.0",
+ "react-native": "*"
+ }
+ },
+ "node_modules/@react-navigation/routers": {
+ "version": "7.4.1",
+ "resolved": "https://registry.npmmirror.com/@react-navigation/routers/-/routers-7.4.1.tgz",
+ "integrity": "sha512-42mZrMzQ0LfKxUb5OHIurYrPYyRsXFLolucILrvm21f0O40Sw0Ufh1bnn/jRqnxZZu7wvpUGIGYM8nS9zVE1Aw==",
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.11"
+ }
+ },
+ "node_modules/@react-navigation/stack": {
+ "version": "7.4.2",
+ "resolved": "https://registry.npmmirror.com/@react-navigation/stack/-/stack-7.4.2.tgz",
+ "integrity": "sha512-QlqBxKBfKVx/XRH04pRRGQ92tO1fV0RL7YEw5G4pew6CNY26102dVQl5A39ZztvlvEDQbCQkatyDS7i2xR1QiA==",
+ "license": "MIT",
+ "dependencies": {
+ "@react-navigation/elements": "^2.5.2",
+ "color": "^4.2.3"
+ },
+ "peerDependencies": {
+ "@react-navigation/native": "^7.1.14",
+ "react": ">= 18.2.0",
+ "react-native": "*",
+ "react-native-gesture-handler": ">= 2.0.0",
+ "react-native-safe-area-context": ">= 4.0.0",
+ "react-native-screens": ">= 4.0.0"
+ }
+ },
"node_modules/@sideway/address": {
"version": "4.1.5",
"resolved": "https://registry.npmmirror.com/@sideway/address/-/address-4.1.5.tgz",
@@ -3395,6 +3548,12 @@
"@types/node": "*"
}
},
+ "node_modules/@types/hammerjs": {
+ "version": "2.0.46",
+ "resolved": "https://registry.npmmirror.com/@types/hammerjs/-/hammerjs-2.0.46.tgz",
+ "integrity": "sha512-ynRvcq6wvqexJ9brDMS4BnBLzmr0e14d6ZJTEShTBWKymQiHwlAyGu0ZPEFI2Fh1U53F7tN9ufClWM5KvqkKOw==",
+ "license": "MIT"
+ },
"node_modules/@types/istanbul-lib-coverage": {
"version": "2.0.6",
"resolved": "https://registry.npmmirror.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz",
@@ -3514,6 +3673,13 @@
"integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==",
"license": "MIT"
},
+ "node_modules/@types/uuid": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmmirror.com/@types/uuid/-/uuid-10.0.0.tgz",
+ "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/yargs": {
"version": "17.0.33",
"resolved": "https://registry.npmmirror.com/@types/yargs/-/yargs-17.0.33.tgz",
@@ -4810,6 +4976,19 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/color": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmmirror.com/color/-/color-4.2.3.tgz",
+ "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1",
+ "color-string": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=12.5.0"
+ }
+ },
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz",
@@ -4828,6 +5007,16 @@
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"license": "MIT"
},
+ "node_modules/color-string": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmmirror.com/color-string/-/color-string-1.9.1.tgz",
+ "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "^1.0.0",
+ "simple-swizzle": "^0.2.2"
+ }
+ },
"node_modules/colorette": {
"version": "1.4.0",
"resolved": "https://registry.npmmirror.com/colorette/-/colorette-1.4.0.tgz",
@@ -5126,6 +5315,15 @@
"node": ">=0.10.0"
}
},
+ "node_modules/decode-uri-component": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmmirror.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz",
+ "integrity": "sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
"node_modules/dedent": {
"version": "1.6.0",
"resolved": "https://registry.npmmirror.com/dedent/-/dedent-1.6.0.tgz",
@@ -6234,11 +6432,16 @@
"integrity": "sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==",
"license": "Apache-2.0"
},
+ "node_modules/fast-base64-decode": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmmirror.com/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz",
+ "integrity": "sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==",
+ "license": "MIT"
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
- "dev": true,
"license": "MIT"
},
"node_modules/fast-glob": {
@@ -6347,6 +6550,15 @@
"node": ">=8"
}
},
+ "node_modules/filter-obj": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmmirror.com/filter-obj/-/filter-obj-1.1.0.tgz",
+ "integrity": "sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/finalhandler": {
"version": "1.1.2",
"resolved": "https://registry.npmmirror.com/finalhandler/-/finalhandler-1.1.2.tgz",
@@ -6879,6 +7091,21 @@
"hermes-estree": "0.28.1"
}
},
+ "node_modules/hoist-non-react-statics": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmmirror.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
+ "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "react-is": "^16.7.0"
+ }
+ },
+ "node_modules/hoist-non-react-statics/node_modules/react-is": {
+ "version": "16.13.1",
+ "resolved": "https://registry.npmmirror.com/react-is/-/react-is-16.13.1.tgz",
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
+ "license": "MIT"
+ },
"node_modules/html-escaper": {
"version": "2.0.2",
"resolved": "https://registry.npmmirror.com/html-escaper/-/html-escaper-2.0.2.tgz",
@@ -9629,6 +9856,24 @@
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
"license": "MIT"
},
+ "node_modules/nanoid": {
+ "version": "3.3.11",
+ "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.11.tgz",
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
"node_modules/natural-compare": {
"version": "1.4.0",
"resolved": "https://registry.npmmirror.com/natural-compare/-/natural-compare-1.4.0.tgz",
@@ -9726,7 +9971,6 @@
"version": "4.1.1",
"resolved": "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@@ -10279,7 +10523,6 @@
"version": "15.8.1",
"resolved": "https://registry.npmmirror.com/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
- "dev": true,
"license": "MIT",
"dependencies": {
"loose-envify": "^1.4.0",
@@ -10291,7 +10534,6 @@
"version": "16.13.1",
"resolved": "https://registry.npmmirror.com/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true,
"license": "MIT"
},
"node_modules/punycode": {
@@ -10337,6 +10579,24 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/query-string": {
+ "version": "7.1.3",
+ "resolved": "https://registry.npmmirror.com/query-string/-/query-string-7.1.3.tgz",
+ "integrity": "sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==",
+ "license": "MIT",
+ "dependencies": {
+ "decode-uri-component": "^0.2.2",
+ "filter-obj": "^1.1.0",
+ "split-on-first": "^1.0.0",
+ "strict-uri-encode": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/queue": {
"version": "6.0.2",
"resolved": "https://registry.npmmirror.com/queue/-/queue-6.0.2.tgz",
@@ -10432,6 +10692,18 @@
}
}
},
+ "node_modules/react-freeze": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmmirror.com/react-freeze/-/react-freeze-1.0.4.tgz",
+ "integrity": "sha512-r4F0Sec0BLxWicc7HEyo2x3/2icUTrRmDjaaRyzzn+7aDyFZliszMDOgLVwSnQnYENOlL1o569Ze2HZefk8clA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "peerDependencies": {
+ "react": ">=17.0.0"
+ }
+ },
"node_modules/react-is": {
"version": "17.0.2",
"resolved": "https://registry.npmmirror.com/react-is/-/react-is-17.0.2.tgz",
@@ -10497,6 +10769,167 @@
}
}
},
+ "node_modules/react-native-gesture-handler": {
+ "version": "2.27.1",
+ "resolved": "https://registry.npmmirror.com/react-native-gesture-handler/-/react-native-gesture-handler-2.27.1.tgz",
+ "integrity": "sha512-57TUWerhdz589OcDD21e/YlL923Ma4OIpyWsP0hy7gItBCPm5d7qIUW7Yo/cS2wo1qDdOhJaNlvlBD1lDou1fA==",
+ "license": "MIT",
+ "dependencies": {
+ "@egjs/hammerjs": "^2.0.17",
+ "hoist-non-react-statics": "^3.3.0",
+ "invariant": "^2.2.4"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/react-native-get-random-values": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmmirror.com/react-native-get-random-values/-/react-native-get-random-values-1.11.0.tgz",
+ "integrity": "sha512-4BTbDbRmS7iPdhYLRcz3PGFIpFJBwNZg9g42iwa2P6FOv9vZj/xJc678RZXnLNZzd0qd7Q3CCF6Yd+CU2eoXKQ==",
+ "license": "MIT",
+ "dependencies": {
+ "fast-base64-decode": "^1.0.0"
+ },
+ "peerDependencies": {
+ "react-native": ">=0.56"
+ }
+ },
+ "node_modules/react-native-is-edge-to-edge": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmmirror.com/react-native-is-edge-to-edge/-/react-native-is-edge-to-edge-1.2.1.tgz",
+ "integrity": "sha512-FLbPWl/MyYQWz+KwqOZsSyj2JmLKglHatd3xLZWskXOpRaio4LfEDEz8E/A6uD8QoTHW6Aobw1jbEwK7KMgR7Q==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/react-native-paper": {
+ "version": "5.14.5",
+ "resolved": "https://registry.npmmirror.com/react-native-paper/-/react-native-paper-5.14.5.tgz",
+ "integrity": "sha512-eaIH5bUQjJ/mYm4AkI6caaiyc7BcHDwX6CqNDi6RIxfxfWxROsHpll1oBuwn/cFvknvA8uEAkqLk/vzVihI3AQ==",
+ "license": "MIT",
+ "workspaces": [
+ "example",
+ "docs"
+ ],
+ "dependencies": {
+ "@callstack/react-theme-provider": "^3.0.9",
+ "color": "^3.1.2",
+ "use-latest-callback": "^0.2.3"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*",
+ "react-native-safe-area-context": "*"
+ }
+ },
+ "node_modules/react-native-paper/node_modules/color": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmmirror.com/color/-/color-3.2.1.tgz",
+ "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^1.9.3",
+ "color-string": "^1.6.0"
+ }
+ },
+ "node_modules/react-native-paper/node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/react-native-paper/node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "license": "MIT"
+ },
+ "node_modules/react-native-safe-area-context": {
+ "version": "5.5.2",
+ "resolved": "https://registry.npmmirror.com/react-native-safe-area-context/-/react-native-safe-area-context-5.5.2.tgz",
+ "integrity": "sha512-t4YVbHa9uAGf+pHMabGrb0uHrD5ogAusSu842oikJ3YKXcYp6iB4PTGl0EZNkUIR3pCnw/CXKn42OCfhsS0JIw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/react-native-screens": {
+ "version": "4.13.1",
+ "resolved": "https://registry.npmmirror.com/react-native-screens/-/react-native-screens-4.13.1.tgz",
+ "integrity": "sha512-EESsMAtyzYcL3gpAI2NKKiIo+Ew0fnX4P4b3Zy/+MTc6SJIo3foJbZwdIWd/SUBswOf7IYCvWBppg+D8tbwnsw==",
+ "license": "MIT",
+ "dependencies": {
+ "react-freeze": "^1.0.0",
+ "react-native-is-edge-to-edge": "^1.2.1",
+ "warn-once": "^0.1.0"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/react-native-vector-icons": {
+ "version": "10.2.0",
+ "resolved": "https://registry.npmmirror.com/react-native-vector-icons/-/react-native-vector-icons-10.2.0.tgz",
+ "integrity": "sha512-n5HGcxUuVaTf9QJPs/W22xQpC2Z9u0nb0KgLPnVltP8vdUvOp6+R26gF55kilP/fV4eL4vsAHUqUjewppJMBOQ==",
+ "license": "MIT",
+ "dependencies": {
+ "prop-types": "^15.7.2",
+ "yargs": "^16.1.1"
+ },
+ "bin": {
+ "fa-upgrade.sh": "bin/fa-upgrade.sh",
+ "fa5-upgrade": "bin/fa5-upgrade.sh",
+ "fa6-upgrade": "bin/fa6-upgrade.sh",
+ "generate-icon": "bin/generate-icon.js"
+ }
+ },
+ "node_modules/react-native-vector-icons/node_modules/cliui": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmmirror.com/cliui/-/cliui-7.0.4.tgz",
+ "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^7.0.0"
+ }
+ },
+ "node_modules/react-native-vector-icons/node_modules/yargs": {
+ "version": "16.2.0",
+ "resolved": "https://registry.npmmirror.com/yargs/-/yargs-16.2.0.tgz",
+ "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==",
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^7.0.2",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.0",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^20.2.2"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/react-native-vector-icons/node_modules/yargs-parser": {
+ "version": "20.2.9",
+ "resolved": "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-20.2.9.tgz",
+ "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/react-native/node_modules/ansi-styles": {
"version": "5.2.0",
"resolved": "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-5.2.0.tgz",
@@ -11231,6 +11664,21 @@
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"license": "ISC"
},
+ "node_modules/simple-swizzle": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmmirror.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
+ "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
+ "license": "MIT",
+ "dependencies": {
+ "is-arrayish": "^0.3.1"
+ }
+ },
+ "node_modules/simple-swizzle/node_modules/is-arrayish": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.3.2.tgz",
+ "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
+ "license": "MIT"
+ },
"node_modules/sisteransi": {
"version": "1.0.5",
"resolved": "https://registry.npmmirror.com/sisteransi/-/sisteransi-1.0.5.tgz",
@@ -11312,6 +11760,15 @@
"source-map": "^0.6.0"
}
},
+ "node_modules/split-on-first": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmmirror.com/split-on-first/-/split-on-first-1.1.0.tgz",
+ "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/sprintf-js/-/sprintf-js-1.0.3.tgz",
@@ -11389,6 +11846,15 @@
"node": ">= 0.4"
}
},
+ "node_modules/strict-uri-encode": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmmirror.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
+ "integrity": "sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.3.0.tgz",
@@ -12039,6 +12505,24 @@
"punycode": "^2.1.0"
}
},
+ "node_modules/use-latest-callback": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmmirror.com/use-latest-callback/-/use-latest-callback-0.2.4.tgz",
+ "integrity": "sha512-LS2s2n1usUUnDq4oVh1ca6JFX9uSqUncTfAm44WMg0v6TxL7POUTk1B044NH8TeLkFbNajIsgDHcgNpNzZucdg==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": ">=16.8"
+ }
+ },
+ "node_modules/use-sync-external-store": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmmirror.com/use-sync-external-store/-/use-sync-external-store-1.5.0.tgz",
+ "integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
+ }
+ },
"node_modules/util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -12055,6 +12539,19 @@
"node": ">= 0.4.0"
}
},
+ "node_modules/uuid": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmmirror.com/uuid/-/uuid-11.1.0.tgz",
+ "integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==",
+ "funding": [
+ "https://github.com/sponsors/broofa",
+ "https://github.com/sponsors/ctavan"
+ ],
+ "license": "MIT",
+ "bin": {
+ "uuid": "dist/esm/bin/uuid"
+ }
+ },
"node_modules/v8-to-istanbul": {
"version": "9.3.0",
"resolved": "https://registry.npmmirror.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz",
@@ -12095,6 +12592,12 @@
"makeerror": "1.0.12"
}
},
+ "node_modules/warn-once": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmmirror.com/warn-once/-/warn-once-0.1.1.tgz",
+ "integrity": "sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==",
+ "license": "MIT"
+ },
"node_modules/wcwidth": {
"version": "1.0.1",
"resolved": "https://registry.npmmirror.com/wcwidth/-/wcwidth-1.0.1.tgz",
diff --git a/package.json b/package.json
index 09f92f6..b75c2dc 100644
--- a/package.json
+++ b/package.json
@@ -10,9 +10,19 @@
"test": "jest"
},
"dependencies": {
+ "@react-native/new-app-screen": "0.80.1",
+ "@react-navigation/bottom-tabs": "^7.4.2",
+ "@react-navigation/native": "^7.1.14",
+ "@react-navigation/stack": "^7.4.2",
"react": "19.1.0",
"react-native": "0.80.1",
- "@react-native/new-app-screen": "0.80.1"
+ "react-native-gesture-handler": "^2.27.1",
+ "react-native-get-random-values": "^1.11.0",
+ "react-native-paper": "^5.14.5",
+ "react-native-safe-area-context": "^5.5.2",
+ "react-native-screens": "^4.13.1",
+ "react-native-vector-icons": "^10.2.0",
+ "uuid": "^11.1.0"
},
"devDependencies": {
"@babel/core": "^7.25.2",
@@ -28,6 +38,7 @@
"@types/jest": "^29.5.13",
"@types/react": "^19.1.0",
"@types/react-test-renderer": "^19.1.0",
+ "@types/uuid": "^10.0.0",
"eslint": "^8.19.0",
"jest": "^29.6.3",
"prettier": "2.8.8",
@@ -37,4 +48,4 @@
"engines": {
"node": ">=18"
}
-}
\ No newline at end of file
+}
diff --git a/src/components/BottomActionBar.tsx b/src/components/BottomActionBar.tsx
new file mode 100644
index 0000000..41c17a0
--- /dev/null
+++ b/src/components/BottomActionBar.tsx
@@ -0,0 +1,43 @@
+import React from 'react';
+import { View, Button, StyleSheet } from 'react-native';
+
+interface BottomActionBarProps {
+ onRun: () => void;
+ onSave: () => void;
+ onUndo: () => void;
+ onRestore: () => void;
+ onBack: () => void;
+ isSaveDisabled?: boolean;
+}
+
+const BottomActionBar: React.FC = ({
+ onRun,
+ onSave,
+ onUndo,
+ onRestore,
+ onBack,
+ isSaveDisabled = true,
+}) => {
+ return (
+
+
+
+
+
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flexDirection: 'row',
+ justifyContent: 'space-around',
+ padding: 16,
+ borderTopWidth: 1,
+ borderColor: '#ccc',
+ backgroundColor: '#f5f5f5',
+ },
+});
+
+export default BottomActionBar;
diff --git a/src/components/TaskCard.tsx b/src/components/TaskCard.tsx
new file mode 100644
index 0000000..af9afbd
--- /dev/null
+++ b/src/components/TaskCard.tsx
@@ -0,0 +1,43 @@
+import React from 'react';
+import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
+import { Task } from '../types/task';
+
+interface TaskCardProps {
+ task: Task;
+ onPress: (id: string) => void;
+}
+
+const TaskCard: React.FC = ({ task, onPress }) => {
+ return (
+ onPress(task.id)}>
+ {task.name}
+ 状态: {task.status}
+
+ );
+};
+
+const styles = StyleSheet.create({
+ card: {
+ backgroundColor: '#fff',
+ borderRadius: 8,
+ padding: 16,
+ margin: 8,
+ width: '45%',
+ elevation: 3,
+ shadowColor: '#000',
+ shadowOffset: { width: 0, height: 2 },
+ shadowOpacity: 0.1,
+ shadowRadius: 2,
+ },
+ title: {
+ fontSize: 16,
+ fontWeight: 'bold',
+ marginBottom: 8,
+ },
+ status: {
+ fontSize: 14,
+ color: '#666',
+ },
+});
+
+export default TaskCard;
diff --git a/src/components/TaskForm.tsx b/src/components/TaskForm.tsx
new file mode 100644
index 0000000..69d2d97
--- /dev/null
+++ b/src/components/TaskForm.tsx
@@ -0,0 +1,105 @@
+import React from 'react';
+import { View, Text, TextInput, StyleSheet, ScrollView } from 'react-native';
+import { Task, RobotAction } from '../types/task';
+
+interface TaskFormProps {
+ task: Task;
+ onTaskChange: (updatedTask: Task) => void;
+}
+
+const TaskForm: React.FC = ({ task, onTaskChange }) => {
+ const handleParamChange = (field: string, value: string) => {
+ const updatedTask = {
+ ...task,
+ parameters: {
+ ...task.parameters,
+ [field]: value,
+ },
+ };
+ onTaskChange(updatedTask);
+ };
+
+ return (
+
+
+ 任务名称
+ onTaskChange({ ...task, name: text })}
+ />
+
+
+
+ 起点
+ handleParamChange('startLocation', text)}
+ />
+
+
+
+ 终点
+ handleParamChange('endLocation', text)}
+ />
+
+
+
+ 途经点
+ handleParamChange('waypoint', text)}
+ placeholder="可选"
+ />
+
+
+
+ 机器人动作
+ {/* 在实际应用中,这里最好是一个下拉选择器 */}
+ handleParamChange('robotAction', text as RobotAction)}
+ />
+
+
+
+ 载荷
+ handleParamChange('payload', text)}
+ />
+
+
+ );
+};
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ padding: 16,
+ },
+ fieldContainer: {
+ marginBottom: 16,
+ },
+ label: {
+ fontSize: 16,
+ marginBottom: 8,
+ fontWeight: 'bold',
+ },
+ input: {
+ borderWidth: 1,
+ borderColor: '#ccc',
+ borderRadius: 4,
+ padding: 12,
+ fontSize: 16,
+ },
+});
+
+export default TaskForm;
diff --git a/src/data/mockData.ts b/src/data/mockData.ts
new file mode 100644
index 0000000..d7f84e0
--- /dev/null
+++ b/src/data/mockData.ts
@@ -0,0 +1,53 @@
+import { Task } from '../types/task';
+import { v4 as uuidv4 } from 'uuid';
+
+export const MOCK_TASKS: Task[] = [
+ {
+ id: uuidv4(),
+ name: '炉前缓存区到热处理上料交接区运输',
+ status: 'IDLE',
+ createdAt: new Date().toISOString(),
+ parameters: {
+ startLocation: '炉前缓存区',
+ endLocation: '热处理上料交接区',
+ robotAction: 'TRANSPORT',
+ payload: '满料架-A1',
+ },
+ },
+ {
+ id: uuidv4(),
+ name: '空料架到焊接空料架交接区运输',
+ status: 'RUNNING',
+ createdAt: new Date().toISOString(),
+ parameters: {
+ startLocation: '空料架缓存区',
+ endLocation: '焊接空料架交接区',
+ robotAction: 'TRANSPORT',
+ payload: '空料架-B2',
+ },
+ },
+ {
+ id: uuidv4(),
+ name: '热后空料架返回交接区',
+ status: 'COMPLETED',
+ createdAt: new Date().toISOString(),
+ parameters: {
+ startLocation: '热后区',
+ endLocation: '空料架缓存区',
+ robotAction: 'TRANSPORT',
+ payload: '空料架-C3',
+ },
+ },
+ {
+ id: uuidv4(),
+ name: 'ALD上料空车运输到空车区',
+ status: 'IDLE',
+ createdAt: new Date().toISOString(),
+ parameters: {
+ startLocation: 'ALD上料区',
+ endLocation: '空车区',
+ robotAction: 'TRANSPORT',
+ payload: '空车',
+ },
+ },
+];
diff --git a/src/navigation/AppNavigator.tsx b/src/navigation/AppNavigator.tsx
new file mode 100644
index 0000000..4ec44a4
--- /dev/null
+++ b/src/navigation/AppNavigator.tsx
@@ -0,0 +1,31 @@
+import React from 'react';
+import { createStackNavigator } from '@react-navigation/stack';
+import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
+import TaskListScreen from '../screens/TaskListScreen';
+import TaskEditScreen from '../screens/TaskEditScreen';
+import RunScreen from '../screens/RunScreen';
+import EditScreen from '../screens/EditScreen';
+import SettingsScreen from '../screens/SettingsScreen';
+
+const HomeStack = createStackNavigator();
+const Tab = createBottomTabNavigator();
+
+function HomeStackNavigator() {
+ return (
+
+
+
+
+ );
+}
+
+export default function AppNavigator() {
+ return (
+
+
+
+
+
+
+ );
+}
diff --git a/src/screens/EditScreen.tsx b/src/screens/EditScreen.tsx
new file mode 100644
index 0000000..7699e71
--- /dev/null
+++ b/src/screens/EditScreen.tsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import { StyleSheet, Text, View } from 'react-native';
+
+export default function EditScreen() {
+ return (
+
+ 编辑!
+
+ );
+}
+
+const styles = StyleSheet.create({
+ screenContainer: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+});
diff --git a/src/screens/HomeScreen.tsx b/src/screens/HomeScreen.tsx
new file mode 100644
index 0000000..f9018cc
--- /dev/null
+++ b/src/screens/HomeScreen.tsx
@@ -0,0 +1,32 @@
+import React from 'react';
+import { StyleSheet, Text, View, Button, SafeAreaView } from 'react-native';
+
+export default function HomeScreen() {
+ return (
+
+
+ {[...Array(8)].map((_, i) => (
+
+
+ ))}
+
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ marginTop: 20,
+ },
+ grid: {
+ flexDirection: 'row',
+ flexWrap: 'wrap',
+ justifyContent: 'center',
+ },
+ buttonContainer: {
+ width: '40%',
+ margin: 10,
+ },
+});
diff --git a/src/screens/RunScreen.tsx b/src/screens/RunScreen.tsx
new file mode 100644
index 0000000..4a7dbda
--- /dev/null
+++ b/src/screens/RunScreen.tsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import { StyleSheet, Text, View } from 'react-native';
+
+export default function RunScreen() {
+ return (
+
+ 运行!
+
+ );
+}
+
+const styles = StyleSheet.create({
+ screenContainer: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+});
diff --git a/src/screens/SettingsScreen.tsx b/src/screens/SettingsScreen.tsx
new file mode 100644
index 0000000..1e0eac2
--- /dev/null
+++ b/src/screens/SettingsScreen.tsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import { StyleSheet, Text, View } from 'react-native';
+
+export default function SettingsScreen() {
+ return (
+
+ 设置!
+
+ );
+}
+
+const styles = StyleSheet.create({
+ screenContainer: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ },
+});
diff --git a/src/screens/TaskEditScreen.tsx b/src/screens/TaskEditScreen.tsx
new file mode 100644
index 0000000..b1a8441
--- /dev/null
+++ b/src/screens/TaskEditScreen.tsx
@@ -0,0 +1,70 @@
+import React, { useState, useEffect } from 'react';
+import { View, StyleSheet, Alert } from 'react-native';
+import { useRoute, useNavigation } from '@react-navigation/native';
+import { RouteProp } from '@react-navigation/native';
+import TaskForm from '../components/TaskForm';
+import BottomActionBar from '../components/BottomActionBar';
+import { Task } from '../types/task';
+
+import { MOCK_TASKS } from '../data/mockData';
+
+type RootStackParamList = {
+ TaskEdit: { taskId: string };
+};
+
+type TaskEditRouteProp = RouteProp;
+
+export default function TaskEditScreen() {
+ const route = useRoute();
+ const navigation = useNavigation();
+ const { taskId } = route.params;
+
+ const [task, setTask] = useState(null);
+ const [isModified, setIsModified] = useState(false);
+
+ useEffect(() => {
+ // 根据taskId从模拟数据中查找任务
+ const foundTask = MOCK_TASKS.find(t => t.id === taskId);
+ if (foundTask) {
+ setTask(foundTask);
+ }
+ }, [taskId]);
+
+ const handleTaskChange = (updatedTask: Task) => {
+ setTask(updatedTask);
+ if (!isModified) {
+ setIsModified(true);
+ }
+ };
+
+ const handleSave = () => {
+ // 在这里处理保存逻辑,比如调用API
+ Alert.alert('已保存', `任务 "${task?.name}" 已被保存。`);
+ setIsModified(false);
+ };
+
+ if (!task) {
+ return null; // 或者显示一个加载指示器
+ }
+
+ return (
+
+
+ Alert.alert('运行', '开始运行任务...')}
+ onSave={handleSave}
+ onUndo={() => Alert.alert('撤销', '撤销更改...')}
+ onRestore={() => Alert.alert('恢复', '恢复到初始状态...')}
+ onBack={() => navigation.goBack()}
+ isSaveDisabled={!isModified}
+ />
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: '#fff',
+ },
+});
diff --git a/src/screens/TaskListScreen.tsx b/src/screens/TaskListScreen.tsx
new file mode 100644
index 0000000..2910fb8
--- /dev/null
+++ b/src/screens/TaskListScreen.tsx
@@ -0,0 +1,45 @@
+import React, { useState } from 'react';
+import { View, FlatList, StyleSheet } from 'react-native';
+import { useNavigation } from '@react-navigation/native';
+import { StackNavigationProp } from '@react-navigation/stack';
+import TaskCard from '../components/TaskCard';
+import { Task } from '../types/task';
+import { MOCK_TASKS } from '../data/mockData';
+
+type RootStackParamList = {
+ TaskList: undefined;
+ TaskEdit: { taskId: string };
+};
+
+type TaskListNavigationProp = StackNavigationProp;
+
+export default function TaskListScreen() {
+ const [tasks] = useState(MOCK_TASKS);
+ const navigation = useNavigation();
+
+ const handlePressTask = (taskId: string) => {
+ navigation.navigate('TaskEdit', { taskId });
+ };
+
+ return (
+
+ }
+ keyExtractor={item => item.id}
+ numColumns={2}
+ columnWrapperStyle={styles.row}
+ />
+
+ );
+}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: '#f5f5f5',
+ },
+ row: {
+ justifyContent: 'center',
+ },
+});
diff --git a/src/types/task.ts b/src/types/task.ts
new file mode 100644
index 0000000..27e568c
--- /dev/null
+++ b/src/types/task.ts
@@ -0,0 +1,23 @@
+// 机器人的具体动作,可以定义为枚举或联合类型
+export type RobotAction = 'PICKUP' | 'DROPOFF' | 'TRANSPORT' | 'WAIT';
+
+// 任务的状态
+export type TaskStatus = 'IDLE' | 'RUNNING' | 'COMPLETED' | 'ERROR';
+
+// 任务参数
+export interface TaskParameters {
+ startLocation: string; // 起点
+ endLocation: string; // 终点
+ waypoint?: string; // 途经点 (可选)
+ robotAction: RobotAction; // 机器人动作
+ payload: string; // 载荷,比如 '空料架' 或具体的物料ID
+}
+
+// 核心任务对象
+export interface Task {
+ id: string; // 唯一ID,例如使用 uuid
+ name: string; // 任务名称, e.g., "炉前缓存区到热处理上料交接区运输"
+ status: TaskStatus; // 任务当前状态
+ parameters: TaskParameters; // 任务的具体执行参数
+ createdAt: string; // 创建时间
+}