u
This commit is contained in:
1 parent
e893ef2e48
commit
b6415c0d65
25 files changed
+1495
-112
No files matched your search
@@ -46,10 +46,12 @@
|
||||
"react-dom": "19.2.0",
|
||||
"react-native": "0.83.4",
|
||||
"react-native-gesture-handler": "~2.30.0",
|
||||
"react-native-keyboard-controller": "1.20.7",
|
||||
"react-native-reanimated": "4.2.1",
|
||||
"react-native-safe-area-context": "~5.6.2",
|
||||
"react-native-screens": "~4.23.0",
|
||||
"react-native-shadow-2": "^7.1.2",
|
||||
"react-native-sortables": "^1.9.4",
|
||||
"react-native-svg": "15.15.3",
|
||||
"react-native-web": "~0.21.0",
|
||||
"react-native-worklets": "0.7.2",
|
||||
|
||||
Generated
+86
-1
@@ -107,6 +107,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-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)
|
||||
react-native-reanimated:
|
||||
specifier: 4.2.1
|
||||
version: 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)
|
||||
@@ -119,6 +122,9 @@ importers:
|
||||
react-native-shadow-2:
|
||||
specifier: ^7.1.2
|
||||
version: 7.1.2(react-native-svg@15.15.3(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-native-sortables:
|
||||
specifier: ^1.9.4
|
||||
version: 1.9.4(react-native-gesture-handler@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-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)
|
||||
react-native-svg:
|
||||
specifier: 15.15.3
|
||||
version: 15.15.3(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0)
|
||||
@@ -1004,48 +1010,56 @@ 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==}
|
||||
@@ -1118,48 +1132,56 @@ 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==}
|
||||
@@ -1578,24 +1600,28 @@ 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==}
|
||||
@@ -2513,7 +2539,7 @@ packages:
|
||||
|
||||
glob@7.2.3:
|
||||
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
|
||||
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
|
||||
deprecated: Glob versions prior to v9 are no longer supported
|
||||
|
||||
gopd@1.2.0:
|
||||
resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==}
|
||||
@@ -2846,72 +2872,84 @@ 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==}
|
||||
@@ -3454,6 +3492,15 @@ packages:
|
||||
react: '*'
|
||||
react-native: '*'
|
||||
|
||||
react-native-haptic-feedback@3.0.0:
|
||||
resolution: {integrity: sha512-yxBQFHhXU8S0xupGtzDRToGw5yMWezUdLzxtlx2Oi9YpjPwprWZWCw8foPt0S2t84B0ZikzZYyOHiMSXIelUxg==}
|
||||
peerDependencies:
|
||||
react: '>=18.0.0'
|
||||
react-native: '>=0.71.0'
|
||||
peerDependenciesMeta:
|
||||
react:
|
||||
optional: true
|
||||
|
||||
react-native-iconfont-cli@2.2.4:
|
||||
resolution: {integrity: sha512-qTjfHG2f/sc3/YKWZJvIJk/SwiTu8C9/SvtoLxRX+GM/6pvOJq0ge6rcV3vTh4s3QJDuNDOD6+a4hGD6vv2vSg==}
|
||||
hasBin: true
|
||||
@@ -3474,6 +3521,13 @@ packages:
|
||||
react: '*'
|
||||
react-native: '*'
|
||||
|
||||
react-native-keyboard-controller@1.20.7:
|
||||
resolution: {integrity: sha512-G8S5jz1FufPrcL1vPtReATx+jJhT/j+sTqxMIb30b1z7cYEfMlkIzOCyaHgf6IMB2KA9uBmnA5M6ve2A9Ou4kw==}
|
||||
peerDependencies:
|
||||
react: '*'
|
||||
react-native: '*'
|
||||
react-native-reanimated: '>=3.0.0'
|
||||
|
||||
react-native-reanimated@4.2.1:
|
||||
resolution: {integrity: sha512-/NcHnZMyOvsD/wYXug/YqSKw90P9edN0kEPL5lP4PFf1aQ4F1V7MKe/E0tvfkXKIajy3Qocp5EiEnlcrK/+BZg==}
|
||||
peerDependencies:
|
||||
@@ -3499,6 +3553,14 @@ packages:
|
||||
react-native: '*'
|
||||
react-native-svg: '>=12.1.0'
|
||||
|
||||
react-native-sortables@1.9.4:
|
||||
resolution: {integrity: sha512-a6hxT+gl14HA5Sm8UiLXJqF8KMEQVa+mUJd75OnzoVsmrxUDtjAatlMdV0kI9qTQDT/ZSFLPRmdUhOR762IA4g==}
|
||||
peerDependencies:
|
||||
react: '*'
|
||||
react-native: '*'
|
||||
react-native-gesture-handler: '>=2.0.0'
|
||||
react-native-reanimated: '>=3.0.0'
|
||||
|
||||
react-native-svg@15.15.3:
|
||||
resolution: {integrity: sha512-/k4KYwPBLGcx2f5d4FjE+vCScK7QOX14cl2lIASJ28u4slHHtIhL0SZKU7u9qmRBHxTCKPoPBtN6haT1NENJNA==}
|
||||
peerDependencies:
|
||||
@@ -7868,6 +7930,13 @@ snapshots:
|
||||
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-haptic-feedback@3.0.0(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-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0)
|
||||
optionalDependencies:
|
||||
react: 19.2.0
|
||||
optional: true
|
||||
|
||||
react-native-iconfont-cli@2.2.4(react-native-svg@15.15.3(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):
|
||||
dependencies:
|
||||
colors: 1.4.0
|
||||
@@ -7893,6 +7962,13 @@ snapshots:
|
||||
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-keyboard-controller@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):
|
||||
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.3.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-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-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):
|
||||
dependencies:
|
||||
react: 19.2.0
|
||||
@@ -7919,6 +7995,15 @@ snapshots:
|
||||
react-native: 0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0)
|
||||
react-native-svg: 15.15.3(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-sortables@1.9.4(react-native-gesture-handler@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-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):
|
||||
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-gesture-handler: 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-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)
|
||||
optionalDependencies:
|
||||
react-native-haptic-feedback: 3.0.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-svg@15.15.3(react-native@0.83.4(@babel/core@7.29.0)(@types/react@19.2.14)(react@19.2.0))(react@19.2.0):
|
||||
dependencies:
|
||||
css-select: 5.2.2
|
||||
|
||||
@@ -20,9 +20,9 @@ const tabs: TabbarItem[] = [
|
||||
icon: HomeIcon,
|
||||
},
|
||||
{
|
||||
id: "/chat",
|
||||
title: "聊天",
|
||||
icon: MessageCircleIcon,
|
||||
id: "/space",
|
||||
title: "空间",
|
||||
icon: EarthIcon,
|
||||
},
|
||||
{
|
||||
id: "/tools",
|
||||
@@ -31,9 +31,9 @@ const tabs: TabbarItem[] = [
|
||||
isCenter: true,
|
||||
},
|
||||
{
|
||||
id: "/space",
|
||||
title: "空间",
|
||||
icon: EarthIcon,
|
||||
id: "/chat",
|
||||
title: "聊天",
|
||||
icon: MessageCircleIcon,
|
||||
},
|
||||
{
|
||||
id: "/my",
|
||||
|
||||
@@ -1,36 +1,43 @@
|
||||
import { Button, Dialog } from "heroui-native";
|
||||
import { Button, Toast, useToast, useThemeColor } from "heroui-native";
|
||||
import { View } from "react-native";
|
||||
import { useState } from "react";
|
||||
|
||||
export default function DialogExample() {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
export default function ToastExample() {
|
||||
const { toast } = useToast();
|
||||
const themeColorForeground = useThemeColor("foreground");
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button variant="primary" onPress={() => {
|
||||
setIsOpen(true)
|
||||
}}>Open Dialog</Button>
|
||||
<View className="gap-4 p-4">
|
||||
<Button
|
||||
onPress={() =>
|
||||
toast.show({
|
||||
variant: "success",
|
||||
label: "You have upgraded your plan",
|
||||
description: "You can continue using HeroUI Chat",
|
||||
actionLabel: "Close",
|
||||
onActionPress: ({ hide }) => hide(),
|
||||
})
|
||||
}
|
||||
>
|
||||
Show Success Toast
|
||||
</Button>
|
||||
|
||||
<Dialog isOpen={isOpen} onOpenChange={setIsOpen}>
|
||||
<Dialog.Portal>
|
||||
<Dialog.Overlay />
|
||||
<Dialog.Content>
|
||||
<Dialog.Close variant="ghost" />
|
||||
<View className="mb-5 gap-1.5">
|
||||
<Dialog.Title>Confirm Action</Dialog.Title>
|
||||
<Dialog.Description>
|
||||
Are you sure you want to proceed with this action? This cannot be undone.
|
||||
</Dialog.Description>
|
||||
</View>
|
||||
<View className="flex-row justify-end gap-3">
|
||||
<Button variant="ghost" size="sm" onPress={() => setIsOpen(false)}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button size="sm">Confirm</Button>
|
||||
</View>
|
||||
</Dialog.Content>
|
||||
</Dialog.Portal>
|
||||
</Dialog>
|
||||
</>
|
||||
<Button
|
||||
onPress={() =>
|
||||
toast.show({
|
||||
duration: 0,
|
||||
component: (props) => (
|
||||
<Toast variant="accent" {...props}>
|
||||
<Toast.Title>Custom Toast</Toast.Title>
|
||||
<Toast.Description>This uses a custom component</Toast.Description>
|
||||
<Toast.Action onPress={() => props.hide()}>Undo</Toast.Action>
|
||||
<Toast.Close className="absolute top-0 right-0" />
|
||||
</Toast>
|
||||
),
|
||||
})
|
||||
}
|
||||
>
|
||||
Show Custom Toast
|
||||
</Button>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -1,13 +1,566 @@
|
||||
import React from "react";
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import LayoutView from "@/components/layout/view";
|
||||
import { Text } from "react-native";
|
||||
import { View, Text } from "react-native";
|
||||
import {
|
||||
Button,
|
||||
Separator,
|
||||
Spinner,
|
||||
Chip,
|
||||
BottomSheet,
|
||||
Label,
|
||||
TextField,
|
||||
Input,
|
||||
InputOTP,
|
||||
type InputOTPRef,
|
||||
PressableFeedback,
|
||||
useBottomSheetAwareHandlers,
|
||||
} from "heroui-native";
|
||||
import { PlusIcon, HousePlusIcon, GripIcon } from "lucide-react-native";
|
||||
import { useUserStore } from "@/store";
|
||||
import { getUniqueIdApi, loadDataApi, loadDataBySqlApi, saveDataApi } from "@/request/api";
|
||||
import EmptyState from "@/components/EmptyStatus";
|
||||
import Sortable from "react-native-sortables";
|
||||
import { useSpaceStore } from "@/store";
|
||||
import { useRouter } from "expo-router";
|
||||
import { UserRoundIcon, UsersRoundIcon } from "lucide-react-native";
|
||||
import { toast } from "sonner-native";
|
||||
import { FadeIn } from "react-native-reanimated";
|
||||
import { generateCode } from "@/utils/common";
|
||||
|
||||
export default function Space() {
|
||||
const router = useRouter();
|
||||
const userStore = useUserStore();
|
||||
const spaceStore = useSpaceStore();
|
||||
|
||||
const ITEM_HEIGHT = 64;
|
||||
|
||||
const [spaces, setSpaces] = useState<any[]>([]);
|
||||
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
// 加入
|
||||
const [showJoin, setShowJoin] = useState(false);
|
||||
const [joinLoading, setJoinLoading] = useState(false);
|
||||
const [joinForm, setJoinForm] = useState({
|
||||
invite_code: "",
|
||||
});
|
||||
const joinInputRef = useRef<InputOTPRef>(null);
|
||||
|
||||
// 新建
|
||||
const [showCreate, setShowCreate] = useState(false);
|
||||
const [createForm, setCreateForm] = useState({
|
||||
name: "",
|
||||
});
|
||||
const [createLoading, setCreateLoading] = useState(false);
|
||||
const createInputRef = useRef<any>(null);
|
||||
|
||||
const { onFocus, onBlur } = useBottomSheetAwareHandlers();
|
||||
|
||||
useEffect(() => {
|
||||
if (showCreate) {
|
||||
setTimeout(() => {
|
||||
createInputRef.current?.focus();
|
||||
}, 0);
|
||||
}
|
||||
}, [showCreate]);
|
||||
|
||||
useEffect(() => {
|
||||
if (showJoin) {
|
||||
setTimeout(() => {
|
||||
joinInputRef.current?.focus();
|
||||
}, 0);
|
||||
}
|
||||
}, [showJoin]);
|
||||
|
||||
useEffect(() => {
|
||||
listUserSpaces();
|
||||
}, []);
|
||||
|
||||
function listUserSpaces(loading = true) {
|
||||
if (loading) {
|
||||
setLoading(true);
|
||||
}
|
||||
|
||||
loadDataApi({
|
||||
view_name: "v_user_spaces",
|
||||
search_condition: `v_user_id = ?`,
|
||||
search_columns: [],
|
||||
order_by: "",
|
||||
args: [userStore.userInfo.id],
|
||||
}).then((res) => {
|
||||
if (res.isSuccess) {
|
||||
setSpaces(res.data);
|
||||
if (loading) {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function handleCreate() {
|
||||
if (createLoading) return;
|
||||
|
||||
if (createForm.name === "") {
|
||||
toast.warning("空间名称不能为空");
|
||||
return;
|
||||
}
|
||||
|
||||
setCreateLoading(true);
|
||||
|
||||
try {
|
||||
let inviteCode = "";
|
||||
let isExist = true;
|
||||
|
||||
// 循环生成直到不存在
|
||||
while (isExist) {
|
||||
inviteCode = generateCode(6);
|
||||
|
||||
const res = await loadDataBySqlApi({
|
||||
sql: `SELECT 1 FROM space WHERE invite_code = ? LIMIT 1`,
|
||||
args: [inviteCode],
|
||||
});
|
||||
|
||||
if (!res.isSuccess) {
|
||||
throw new Error("校验邀请码失败");
|
||||
}
|
||||
|
||||
isExist = res.data.length > 0;
|
||||
}
|
||||
|
||||
// 设置是否是默认空间
|
||||
let isDefault = false;
|
||||
|
||||
const defaultRes = await loadDataApi({
|
||||
view_name: "v_user_spaces",
|
||||
search_condition: `v_user_id = ?`,
|
||||
search_columns: ["v_is_default"],
|
||||
order_by: "",
|
||||
args: [userStore.userInfo.id],
|
||||
});
|
||||
|
||||
if (!defaultRes.isSuccess) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (defaultRes.data.length == 0) {
|
||||
isDefault = true;
|
||||
}
|
||||
|
||||
// 创建
|
||||
const autoRes = await getUniqueIdApi(2);
|
||||
if (!autoRes.isSuccess) {
|
||||
return;
|
||||
}
|
||||
|
||||
const spaceId = autoRes.data[0];
|
||||
const spaceMemberId = autoRes.data[1];
|
||||
|
||||
// 插入空间
|
||||
const requestData = [];
|
||||
|
||||
requestData.push({
|
||||
table_name: "space",
|
||||
key_field: "id",
|
||||
inserts: [
|
||||
{
|
||||
id: spaceId,
|
||||
name: createForm.name,
|
||||
invite_code: inviteCode,
|
||||
owner_id: userStore.userInfo.id,
|
||||
status: 0,
|
||||
},
|
||||
],
|
||||
updates: [],
|
||||
deletes: [],
|
||||
});
|
||||
|
||||
// 插入空间用户
|
||||
requestData.push({
|
||||
table_name: "space_member",
|
||||
key_field: "id",
|
||||
inserts: [
|
||||
{
|
||||
id: spaceMemberId,
|
||||
space_id: spaceId,
|
||||
user_id: userStore.userInfo.id,
|
||||
role: 0,
|
||||
is_default: isDefault ? 1 : 0,
|
||||
sort_number: defaultRes.data.length,
|
||||
member_name: userStore.userInfo.nickname,
|
||||
},
|
||||
],
|
||||
updates: [],
|
||||
deletes: [],
|
||||
});
|
||||
|
||||
const saveRes = await saveDataApi(requestData);
|
||||
|
||||
if (saveRes.isSuccess) {
|
||||
toast.success("创建成功");
|
||||
setShowCreate(false);
|
||||
|
||||
setCreateForm({
|
||||
name: "",
|
||||
});
|
||||
|
||||
listUserSpaces();
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
} finally {
|
||||
setCreateLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function handleJoin() {
|
||||
if (joinLoading) return;
|
||||
|
||||
const code = joinForm.invite_code.trim();
|
||||
|
||||
if (!code) {
|
||||
toast.warning("邀请码不能为空");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!/^[A-Za-z0-9]{6}$/.test(code)) {
|
||||
toast.warning("邀请码必须为6位字母或数字");
|
||||
return;
|
||||
}
|
||||
|
||||
setJoinLoading(true);
|
||||
|
||||
try {
|
||||
const res = await loadDataBySqlApi({
|
||||
sql: ` SELECT
|
||||
s.id,
|
||||
s.name,
|
||||
EXISTS (
|
||||
SELECT 1
|
||||
FROM space_member sm
|
||||
WHERE sm.space_id = s.id
|
||||
AND sm.user_id = ?
|
||||
) AS is_joined
|
||||
FROM space s
|
||||
WHERE s.invite_code = ?
|
||||
LIMIT 1;
|
||||
`,
|
||||
args: [userStore.userInfo.id, code],
|
||||
});
|
||||
|
||||
if (!res.isSuccess) return;
|
||||
|
||||
const row = res.data?.[0];
|
||||
|
||||
if (!row) {
|
||||
toast.warning("邀请码无效");
|
||||
return;
|
||||
}
|
||||
|
||||
if (row.is_joined) {
|
||||
toast.warning("你已经在该空间了");
|
||||
return;
|
||||
}
|
||||
|
||||
const autoRes = await getUniqueIdApi(1);
|
||||
if (!autoRes.isSuccess) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 设置是否是默认空间
|
||||
let isDefault = false;
|
||||
|
||||
const defaultRes = await loadDataApi({
|
||||
view_name: "v_user_spaces",
|
||||
search_condition: `v_user_id = ?`,
|
||||
search_columns: ["v_is_default"],
|
||||
order_by: "",
|
||||
args: [userStore.userInfo.id],
|
||||
});
|
||||
|
||||
if (!defaultRes.isSuccess) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (defaultRes.data.length == 0) {
|
||||
isDefault = true;
|
||||
}
|
||||
|
||||
// 加入
|
||||
const requestData = [];
|
||||
|
||||
requestData.push({
|
||||
table_name: "space_member",
|
||||
key_field: "id",
|
||||
inserts: [
|
||||
{
|
||||
id: autoRes.data[0],
|
||||
space_id: row.id,
|
||||
user_id: userStore.userInfo.id,
|
||||
role: 1,
|
||||
is_default: isDefault ? 1 : 0,
|
||||
sort_number: defaultRes.data.length,
|
||||
member_name: userStore.userInfo.nickname,
|
||||
},
|
||||
],
|
||||
updates: [],
|
||||
deletes: [],
|
||||
});
|
||||
|
||||
const saveRes = await saveDataApi(requestData);
|
||||
|
||||
if (saveRes.isSuccess) {
|
||||
toast.success("加入成功");
|
||||
setShowJoin(false);
|
||||
|
||||
setJoinForm({
|
||||
invite_code: "",
|
||||
});
|
||||
|
||||
listUserSpaces();
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
toast.error("加入失败,请稍后重试");
|
||||
} finally {
|
||||
setJoinLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
const renderItem = ({ item, index }: { item: any; index: number }) => (
|
||||
<PressableFeedback
|
||||
key={item.space_id}
|
||||
onPress={() => {
|
||||
router.navigate({
|
||||
pathname: "/tab-space" as any,
|
||||
params: {
|
||||
spaceId: item.space_id,
|
||||
},
|
||||
});
|
||||
}}
|
||||
style={{
|
||||
height: ITEM_HEIGHT,
|
||||
}}
|
||||
className={`rounded-xl flex-row items-center px-4 py-3 bg-white ${
|
||||
index === spaces.length - 1 ? "mb-4" : ""
|
||||
}`}
|
||||
>
|
||||
<View className="w-full flex-row items-center justify-between">
|
||||
<View>
|
||||
<View className="flex-row items-center gap-2">
|
||||
<Text className="font-semibold text-gray-900">{item.name}</Text>
|
||||
|
||||
{item.owner_id === userStore.userInfo.id && (
|
||||
<Chip size="sm" variant="soft" color="success">
|
||||
创建者
|
||||
</Chip>
|
||||
)}
|
||||
|
||||
{item.v_is_default === 1 && (
|
||||
<Chip size="sm" variant="secondary" color="default">
|
||||
默认
|
||||
</Chip>
|
||||
)}
|
||||
|
||||
{item.space_id === spaceStore?.currentSpace?.space_id && (
|
||||
<Chip size="sm" variant="primary" color="accent">
|
||||
当前空间
|
||||
</Chip>
|
||||
)}
|
||||
</View>
|
||||
|
||||
<View className="flex-row items-center gap-3 mt-3">
|
||||
<View className="flex-row gap-1 items-center">
|
||||
<UserRoundIcon size={12} />
|
||||
<Text className="text-xs">{item.v_member_name}</Text>
|
||||
</View>
|
||||
<View className="flex-row gap-1 items-center">
|
||||
<UsersRoundIcon size={12} />
|
||||
<Text className={`text-xs `}>{item.v_member_count}</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<Sortable.Handle>
|
||||
<GripIcon size={20} />
|
||||
</Sortable.Handle>
|
||||
</View>
|
||||
<PressableFeedback.Ripple />
|
||||
</PressableFeedback>
|
||||
);
|
||||
|
||||
return (
|
||||
<LayoutView>
|
||||
<LayoutView.ScrollView>
|
||||
<Text className="text-base text-black">我的空间</Text>
|
||||
<View className="flex-row gap-4">
|
||||
<Button
|
||||
className="flex-1"
|
||||
onPress={() => {
|
||||
setShowCreate(true);
|
||||
createInputRef.current?.focus();
|
||||
}}
|
||||
>
|
||||
<PlusIcon color="#fff" size={20} />
|
||||
<Button.Label>创建新空间</Button.Label>
|
||||
</Button>
|
||||
<Button
|
||||
className="flex-1"
|
||||
variant="outline"
|
||||
onPress={() => {
|
||||
setShowJoin(true);
|
||||
}}
|
||||
>
|
||||
<HousePlusIcon size={20} />
|
||||
<Button.Label>加入其它空间</Button.Label>
|
||||
</Button>
|
||||
</View>
|
||||
|
||||
<View className="flex-row my-3 items-center gap-3">
|
||||
<Separator className="flex-1" />
|
||||
<Text className="text-xs text-gray-400">我的空间</Text>
|
||||
<Separator className="flex-1" />
|
||||
</View>
|
||||
|
||||
{loading ? (
|
||||
<View className="flex-1 items-center justify-center">
|
||||
<Spinner size="lg" />
|
||||
</View>
|
||||
) : spaces.length === 0 ? (
|
||||
<EmptyState />
|
||||
) : (
|
||||
<Sortable.Grid
|
||||
keyExtractor={(item: any) => {
|
||||
return String(item.space_id);
|
||||
}}
|
||||
activeItemScale={1}
|
||||
columns={1}
|
||||
data={spaces}
|
||||
overDrag="vertical"
|
||||
renderItem={renderItem}
|
||||
rowGap={10}
|
||||
highlight-next-line
|
||||
customHandle
|
||||
autoScrollActivationOffset={200}
|
||||
onDragEnd={(dragData: any) => {
|
||||
const list = dragData.data;
|
||||
|
||||
const updates = list.map((item: any, index: number) => ({
|
||||
id: item.v_space_member_id,
|
||||
sort_number: index,
|
||||
}));
|
||||
|
||||
saveDataApi([
|
||||
{
|
||||
table_name: "space_member",
|
||||
key_field: "id",
|
||||
inserts: [],
|
||||
updates,
|
||||
deletes: [],
|
||||
},
|
||||
]).then((_res) => {
|
||||
// console.log(res);
|
||||
});
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</LayoutView.ScrollView>
|
||||
|
||||
<BottomSheet
|
||||
isOpen={showCreate}
|
||||
onOpenChange={(val) => {
|
||||
if (!val) {
|
||||
setCreateForm({
|
||||
name: "",
|
||||
});
|
||||
setCreateLoading(false);
|
||||
}
|
||||
|
||||
setShowCreate(val);
|
||||
}}
|
||||
>
|
||||
<BottomSheet.Portal>
|
||||
<BottomSheet.Overlay />
|
||||
|
||||
<BottomSheet.Content>
|
||||
<View>
|
||||
<TextField>
|
||||
<Label>空间名称</Label>
|
||||
<Input
|
||||
ref={createInputRef}
|
||||
placeholder="请输入空间名称"
|
||||
onFocus={onFocus}
|
||||
onBlur={onBlur}
|
||||
value={createForm.name}
|
||||
onChangeText={(val) =>
|
||||
setCreateForm({
|
||||
name: val,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</TextField>
|
||||
|
||||
<Button className="mt-3" onPress={handleCreate}>
|
||||
{createLoading && <Spinner entering={FadeIn.delay(50)} color="white" />}
|
||||
<Button.Label>创建</Button.Label>
|
||||
</Button>
|
||||
</View>
|
||||
</BottomSheet.Content>
|
||||
</BottomSheet.Portal>
|
||||
</BottomSheet>
|
||||
|
||||
<BottomSheet
|
||||
isOpen={showJoin}
|
||||
onOpenChange={(val) => {
|
||||
if (!val) {
|
||||
setJoinForm({
|
||||
invite_code: "",
|
||||
});
|
||||
setJoinLoading(false);
|
||||
}
|
||||
|
||||
setShowJoin(val);
|
||||
}}
|
||||
>
|
||||
<BottomSheet.Portal>
|
||||
<BottomSheet.Overlay />
|
||||
|
||||
<BottomSheet.Content>
|
||||
<View>
|
||||
<TextField>
|
||||
<Label>邀请码</Label>
|
||||
<InputOTP
|
||||
ref={joinInputRef}
|
||||
maxLength={6}
|
||||
onFocus={onFocus}
|
||||
onBlur={onBlur}
|
||||
value={joinForm.invite_code}
|
||||
onChange={(val) => {
|
||||
setJoinForm({
|
||||
invite_code: val,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<InputOTP.Group>
|
||||
<InputOTP.Slot index={0} />
|
||||
<InputOTP.Slot index={1} />
|
||||
<InputOTP.Slot index={2} />
|
||||
</InputOTP.Group>
|
||||
<InputOTP.Separator />
|
||||
<InputOTP.Group>
|
||||
<InputOTP.Slot index={3} />
|
||||
<InputOTP.Slot index={4} />
|
||||
<InputOTP.Slot index={5} />
|
||||
</InputOTP.Group>
|
||||
</InputOTP>
|
||||
</TextField>
|
||||
|
||||
<Button className="mt-3" onPress={handleJoin}>
|
||||
{joinLoading && <Spinner entering={FadeIn.delay(50)} color="white" />}
|
||||
<Button.Label>加入</Button.Label>
|
||||
</Button>
|
||||
</View>
|
||||
</BottomSheet.Content>
|
||||
</BottomSheet.Portal>
|
||||
</BottomSheet>
|
||||
</LayoutView>
|
||||
);
|
||||
}
|
||||
@@ -18,11 +18,11 @@ export default function NotFound() {
|
||||
className="mt-4"
|
||||
onPress={() => {
|
||||
requestAnimationFrame(() => {
|
||||
router.replace("/home");
|
||||
router.back();
|
||||
});
|
||||
}}
|
||||
>
|
||||
返回首页
|
||||
返回
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
|
||||
@@ -8,10 +8,15 @@ import "@/global.css";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Stack } from "expo-router";
|
||||
import { Toaster } from "sonner-native";
|
||||
import { KeyboardProvider } from "react-native-keyboard-controller";
|
||||
import { useUserStore } from "@/store";
|
||||
import { useRouter } from "expo-router";
|
||||
|
||||
SplashScreen.preventAutoHideAsync();
|
||||
|
||||
export default function RootLayout() {
|
||||
const router = useRouter();
|
||||
const userStore = useUserStore();
|
||||
const isDark = useIsDark();
|
||||
const isDev = __DEV__;
|
||||
|
||||
@@ -29,31 +34,40 @@ export default function RootLayout() {
|
||||
init();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (userStore.authExpired) {
|
||||
requestAnimationFrame(() => {
|
||||
router.replace("/auth/login");
|
||||
});
|
||||
}
|
||||
}, [userStore.authExpired]);
|
||||
|
||||
if (!isReady) return null;
|
||||
|
||||
return (
|
||||
<GestureHandlerRootView className="flex-1">
|
||||
<ThemeProvider value={isDark ? DarkTheme : DefaultTheme}>
|
||||
<HeroUINativeProvider
|
||||
config={{
|
||||
devInfo: {
|
||||
stylingPrinciples: false,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<Stack
|
||||
screenOptions={{
|
||||
animation: "slide_from_right",
|
||||
contentStyle: {
|
||||
backgroundColor: "#fff",
|
||||
<KeyboardProvider>
|
||||
<ThemeProvider value={isDark ? DarkTheme : DefaultTheme}>
|
||||
<HeroUINativeProvider
|
||||
config={{
|
||||
devInfo: {
|
||||
stylingPrinciples: false,
|
||||
},
|
||||
headerShown: false,
|
||||
}}
|
||||
/>
|
||||
{!isDev && <StatusBar style={isDark ? "light" : "dark"} />}
|
||||
</HeroUINativeProvider>
|
||||
</ThemeProvider>
|
||||
|
||||
>
|
||||
<Stack
|
||||
screenOptions={{
|
||||
animation: "slide_from_right",
|
||||
contentStyle: {
|
||||
backgroundColor: "#fff",
|
||||
},
|
||||
headerShown: false,
|
||||
}}
|
||||
/>
|
||||
{!isDev && <StatusBar style={isDark ? "light" : "dark"} />}
|
||||
</HeroUINativeProvider>
|
||||
</ThemeProvider>
|
||||
</KeyboardProvider>
|
||||
<Toaster duration={1000} />
|
||||
</GestureHandlerRootView>
|
||||
);
|
||||
|
||||
@@ -33,12 +33,14 @@ export default function Login() {
|
||||
setTimeout(() => {
|
||||
requestAnimationFrame(() => {
|
||||
userStore.setUserInfo({
|
||||
id: 1,
|
||||
id: 779895419121733,
|
||||
token: "123",
|
||||
nickname: "Zhang",
|
||||
avatar: "",
|
||||
});
|
||||
|
||||
userStore.setAuthExpired(false);
|
||||
|
||||
router.replace("/(tabs)/home");
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import React from "react";
|
||||
import LayoutView from "@/components/layout/view";
|
||||
import { View, Text } from "react-native";
|
||||
import Navbar from "@/components/layout/navbar";
|
||||
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
||||
import { EarthIcon } from "lucide-react-native";
|
||||
import { useRouter } from "expo-router";
|
||||
|
||||
export default function Space() {
|
||||
const insets = useSafeAreaInsets();
|
||||
const router = useRouter();
|
||||
|
||||
return (
|
||||
<View style={{ flex: 1 }}>
|
||||
<View style={{ flex: 1, zIndex: 0 }}>
|
||||
<LayoutView>
|
||||
<LayoutView.ScrollView>
|
||||
<Text className="text-base text-black">Space</Text>
|
||||
</LayoutView.ScrollView>
|
||||
</LayoutView>
|
||||
</View>
|
||||
<View
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
zIndex: 10,
|
||||
}}
|
||||
>
|
||||
<View style={{ paddingTop: insets.top }}>
|
||||
<Navbar
|
||||
title={"空间"}
|
||||
titleIcon={EarthIcon}
|
||||
onBack={() => {
|
||||
router.back();
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -9,6 +9,12 @@ export function loginWxApi(params: LoginWxParams) {
|
||||
return alovaInstance.Post<ResponseData<LoginResult>>(`/auth/login/wechat`, params);
|
||||
}
|
||||
|
||||
export function getUniqueIdApi(count = 1) {
|
||||
return alovaInstance.Post<ResponseData<number[]>>(`/data/getUniqueId`, {
|
||||
count: count,
|
||||
});
|
||||
}
|
||||
|
||||
interface LoadDataBySqlParams {
|
||||
sql: string;
|
||||
args: any[];
|
||||
@@ -23,10 +29,21 @@ interface LoadDataParams {
|
||||
search_condition: string;
|
||||
order_by: string;
|
||||
search_columns: string[];
|
||||
args: string[];
|
||||
args: any[];
|
||||
}
|
||||
|
||||
export function loadDataApi(params: LoadDataParams) {
|
||||
return alovaInstance.Post<ResponseData<any[]>>(`/data/loadData`, params);
|
||||
}
|
||||
|
||||
interface SaveDataParams {
|
||||
table_name: string;
|
||||
key_field: string;
|
||||
inserts: any[];
|
||||
updates: any[];
|
||||
deletes: any[];
|
||||
}
|
||||
|
||||
export function saveDataApi(params: SaveDataParams[]) {
|
||||
return alovaInstance.Post<ResponseData<null>>(`/data/saveData`, params);
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from "./app";
|
||||
export * from "./user";
|
||||
export * from "./space";
|
||||
@@ -0,0 +1,32 @@
|
||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||
import { create } from "zustand";
|
||||
import { createJSONStorage, persist } from "zustand/middleware";
|
||||
|
||||
interface Space {
|
||||
space_id: number;
|
||||
}
|
||||
|
||||
interface SpaceState {
|
||||
currentSpace: Space | null;
|
||||
setCurrentSpace: (space: Space | null) => void;
|
||||
clear: () => void;
|
||||
inSpace: () => boolean;
|
||||
}
|
||||
|
||||
export const useSpaceStore = create<SpaceState>()(
|
||||
persist(
|
||||
(set, get) => ({
|
||||
currentSpace: null,
|
||||
setCurrentSpace: (space) => set({ currentSpace: space }),
|
||||
clear: () => set({ currentSpace: null }),
|
||||
inSpace: () => {
|
||||
const currentSpace = get().currentSpace;
|
||||
return currentSpace !== null && currentSpace.space_id !== 0;
|
||||
},
|
||||
}),
|
||||
{
|
||||
name: "space-storage",
|
||||
storage: createJSONStorage(() => AsyncStorage),
|
||||
},
|
||||
),
|
||||
);
|
||||
@@ -0,0 +1,13 @@
|
||||
export function generateCode(
|
||||
length: number = 6,
|
||||
chars: string = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789",
|
||||
): string {
|
||||
let result = "";
|
||||
const max = chars.length;
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += chars.charAt(Math.floor(Math.random() * max));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
Reference in new issue
Block a user