u
This commit is contained in:
1 parent
cc88205cba
commit
bddbb49e19
8 files changed
+238
-180
No files matched your search
@@ -20,6 +20,7 @@
|
||||
"@react-navigation/bottom-tabs": "^7.15.5",
|
||||
"@react-navigation/elements": "^2.9.10",
|
||||
"@react-navigation/native": "^7.1.33",
|
||||
"@yz1311/react-native-wheel-picker": "^0.4.5",
|
||||
"alova": "^3.5.1",
|
||||
"axios": "^1.15.0",
|
||||
"dayjs": "^1.11.20",
|
||||
@@ -50,6 +51,7 @@
|
||||
"react-dom": "19.2.0",
|
||||
"react-native": "0.83.4",
|
||||
"react-native-gesture-handler": "~2.30.0",
|
||||
"react-native-image-crop-picker": "^0.51.1",
|
||||
"react-native-keyboard-controller": "1.20.7",
|
||||
"react-native-reanimated": "4.2.1",
|
||||
"react-native-safe-area-context": "~5.6.2",
|
||||
@@ -69,7 +71,6 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "~19.2.2",
|
||||
"@yz1311/react-native-wheel-picker": "^0.4.5",
|
||||
"babel-preset-expo": "^55.0.16",
|
||||
"oxfmt": "^0.44.0",
|
||||
"oxlint": "^1.59.0",
|
||||
|
||||
Generated
+18
-36
@@ -29,6 +29,9 @@ importers:
|
||||
'@react-navigation/native':
|
||||
specifier: ^7.1.33
|
||||
version: 7.2.2(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)
|
||||
'@yz1311/react-native-wheel-picker':
|
||||
specifier: ^0.4.5
|
||||
version: 0.4.5(deprecated-react-native-prop-types@5.0.0)(moment@2.30.1)(react-native-modal@14.0.0-rc.1(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))
|
||||
alova:
|
||||
specifier: ^3.5.1
|
||||
version: 3.5.1
|
||||
@@ -119,6 +122,9 @@ importers:
|
||||
react-native-gesture-handler:
|
||||
specifier: ~2.30.0
|
||||
version: 2.30.1(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)
|
||||
react-native-image-crop-picker:
|
||||
specifier: ^0.51.1
|
||||
version: 0.51.1(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)
|
||||
react-native-keyboard-controller:
|
||||
specifier: 1.20.7
|
||||
version: 1.20.7(react-native-reanimated@4.2.1(react-native-worklets@0.7.2(@babel/core@7.29.0)(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)
|
||||
@@ -171,9 +177,6 @@ importers:
|
||||
'@types/react':
|
||||
specifier: ~19.2.2
|
||||
version: 19.2.14
|
||||
'@yz1311/react-native-wheel-picker':
|
||||
specifier: ^0.4.5
|
||||
version: 0.4.5(deprecated-react-native-prop-types@5.0.0)(moment@2.30.1)(react-native-modal@14.0.0-rc.1(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0))(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))
|
||||
babel-preset-expo:
|
||||
specifier: ^55.0.16
|
||||
version: 55.0.17(@babel/core@7.29.0)(@babel/runtime@7.29.2)(expo@55.0.15)(react-refresh@0.14.2)
|
||||
@@ -1028,56 +1031,48 @@ packages:
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@oxfmt/binding-linux-arm64-musl@0.44.0':
|
||||
resolution: {integrity: sha512-AlObQIXyVRZ96LbtVljtFq0JqH5B92NU+BQeDFrXWBUWlCKAM0wF5GLfIhCLT5kQ3Sl+U0YjRJ7Alqj5hGQaCg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@oxfmt/binding-linux-ppc64-gnu@0.44.0':
|
||||
resolution: {integrity: sha512-YcFE8/q/BbrCiIiM5piwbkA6GwJc5QqhMQp2yDrqQ2fuVkZ7CInb1aIijZ/k8EXc72qXMSwKpVlBv1w/MsGO/A==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@oxfmt/binding-linux-riscv64-gnu@0.44.0':
|
||||
resolution: {integrity: sha512-eOdzs6RqkRzuqNHUX5C8ISN5xfGh4xDww8OEd9YAmc3OWN8oAe5bmlIqQ+rrHLpv58/0BuU48bxkhnIGjA/ATQ==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@oxfmt/binding-linux-riscv64-musl@0.44.0':
|
||||
resolution: {integrity: sha512-YBgNTxntD/QvlFUfgvh8bEdwOhXiquX8gaofZJAwYa/Xp1S1DQrFVZEeck7GFktr24DztsSp8N8WtWCBwxs0Hw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@oxfmt/binding-linux-s390x-gnu@0.44.0':
|
||||
resolution: {integrity: sha512-GLIh1R6WHWshl/i4QQDNgj0WtT25aRO4HNUWEoitxiywyRdhTFmFEYT2rXlcl9U6/26vhmOqG5cRlMLG3ocaIA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@oxfmt/binding-linux-x64-gnu@0.44.0':
|
||||
resolution: {integrity: sha512-gZOpgTlOsLcLfAF9qgpTr7FIIFSKnQN3hDf/0JvQ4CIwMY7h+eilNjxq/CorqvYcEOu+LRt1W4ZS7KccEHLOdA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@oxfmt/binding-linux-x64-musl@0.44.0':
|
||||
resolution: {integrity: sha512-1CyS9JTB+pCUFYFI6pkQGGZaT/AY5gnhHVrQQLhFba6idP9AzVYm1xbdWfywoldTYvjxQJV6x4SuduCIfP3W+A==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@oxfmt/binding-openharmony-arm64@0.44.0':
|
||||
resolution: {integrity: sha512-bmEv70Ak6jLr1xotCbF5TxIKjsmQaiX+jFRtnGtfA03tJPf6VG3cKh96S21boAt3JZc+Vjx8PYcDuLj39vM2Pw==}
|
||||
@@ -1150,56 +1145,48 @@ packages:
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@oxlint/binding-linux-arm64-musl@1.60.0':
|
||||
resolution: {integrity: sha512-eDYDXZGhQAXyn6GwtwiX/qcLS0HlOLPJ/+iiIY8RYr+3P8oKBmgKxADLlniL6FtWfE7pPk7IGN9/xvDEvDvFeg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@oxlint/binding-linux-ppc64-gnu@1.60.0':
|
||||
resolution: {integrity: sha512-nxehly5XYBHUWI9VJX1bqCf9j/B43DaK/aS/T1fcxCpX3PA4Rm9BB54nPD1CKayT8xg6REN1ao+01hSRNgy8OA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@oxlint/binding-linux-riscv64-gnu@1.60.0':
|
||||
resolution: {integrity: sha512-j1qf/NaUfOWQutjeoooNG1Q0zsK0XGmSu1uDLq3cctquRF3j7t9Hxqf/76ehCc5GEUAanth2W4Fa+XT1RFg/nw==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@oxlint/binding-linux-riscv64-musl@1.60.0':
|
||||
resolution: {integrity: sha512-YELKPRefQ/q/h3RUmeRfPCUhh2wBvgV1RyZ/F9M9u8cDyXsQW2ojv1DeWQTt466yczDITjZnIOg/s05pk7Ve2A==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@oxlint/binding-linux-s390x-gnu@1.60.0':
|
||||
resolution: {integrity: sha512-JkO3C6Gki7Y6h/MiIkFKvHFOz98/YWvQ4WYbK9DLXACMP2rjULzkeGyAzorJE5S1dzLQGFgeqvN779kSFwoV1g==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@oxlint/binding-linux-x64-gnu@1.60.0':
|
||||
resolution: {integrity: sha512-XjKHdFVCpZZZSWBCKyyqCq65s2AKXykMXkjLoKYODrD+f5toLhlwsMESscu8FbgnJQ4Y/dpR/zdazsahmgBJIA==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@oxlint/binding-linux-x64-musl@1.60.0':
|
||||
resolution: {integrity: sha512-js29ZWIuPhNWzY8NC7KoffEMEeWG105vbmm+8EOJsC+T/jHBiKIJEUF78+F/IrgEWMMP9N0kRND4Pp75+xAhKg==}
|
||||
engines: {node: ^20.19.0 || >=22.12.0}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@oxlint/binding-openharmony-arm64@1.60.0':
|
||||
resolution: {integrity: sha512-H+PUITKHk04stFpWj3x3Kg08Afp/bcXSBi0EhasR5a0Vw7StXHTzdl655PUI0fB4qdh2Wsu6Dsi+3ACxPoyQnA==}
|
||||
@@ -1621,28 +1608,24 @@ packages:
|
||||
engines: {node: '>= 20'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@tailwindcss/oxide-linux-arm64-musl@4.2.1':
|
||||
resolution: {integrity: sha512-WZA0CHRL/SP1TRbA5mp9htsppSEkWuQ4KsSUumYQnyl8ZdT39ntwqmz4IUHGN6p4XdSlYfJwM4rRzZLShHsGAQ==}
|
||||
engines: {node: '>= 20'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-gnu@4.2.1':
|
||||
resolution: {integrity: sha512-qMFzxI2YlBOLW5PhblzuSWlWfwLHaneBE0xHzLrBgNtqN6mWfs+qYbhryGSXQjFYB1Dzf5w+LN5qbUTPhW7Y5g==}
|
||||
engines: {node: '>= 20'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@tailwindcss/oxide-linux-x64-musl@4.2.1':
|
||||
resolution: {integrity: sha512-5r1X2FKnCMUPlXTWRYpHdPYUY6a1Ar/t7P24OuiEdEOmms5lyqjDRvVY1yy9Rmioh+AunQ0rWiOTPE8F9A3v5g==}
|
||||
engines: {node: '>= 20'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@tailwindcss/oxide-wasm32-wasi@4.2.1':
|
||||
resolution: {integrity: sha512-MGFB5cVPvshR85MTJkEvqDUnuNoysrsRxd6vnk1Lf2tbiqNlXpHYZqkqOQalydienEWOHHFyyuTSYRsLfxFJ2Q==}
|
||||
@@ -2601,7 +2584,7 @@ packages:
|
||||
|
||||
glob@7.2.3:
|
||||
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
|
||||
deprecated: Glob versions prior to v9 are no longer supported
|
||||
deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
|
||||
|
||||
gopd@1.2.0:
|
||||
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
|
||||
@@ -2937,84 +2920,72 @@ packages:
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
lightningcss-linux-arm64-gnu@1.31.1:
|
||||
resolution: {integrity: sha512-WKyLWztD71rTnou4xAD5kQT+982wvca7E6QoLpoawZ1gP9JM0GJj4Tp5jMUh9B3AitHbRZ2/H3W5xQmdEOUlLg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
lightningcss-linux-arm64-gnu@1.32.0:
|
||||
resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
lightningcss-linux-arm64-musl@1.30.1:
|
||||
resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
lightningcss-linux-arm64-musl@1.31.1:
|
||||
resolution: {integrity: sha512-mVZ7Pg2zIbe3XlNbZJdjs86YViQFoJSpc41CbVmKBPiGmC4YrfeOyz65ms2qpAobVd7WQsbW4PdsSJEMymyIMg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
lightningcss-linux-arm64-musl@1.32.0:
|
||||
resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
lightningcss-linux-x64-gnu@1.30.1:
|
||||
resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
lightningcss-linux-x64-gnu@1.31.1:
|
||||
resolution: {integrity: sha512-xGlFWRMl+0KvUhgySdIaReQdB4FNudfUTARn7q0hh/V67PVGCs3ADFjw+6++kG1RNd0zdGRlEKa+T13/tQjPMA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
lightningcss-linux-x64-gnu@1.32.0:
|
||||
resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
lightningcss-linux-x64-musl@1.30.1:
|
||||
resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
lightningcss-linux-x64-musl@1.31.1:
|
||||
resolution: {integrity: sha512-eowF8PrKHw9LpoZii5tdZwnBcYDxRw2rRCyvAXLi34iyeYfqCQNA9rmUM0ce62NlPhCvof1+9ivRaTY6pSKDaA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
lightningcss-linux-x64-musl@1.32.0:
|
||||
resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
lightningcss-win32-arm64-msvc@1.30.1:
|
||||
resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==}
|
||||
@@ -3583,6 +3554,12 @@ packages:
|
||||
react-native: '*'
|
||||
react-native-svg: '>=9.7.0'
|
||||
|
||||
react-native-image-crop-picker@0.51.1:
|
||||
resolution: {integrity: sha512-GIFRyXJgv1dPceKd/hraK9q9V38v45rSg2ONR6RiSePcOJemkHpc/PMU86pq6lWPilDYHSxbZmea2pNMk85ayw==}
|
||||
peerDependencies:
|
||||
react: '*'
|
||||
react-native: '*'
|
||||
|
||||
react-native-is-edge-to-edge@1.2.1:
|
||||
resolution: {integrity: sha512-FLbPWl/MyYQWz+KwqOZsSyj2JmLKglHatd3xLZWskXOpRaio4LfEDEz8E/A6uD8QoTHW6Aobw1jbEwK7KMgR7Q==}
|
||||
peerDependencies:
|
||||
@@ -8092,6 +8069,11 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
react-native-image-crop-picker@0.51.1(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0):
|
||||
dependencies:
|
||||
react: 19.2.0
|
||||
react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0)
|
||||
|
||||
react-native-is-edge-to-edge@1.2.1(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0):
|
||||
dependencies:
|
||||
react: 19.2.0
|
||||
|
||||
@@ -1,13 +1,52 @@
|
||||
import React from "react";
|
||||
import LayoutView from "@/components/layout/view";
|
||||
import { Text } from "react-native";
|
||||
import { useState } from "react";
|
||||
import { Alert, Button, Image, View, StyleSheet } from "react-native";
|
||||
import * as ImagePicker from "expo-image-picker";
|
||||
|
||||
export default function ImagePickerExample() {
|
||||
const [image, setImage] = useState<string | null>(null);
|
||||
|
||||
const pickImage = async () => {
|
||||
// No permissions request is necessary for launching the image library.
|
||||
// Manually request permissions for videos on iOS when `allowsEditing` is set to `false`
|
||||
// and `videoExportPreset` is `'Passthrough'` (the default), ideally before launching the picker
|
||||
// so the app users aren't surprised by a system dialog after picking a video.
|
||||
// See "Invoke permissions for videos" sub section for more details.
|
||||
const permissionResult = await ImagePicker.requestMediaLibraryPermissionsAsync();
|
||||
|
||||
if (!permissionResult.granted) {
|
||||
Alert.alert("Permission required", "Permission to access the media library is required.");
|
||||
return;
|
||||
}
|
||||
|
||||
let result = await ImagePicker.launchImageLibraryAsync({
|
||||
mediaTypes: ["images", "videos"],
|
||||
allowsEditing: true,
|
||||
quality: 1,
|
||||
});
|
||||
|
||||
console.log(result);
|
||||
|
||||
if (!result.canceled) {
|
||||
setImage(result.assets[0].uri);
|
||||
}
|
||||
};
|
||||
|
||||
export default function Chat() {
|
||||
return (
|
||||
<LayoutView>
|
||||
<LayoutView.ScrollView>
|
||||
<Text className="text-base text-black">Hello</Text>
|
||||
</LayoutView.ScrollView>
|
||||
</LayoutView>
|
||||
<View style={styles.container}>
|
||||
<Button title="Pick an image from camera roll" onPress={pickImage} />
|
||||
{image && <Image source={{ uri: image }} style={styles.image} />}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
image: {
|
||||
width: 200,
|
||||
height: 200,
|
||||
},
|
||||
});
|
||||
@@ -65,7 +65,9 @@ export default function RootLayout() {
|
||||
headerShown: false,
|
||||
}}
|
||||
/>
|
||||
{!isDev && <StatusBar style={isDark ? "light" : "dark"} />}
|
||||
{/* {!isDev && <StatusBar style={isDark ? "light" : "dark"} />} */}
|
||||
|
||||
<StatusBar style={"auto"} />
|
||||
</HeroUINativeProvider>
|
||||
</KeyboardProvider>
|
||||
</ThemeProvider>
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
import React, { useState, useEffect, useMemo } from "react";
|
||||
import { DateRangePicker as YzDateRangePicker } from "@yz1311/react-native-wheel-picker";
|
||||
import { BottomSheet, Button } from "heroui-native";
|
||||
import { View, Text } from "react-native";
|
||||
import dayjs from "dayjs";
|
||||
import { toDate } from "@/utils/time";
|
||||
|
||||
interface DateRangePickerProps {
|
||||
startDate: Date | string;
|
||||
endDate: Date | string;
|
||||
show?: boolean;
|
||||
onClose?: () => void;
|
||||
onConfirm?: (start: string, end: string) => void;
|
||||
}
|
||||
|
||||
export default function DateRangePicker({
|
||||
startDate,
|
||||
endDate,
|
||||
show = false,
|
||||
onClose,
|
||||
onConfirm,
|
||||
}: DateRangePickerProps) {
|
||||
const [tempStart, setTempStart] = useState<Date | undefined>(() => toDate(startDate));
|
||||
const [tempEnd, setTempEnd] = useState<Date | undefined>(() => toDate(endDate));
|
||||
|
||||
useEffect(() => {
|
||||
setTempStart(toDate(startDate));
|
||||
setTempEnd(toDate(endDate));
|
||||
}, [startDate, endDate]);
|
||||
|
||||
const isOpen = show;
|
||||
|
||||
const handleClose = () => {
|
||||
onClose?.();
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
setTempStart(toDate(startDate));
|
||||
setTempEnd(toDate(endDate));
|
||||
handleClose();
|
||||
};
|
||||
|
||||
const handleConfirm = () => {
|
||||
const start = dayjs(tempStart).format("YYYY-MM-DD");
|
||||
const end = dayjs(tempEnd).format("YYYY-MM-DD");
|
||||
|
||||
onConfirm?.(start, end);
|
||||
handleClose();
|
||||
};
|
||||
|
||||
const key = useMemo(
|
||||
() => `${dayjs(startDate).format("YYYY-MM-DD")}_${dayjs(endDate).format("YYYY-MM-DD")}`,
|
||||
[startDate, endDate],
|
||||
);
|
||||
|
||||
return (
|
||||
<BottomSheet
|
||||
isOpen={isOpen}
|
||||
onOpenChange={(v) => {
|
||||
if (!v) handleClose();
|
||||
}}
|
||||
>
|
||||
<BottomSheet.Portal>
|
||||
<BottomSheet.Overlay />
|
||||
|
||||
<BottomSheet.Content>
|
||||
<View style={{ width: "100%" }}>
|
||||
{/* Header */}
|
||||
<View className="flex-row items-center justify-between w-full">
|
||||
<Button size="sm" variant="tertiary" onPress={handleCancel}>
|
||||
取消
|
||||
</Button>
|
||||
|
||||
<Text className="text-gray-800 text-base font-medium">选择日期区间</Text>
|
||||
|
||||
<Button size="sm" onPress={handleConfirm}>
|
||||
确认
|
||||
</Button>
|
||||
</View>
|
||||
|
||||
{/* Range Picker */}
|
||||
<YzDateRangePicker
|
||||
key={`${dayjs(startDate).valueOf()}_${dayjs(endDate).valueOf()}`}
|
||||
showHeader={false}
|
||||
startDate={tempStart}
|
||||
endDate={tempEnd}
|
||||
onValueChange={(start: Date, end: Date) => {
|
||||
setTempStart(start);
|
||||
setTempEnd(end);
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</BottomSheet.Content>
|
||||
</BottomSheet.Portal>
|
||||
</BottomSheet>
|
||||
);
|
||||
}
|
||||
@@ -3,9 +3,11 @@ import dayjs from "dayjs";
|
||||
import { BottomSheet, Button } from "heroui-native";
|
||||
import { useState, useEffect } from "react";
|
||||
import { toDate } from "@/utils/time";
|
||||
import { View, Text } from "react-native";
|
||||
import { View } from "react-native";
|
||||
import { CheckIcon } from "lucide-react-native";
|
||||
|
||||
export type DatePickerMode = "year" | "month" | "date" | "time" | "datetime";
|
||||
|
||||
export type DateFormatType = "YYYY" | "YYYY-MM" | "YYYY-MM-DD" | "HH:mm:ss" | "YYYY-MM-DD HH:mm";
|
||||
|
||||
interface DatePickerProps {
|
||||
@@ -25,7 +27,7 @@ const defaultFormatMap: Record<DatePickerMode, DateFormatType> = {
|
||||
datetime: "YYYY-MM-DD HH:mm",
|
||||
};
|
||||
|
||||
export default function DatePicker({
|
||||
export default function DateTime({
|
||||
value,
|
||||
show = false,
|
||||
onClose,
|
||||
@@ -33,62 +35,46 @@ export default function DatePicker({
|
||||
mode = "date",
|
||||
format,
|
||||
}: DatePickerProps) {
|
||||
const [tempDate, setTempDate] = useState<Date>(toDate(value));
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const finalFormat = format ?? defaultFormatMap[mode] ?? "YYYY-MM-DD";
|
||||
|
||||
const finalFormat = format || defaultFormatMap[mode];
|
||||
const [tempDate, setTempDate] = useState<Date>(toDate(value) ?? new Date());
|
||||
|
||||
useEffect(() => {
|
||||
if (show) {
|
||||
setTempDate(toDate(value));
|
||||
setIsOpen(true);
|
||||
} else {
|
||||
setIsOpen(false);
|
||||
setTempDate(toDate(value) ?? new Date());
|
||||
}
|
||||
}, [show, value]);
|
||||
|
||||
const handleClose = () => {
|
||||
setIsOpen(false);
|
||||
onClose?.();
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
setTempDate(toDate(value));
|
||||
handleClose();
|
||||
};
|
||||
|
||||
const handleConfirm = () => {
|
||||
const formatted = dayjs(tempDate).format(finalFormat);
|
||||
onConfirm?.(formatted);
|
||||
if (!tempDate) return;
|
||||
|
||||
onConfirm?.(dayjs(tempDate).format(finalFormat));
|
||||
handleClose();
|
||||
};
|
||||
|
||||
return (
|
||||
<BottomSheet isOpen={isOpen} onOpenChange={(v) => !v && handleClose()}>
|
||||
<BottomSheet isOpen={show} onOpenChange={(v) => !v && handleClose()}>
|
||||
<BottomSheet.Portal>
|
||||
<BottomSheet.Overlay />
|
||||
|
||||
<BottomSheet.Content>
|
||||
<View style={{ width: "100%", alignItems: "center" }}>
|
||||
<View className="flex-row items-center justify-between w-full">
|
||||
<Button size="sm" variant="tertiary" onPress={handleCancel}>
|
||||
取消
|
||||
</Button>
|
||||
|
||||
<Text className="text-gray-800 text-base font-medium">选择时间</Text>
|
||||
|
||||
<Button size="sm" onPress={handleConfirm}>
|
||||
确认
|
||||
</Button>
|
||||
</View>
|
||||
<YzDatePicker
|
||||
showHeader={false}
|
||||
date={tempDate}
|
||||
mode={mode}
|
||||
isModal={false}
|
||||
onPickerCancel={handleCancel}
|
||||
onPickerConfirm={handleConfirm}
|
||||
onDateChange={(d: Date) => setTempDate(d)}
|
||||
/>
|
||||
|
||||
<Button className="w-full" onPress={handleConfirm}>
|
||||
<CheckIcon color="#fff" />
|
||||
<Button.Label>确认</Button.Label>
|
||||
</Button>
|
||||
</View>
|
||||
</BottomSheet.Content>
|
||||
</BottomSheet.Portal>
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { DatePicker as YzDatePicker } from "@yz1311/react-native-wheel-picker";
|
||||
import { BottomSheet, Button } from "heroui-native";
|
||||
import { View, Text, TouchableOpacity } from "react-native";
|
||||
import dayjs from "dayjs";
|
||||
import { toDate } from "@/utils/time";
|
||||
import { CheckIcon } from "lucide-react-native";
|
||||
|
||||
interface DateRangePickerProps {
|
||||
startDate?: Date | string;
|
||||
endDate?: Date | string;
|
||||
show?: boolean;
|
||||
onClose?: () => void;
|
||||
onConfirm?: (start: string, end: string) => void;
|
||||
}
|
||||
|
||||
export default function DateTimeRange({
|
||||
startDate,
|
||||
endDate,
|
||||
show = false,
|
||||
onClose,
|
||||
onConfirm,
|
||||
}: DateRangePickerProps) {
|
||||
const [tempStart, setTempStart] = useState<Date | undefined>(undefined);
|
||||
const [tempEnd, setTempEnd] = useState<Date | undefined>(undefined);
|
||||
|
||||
const [active, setActive] = useState<"start" | "end">("start");
|
||||
|
||||
// ✅ 每次打开重置
|
||||
useEffect(() => {
|
||||
if (show) {
|
||||
setTempStart(toDate(startDate) ?? new Date());
|
||||
setTempEnd(toDate(endDate) ?? undefined);
|
||||
setActive("start");
|
||||
}
|
||||
}, [show, startDate, endDate]);
|
||||
|
||||
const handleClose = () => {
|
||||
onClose?.();
|
||||
};
|
||||
|
||||
const handleConfirm = () => {
|
||||
if (!tempStart) return;
|
||||
|
||||
onConfirm?.(
|
||||
dayjs(tempStart).format("YYYY-MM-DD"),
|
||||
tempEnd ? dayjs(tempEnd).format("YYYY-MM-DD") : "",
|
||||
);
|
||||
|
||||
handleClose();
|
||||
};
|
||||
|
||||
// ❗ start 修改 → 清空 end
|
||||
const handleStartChange = (date: Date) => {
|
||||
setTempStart(date);
|
||||
setTempEnd(undefined);
|
||||
};
|
||||
|
||||
// ❗ end 修改
|
||||
const handleEndChange = (date: Date) => {
|
||||
if (!tempStart) return;
|
||||
setTempEnd(date);
|
||||
};
|
||||
|
||||
const formatDate = (date?: Date) => (date ? dayjs(date).format("YYYY-MM-DD") : "请选择");
|
||||
|
||||
return (
|
||||
<BottomSheet isOpen={show} onOpenChange={(v) => !v && handleClose()}>
|
||||
<BottomSheet.Portal>
|
||||
<BottomSheet.Overlay />
|
||||
|
||||
<BottomSheet.Content>
|
||||
<View className="w-full items-center">
|
||||
{/* 顶部选择区 */}
|
||||
<View className="flex-row items-center justify-between w-full">
|
||||
{/* start */}
|
||||
<TouchableOpacity className="flex-1 items-center" onPress={() => setActive("start")}>
|
||||
<Text>开始时间</Text>
|
||||
<Text
|
||||
className={`text-base ${
|
||||
active === "start" ? "text-accent font-bold" : "text-gray-400"
|
||||
}`}
|
||||
>
|
||||
{formatDate(tempStart)}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<View className="w-px h-10 bg-gray-300 mx-2" />
|
||||
|
||||
{/* end */}
|
||||
<TouchableOpacity
|
||||
className="flex-1 items-center"
|
||||
style={{ opacity: tempStart ? 1 : 0.4 }}
|
||||
disabled={!tempStart}
|
||||
onPress={() => {
|
||||
if (!tempStart) return;
|
||||
|
||||
// ✅ 核心优化:未选 end → 自动补 start
|
||||
if (!tempEnd) {
|
||||
setTempEnd(tempStart);
|
||||
}
|
||||
|
||||
setActive("end");
|
||||
}}
|
||||
>
|
||||
<Text>结束时间</Text>
|
||||
<Text
|
||||
className={`text-base ${
|
||||
active === "end" ? "text-accent font-bold" : "text-gray-400"
|
||||
}`}
|
||||
>
|
||||
{formatDate(tempEnd)}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* Picker */}
|
||||
{active === "start" ? (
|
||||
<YzDatePicker
|
||||
showHeader={false}
|
||||
mode="date"
|
||||
date={tempStart ?? new Date()}
|
||||
onDateChange={handleStartChange}
|
||||
/>
|
||||
) : (
|
||||
<YzDatePicker
|
||||
showHeader={false}
|
||||
mode="date"
|
||||
date={tempEnd ?? tempStart ?? new Date()}
|
||||
minDate={tempStart}
|
||||
onDateChange={handleEndChange}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* confirm */}
|
||||
<Button className="w-full" onPress={handleConfirm}>
|
||||
<CheckIcon color="#fff" />
|
||||
<Button.Label>确认</Button.Label>
|
||||
</Button>
|
||||
</View>
|
||||
</BottomSheet.Content>
|
||||
</BottomSheet.Portal>
|
||||
</BottomSheet>
|
||||
);
|
||||
}
|
||||
@@ -33,14 +33,14 @@ export function getCurrentYear(): string {
|
||||
}
|
||||
|
||||
/** 字符串 / 数字 / Date → Date(无效返回 null) */
|
||||
export function toDate(input: string | number | Date | undefined | null): Date {
|
||||
if (!input) return new Date();
|
||||
export function toDate(input: string | number | Date | undefined | null): Date | undefined {
|
||||
if (!input) return undefined;
|
||||
|
||||
if (input instanceof Date) return input;
|
||||
|
||||
const d = dayjs(input);
|
||||
return d.isValid() ? d.toDate() : new Date();
|
||||
return d.isValid() ? d.toDate() : undefined;
|
||||
}
|
||||
|
||||
/** Date → YYYY-MM-DD */
|
||||
export function toDateString(date: string | number | Date): string {
|
||||
const d = dayjs(toDate(date));
|
||||
|
||||
Reference in new issue
Block a user