Compare commits

...

4 Commits

10 changed files with 115 additions and 98 deletions

View File

@ -1,5 +1,6 @@
import { Ionicons } from '@expo/vector-icons'
import React, { type ReactNode } from 'react'
import { KeyboardAwareScrollView } from 'react-native-keyboard-controller'
import Block from './Block'
import Text from './Text'
@ -49,50 +50,50 @@ const ConfirmModal: React.FC<ConfirmModalProps> = ({
}
return (
<Block className="fixed inset-0 z-[60] items-center justify-center p-[24px]">
<Block className="relative w-full max-w-[320px] -skew-x-3 border-4 border-black bg-white p-[24px] shadow-[10px_10px_0px_#e61e25]">
<Block className="absolute left-[-12px] top-[-12px] skew-x-3 border-[3px] border-black bg-accent px-[8px] py-[4px] shadow-[2px_2px_0px_rgba(0,0,0,0.2)]">
<Text className="text-[12px] font-black tracking-wider">{badge}</Text>
</Block>
<Text className="mb-[8px] mt-[4px] text-[24px] font-black tracking-tight text-black">{title}</Text>
<Block className="mb-[20px] h-[4px] w-full bg-black" />
<Block className="mb-[24px]">
{typeof content === 'string' ? (
<Text className="text-[14px] font-bold leading-relaxed text-gray-800">{content}</Text>
) : (
content
)}
</Block>
<Block className="w-full flex-row gap-x-[12px]">
<Block className="flex flex-1 border-[3px] border-black py-[12px]" onClick={handleCancel}>
<Text className="text-center text-black">{cancelText}</Text>
<KeyboardAwareScrollView bottomOffset={100}>
<Block className="fixed inset-0 z-[60] items-center justify-center p-[24px]">
<Block className="relative w-full max-w-[320px] -skew-x-3 border-4 border-black bg-white p-[24px] shadow-[10px_10px_0px_#e61e25]">
<Block className="absolute left-[-12px] top-[-12px] skew-x-3 border-[3px] border-black bg-accent px-[8px] py-[4px] shadow-[2px_2px_0px_rgba(0,0,0,0.2)]">
<Text className="text-[12px] font-black tracking-wider">{badge}</Text>
</Block>
<Block
className="flex flex-1 flex-row items-center justify-center border-[3px] border-black bg-accent py-[12px] shadow-[4px_4px_0px_#000]"
onClick={handleConfirm}
style={{ opacity: confirmLoading ? 0.6 : 1 }}
>
{confirmLoading ? (
<>
<Ionicons color="#000" name="sync" size={16} style={{ marginRight: 4 }} />
<Text className="text-black">{confirmText}</Text>
</>
<Text className="mb-[8px] mt-[4px] text-[24px] font-black tracking-tight text-black">{title}</Text>
<Block className="mb-[20px] h-[4px] w-full bg-black" />
<Block className="mb-[24px]">
{typeof content === 'string' ? (
<Text className="text-[14px] font-bold leading-relaxed text-gray-800">{content}</Text>
) : (
<>
<Text className="text-black">{confirmText}</Text>
{title==='确认支付?' && (
<Ionicons color="#000" name="flash" size={16} style={{ marginLeft: 4 }} />
)}
</>
content
)}
</Block>
<Block className="w-full flex-row gap-x-[12px]">
<Block className="flex flex-1 border-[3px] border-black py-[12px]" onClick={handleCancel}>
<Text className="text-center text-black">{cancelText}</Text>
</Block>
<Block
className="flex flex-1 flex-row items-center justify-center border-[3px] border-black bg-accent py-[12px] shadow-[4px_4px_0px_#000]"
onClick={handleConfirm}
style={{ opacity: confirmLoading ? 0.6 : 1 }}
>
{confirmLoading ? (
<>
<Ionicons color="#000" name="sync" size={16} style={{ marginRight: 4 }} />
<Text className="text-black">{confirmText}</Text>
</>
) : (
<>
<Text className="text-black">{confirmText}</Text>
{title === '确认支付?' && <Ionicons color="#000" name="flash" size={16} style={{ marginLeft: 4 }} />}
</>
)}
</Block>
</Block>
</Block>
</Block>
</Block>
</KeyboardAwareScrollView>
)
}

View File

@ -10,7 +10,7 @@ export const IOS_UNIVERSAL_LINK = 'duooomi.bowong.cn'
// 原生版本,原生代码变更时需要更新此版本号
export const VERSION = '1.2.0'
// JavaScript版本JS代码变更时需要更新此版本号
export const APP_VERSION = 'dev202601221539'
export const APP_VERSION = 'dev202601271754'
const ALIPAY_SCHEMA = 'alipay2021006119657394'
const ALIPAY_SCHEMA_SANDBOX = 'alipay9021000158673972'

View File

@ -37,7 +37,7 @@ export default observer(function TabTwoScreen() {
const isConnected = bleStore.state.isConnected
console.log('isConnected----------', isConnected)
// console.log('isConnected----------', isConnected)
const { galleryList: contents } = bleStore

View File

@ -582,11 +582,6 @@ const GooActions = observer<GooActionsProps>(function GooActions({ gooPoints, on
{isDev && isPolling && <Block className="ml-[4px] size-[6px] rounded-full bg-green-500" />}
</Block>
)}
{!!isLogin && (
<Block onClick={() => router.push('/settings')}>
<Ionicons color="white" name="settings-outline" size={22} />
</Block>
)}
<Block
className="size-[48px] items-center justify-center rounded-full border-[3px] border-black bg-white shadow-[4px_4px_0px_#000]"
onClick={onOpenSearch}

View File

@ -72,7 +72,7 @@ const Sync = observer(() => {
// 加载生成记录
useEffect(() => {
if (isFocused) {
loadGenerations()
// loadGenerations()
}
}, [isFocused])
@ -423,7 +423,7 @@ const Sync = observer(() => {
<FlashList
contentContainerStyle={{ paddingHorizontal: 12, paddingBottom: 200 }}
data={posts}
drawDistance={300}
// drawDistance={300}
maxItemsInRecyclePool={0}
removeClippedSubviews={true}
ItemSeparatorComponent={() => <Block style={{ height: 6 }} />}
@ -499,6 +499,9 @@ const DeviceItem = observer(({ device }: { device: any }) => {
const canEdit = !!bindDevice && isConnected
// 绑定过的设备
const hasBind = !!bleStore.bindDeviceList?.find((d) => d?.id === id)
const { id: userId } = userStore.user || {}
const onConnectToggle = async (device: any) => {
if (device.connected) {
@ -623,6 +626,16 @@ const DeviceItem = observer(({ device }: { device: any }) => {
{isConnected ? '已连接' : '未连接'}
</Text>
</Block>
{hasBind && (
<Block className="ml-[8px]">
<Text
className={`border-2 border-black px-[6px] text-[10px] font-[900] ${isConnected ? 'bg-black text-accent' : 'bg-gray-200 text-gray-500'}`}
>
</Text>
</Block>
)}
</Block>
</Block>
</Block>
@ -856,13 +869,10 @@ const HeaderBanner = observer(({ connectedDevice, onPick }: { connectedDevice: a
const handleLogout = () => {
if (isLogin) {
signOut().then(() => {
Toast.show({ title: '已登出' })
router.replace('/auth')
})
router.push('/settings')
}
}
const loginText = isLogin ? '登出' : '登录'
const loginText = isLogin ? '设置' : '登录'
return (
<Block className="relative z-40 flex-row items-center justify-between py-[12px]">

View File

@ -153,12 +153,25 @@ export default observer(function ProfilePage() {
Toast.show({ title: err.message || '修改失败,请重试' })
return
}
Toast.hideModal()
Toast.show({ title: '密码已修改,请重新登录' })
// 退出登录
await userStore.signOut()
// 跳转到登录页
router.replace('/auth')
Toast.hideModal()
// 2. 等待 Modal 关闭动画完成(关键:避免 View 空指针)
setTimeout(() => {
// 3. 清空导航栈
router.dismissAll()
// 4. 执行登出
userStore.signOut()
// 5. 跳转到登录页
router.replace('/auth')
// 6. 显示提示
setTimeout(() => {
Toast.show({ title: '已退出登录' })
}, 100)
}, 400)
} catch (e) {
Toast.show({ title: '修改失败,请重试' })
}

View File

@ -1,17 +1,13 @@
import { Ionicons } from '@expo/vector-icons'
import { Block, Text } from '@share/components'
import { Stack, router } from 'expo-router'
import { router, Stack } from 'expo-router'
import React from 'react'
import { ScrollView } from 'react-native'
export default function ServicePage() {
const renderHeader = () => (
<Block className="flex-row items-center justify-between px-[16px] py-[10px]">
<Block
className="ml-[-8px] size-[40px] items-center justify-center"
opacity={0.7}
onClick={() => router.back()}
>
<Block className="ml-[-8px] size-[40px] items-center justify-center" opacity={0.7} onClick={() => router.back()}>
<Ionicons color="#323232" name="chevron-back" size={24} />
</Block>
<Text className="text-[16px] font-[700] text-[#323232]"> / Terms of Service</Text>
@ -69,9 +65,7 @@ export default function ServicePage() {
{renderSectionTitle('3. 用户账户 / User Accounts')}
{renderSectionTitle('3.1 账户注册 / Account Registration')}
{renderParagraph('要使用我们的服务,您需要创建一个账户。注册时,您必须:')}
{renderParagraph(
'To use our services, you need to create an account. When registering, you must:',
)}
{renderParagraph('To use our services, you need to create an account. When registering, you must:')}
{renderBullet('提供真实、准确、完整的信息 / Provide true, accurate, and complete information;')}
{renderBullet('维护并及时更新您的账户信息 / Maintain and promptly update your account information;')}
{renderBullet('对您账户下的所有活动负责 / Be responsible for all activities under your account.')}
@ -86,9 +80,7 @@ export default function ServicePage() {
{renderSectionTitle('4. 使用规范 / Acceptable Use')}
{renderSectionTitle('4.1 合法使用 / Legal Use')}
{renderParagraph(
'您同意仅将我们的服务用于合法目的,并遵守所有适用的法律法规。',
)}
{renderParagraph('您同意仅将我们的服务用于合法目的,并遵守所有适用的法律法规。')}
{renderParagraph(
'You agree to use our services only for lawful purposes and in compliance with all applicable laws and regulations.',
)}
@ -99,11 +91,11 @@ export default function ServicePage() {
{renderBullet(
'上传、发布或传输任何违法、有害、威胁、辱骂、骚扰、诽谤、粗俗、淫秽或其他令人反感的内容 / Upload, post, or transmit any illegal, harmful, threatening, abusive, harassing, defamatory, vulgar, obscene, or otherwise objectionable content;',
)}
{renderBullet('侵犯他人的知识产权或其他权利 / Infringe upon the intellectual property or other rights of others;')}
{renderBullet('干扰或破坏服务的正常运行 / Interfere with or disrupt the normal operation of the service;')}
{renderBullet(
'尝试未经授权访问任何系统或网络 / Attempt to gain unauthorized access to any system or network;',
'侵犯他人的知识产权或其他权利 / Infringe upon the intellectual property or other rights of others;',
)}
{renderBullet('干扰或破坏服务的正常运行 / Interfere with or disrupt the normal operation of the service;')}
{renderBullet('尝试未经授权访问任何系统或网络 / Attempt to gain unauthorized access to any system or network;')}
{renderBullet('使用自动化工具或脚本滥用服务 / Abuse the service using automated tools or scripts.')}
{renderSectionTitle('5. 知识产权 / Intellectual Property')}
@ -133,9 +125,7 @@ export default function ServicePage() {
)}
{renderSectionTitle('6.2 自动续订 / Auto-Renewal')}
{renderParagraph(
'除非您取消订阅,否则订阅将自动续订。您可以在订阅设置中随时取消自动续订。',
)}
{renderParagraph('除非您取消订阅,否则订阅将自动续订。您可以在订阅设置中随时取消自动续订。')}
{renderParagraph(
'Subscriptions will automatically renew unless you cancel them. You may cancel auto-renewal at any time in your subscription settings.',
)}
@ -149,9 +139,7 @@ export default function ServicePage() {
)}
{renderSectionTitle('7. 隐私保护 / Privacy')}
{renderParagraph(
'我们非常重视您的隐私。有关我们如何收集、使用和保护您的信息,请参阅我们的隐私协议。',
)}
{renderParagraph('我们非常重视您的隐私。有关我们如何收集、使用和保护您的信息,请参阅我们的隐私协议。')}
{renderParagraph(
'We take your privacy seriously. Please refer to our Privacy Policy for information on how we collect, use, and protect your information.',
)}
@ -175,17 +163,13 @@ export default function ServicePage() {
{renderSectionTitle('9. 服务终止 / Termination')}
{renderSectionTitle('9.1 终止权利 / Termination Rights')}
{renderParagraph(
'我们保留随时终止或暂停您对服务的访问的权利,无论是否事先通知,原因包括但不限于违反本条款。',
)}
{renderParagraph('我们保留随时终止或暂停您对服务的访问的权利,无论是否事先通知,原因包括但不限于违反本条款。')}
{renderParagraph(
'We reserve the right to terminate or suspend your access to the service at any time, with or without prior notice, for reasons including but not limited to violation of these terms.',
)}
{renderSectionTitle('9.2 终止后果 / Consequences of Termination')}
{renderParagraph(
'服务终止后,您访问服务的权利将立即终止。本条款中在终止后仍然有效的条款将继续适用。',
)}
{renderParagraph('服务终止后,您访问服务的权利将立即终止。本条款中在终止后仍然有效的条款将继续适用。')}
{renderParagraph(
'Upon termination, your right to access the service will immediately cease. The provisions of these terms that by their nature should survive termination will continue to apply.',
)}
@ -211,13 +195,11 @@ export default function ServicePage() {
{renderParagraph('If you have any questions regarding these Terms of Service, please contact us at:')}
{renderParagraph('公司名称 / Company Name: BOWONG AI (HK) LIMITED')}
{renderParagraph('客服邮箱 / Support Email: support@bowong.ai')}
{renderParagraph(
'通过使用我们的服务,您确认已阅读、理解并同意遵守本服务条款。',
)}
{renderParagraph('通过使用我们的服务,您确认已阅读、理解并同意遵守本服务条款。')}
{renderParagraph(
'By using our services, you acknowledge that you have read, understood, and agree to be bound by these Terms of Service.',
)}
</ScrollView>
</Block>
)
}
}

View File

@ -24,11 +24,25 @@ export default observer(function SettingsPage() {
content="确定要退出登录吗?"
onCancel={Toast.hideModal}
onConfirm={async () => {
await signOut()
Toast.show({ title: '已退出登录' })
router.replace('/(tabs)')
// 关闭modal
// 1. 立即关闭 Modal避免在动画期间操作路由
Toast.hideModal()
// 2. 等待 Modal 关闭动画完成(关键:避免 View 空指针)
setTimeout(() => {
// 3. 清空导航栈
router.dismissAll()
// 4. 执行登出
signOut()
// 5. 跳转到登录页
router.replace('/auth')
// 6. 显示提示
setTimeout(() => {
Toast.show({ title: '已退出登录' })
}, 100)
}, 400)
}}
/>,
)

View File

@ -1,6 +1,6 @@
import { root } from '@repo/core'
import { type ListTemplateGenerationsInput, type TemplateGeneration, TemplateGenerationController } from '@repo/sdk'
import { useCallback, useRef, useState } from 'react'
import { useCallback, useEffect, useRef, useState } from 'react'
import { type ApiError } from '@/lib/types'
@ -19,14 +19,13 @@ export const useTemplateGenerations = () => {
const load = useCallback(async (params?: ListTemplateGenerationsInput) => {
setLoading(true)
setError(null)
currentPageRef.current = 1
const templateGeneration = root.get(TemplateGenerationController)
const { data, error } = await handleError(
async () =>
await templateGeneration.list({
page: currentPageRef.current,
page: 1,
limit: params?.limit || pageSize,
...params,
}),
@ -93,6 +92,10 @@ export const useTemplateGenerations = () => {
[load],
)
useEffect(() => {
load()
}, [])
return {
data,
loading,

View File

@ -1,6 +1,5 @@
import { router } from 'expo-router'
import { storage } from './storage'
import { storage as storage2 } from '../utils/storage'
import { storage } from './storage.native'
interface FetchLoggerOptions {
enableLogging?: boolean
@ -42,9 +41,9 @@ export const createFetchWithLogger = (options: FetchLoggerOptions = {}) => {
const response = await originalFetch(input, init)
if (response.status === 401) {
console.warn('🔐 401 未授权,跳转到登录页')
console.warn('🔐 401 未授权,清空登录状态')
// router.replace('/auth')
router.replace('/auth')
storage2.set('isLogin', false)
}
return response