This commit is contained in:
oneao committed 2025-11-17 22:38:37 +08:00
1 parent 1f82f1dd1f
commit eaba6cf17b
6 files changed
+211 -187

No files matched your search

@@ -1,62 +1,78 @@
import { useState, useCallback } from 'react'
import { Pressable, Text, View, FlatList } from 'react-native'
import { AddIcon, GlobeIcon, Icon, PlayIcon, SettingsIcon } from '@/components/ui/icon'
import { Menu, MenuItem, MenuItemLabel } from '@/components/ui/menu'
import React, { useState } from 'react'
import { FlatList, Text, View } from 'react-native'
import {
Menu,
MenuOption,
MenuOptions,
MenuProvider,
MenuTrigger,
} from 'react-native-popup-menu'
import { Button, ButtonText } from '@/components/ui/button'
export default function Example() {
const data = Array.from({ length: 1000 }, (_, i) => i + 1)
const [openIndex, setOpenIndex] = useState<number | null>(null) // 控制哪个菜单打开
const data = Array.from({ length: 10 }, (_, i) => i + 1)
const [activeIndex, setActiveIndex] = useState<number | null>(null)
const renderItem = useCallback(
({ item: index }) => (
<View style={{ marginVertical: 10 }}>
const renderItem = ({ item: index }: { item: number }) => {
const isActive = activeIndex === index
return (
<View
style={{
marginVertical: 10,
padding: 10,
borderWidth: 1,
borderColor: '#ccc',
borderRadius: 6,
}}
>
<Menu
placement="top"
offset={5}
disabledKeys={['Settings']}
isOpen={openIndex === index}
onOpen={() => setOpenIndex(index)}
onClose={() => setOpenIndex(null)}
trigger={({ onPress, ...triggerProps }) => (
<Pressable {...triggerProps} onLongPress={onPress}>
<Text>Menu {index}</Text>
</Pressable>
)}
onOpen={() => setActiveIndex(index)}
onClose={() => setActiveIndex(null)}
>
{openIndex === index && (
<>
<MenuItem key="Add account" textValue="Add account">
<Icon as={AddIcon} size="sm" className="mr-2" />
<MenuItemLabel size="sm">Add account - {index}</MenuItemLabel>
</MenuItem>
<MenuItem key="Community" textValue="Community">
<Icon as={GlobeIcon} size="sm" className="mr-2" />
<MenuItemLabel size="sm">Community - {index}</MenuItemLabel>
</MenuItem>
<MenuItem key="Plugins" textValue="Plugins">
<Icon as={PlayIcon} size="sm" className="mr-2" />
<MenuItemLabel size="sm">Plugins - {index}</MenuItemLabel>
</MenuItem>
<MenuItem key="Settings" textValue="Settings">
<Icon as={SettingsIcon} size="sm" className="mr-2" />
<MenuItemLabel size="sm">Settings - {index}</MenuItemLabel>
</MenuItem>
</>
)}
{/* MenuTrigger 应该包装一个可触摸的组件 */}
<MenuTrigger
customStyles={{
TriggerTouchableComponent: Button, // 使用你的 Button 组件
}}
>
{/* 触发区域的内容 */}
<ButtonText>
Item
{' '}
{index}
{' '}
{isActive ? '(active)' : ''}
</ButtonText>
</MenuTrigger>
<MenuOptions>
<MenuOption onSelect={() => alert(`Clicked Option A for ${index}`)}>
<Text>
Option A -
{index}
</Text>
</MenuOption>
<MenuOption onSelect={() => alert(`Clicked Option B for ${index}`)}>
<Text style={{ color: 'red' }}>
Option B -
{index}
</Text>
</MenuOption>
<MenuOption onSelect={() => setActiveIndex(null)}>
<Text>Close Menu</Text>
</MenuOption>
</MenuOptions>
</Menu>
</View>
),
[openIndex]
)
)
}
return (
<FlatList
data={data}
renderItem={renderItem}
keyExtractor={(item) => item.toString()}
initialNumToRender={20}
maxToRenderPerBatch={20}
windowSize={10}
keyExtractor={item => item.toString()}
/>
)
}
@@ -1,10 +1,16 @@
import type { MoneyRecordGroup, MoneyRecordItem } from '@/types/money/record'
import React, { useCallback, useState } from 'react'
import { Pressable, SectionList, Text, View } from 'react-native'
import {
Menu,
MenuOption,
MenuOptions,
MenuTrigger,
renderers,
} from 'react-native-popup-menu'
import { LucideIcon } from '@/components/common/ao'
import EmptyState from '@/components/common/EmptyStatus'
import { Badge, BadgeText } from '@/components/ui/badge'
import { Menu, MenuItem, MenuItemLabel } from '@/components/ui/menu'
import MoneyCategoryIcon from './MoneyCategoryIcon'
interface StaticTransactionsProps {
@@ -75,78 +81,76 @@ export default function StaticTransactions({
)}
renderItem={({ item }) => {
const isOpen = item.id === selectedId
return (
<Menu
placement="bottom"
offset={5}
isOpen={isOpen}
onClose={() => setSelectedId(null)}
trigger={({ onLongPress, onPressOut, delayLongPress, android_ripple, ...triggerProps }) => (
<Pressable
{...triggerProps}
onLongPress={() => setSelectedId(item.id)}
delayLongPress={200}
android_ripple={undefined}
>
<View
className="flex-row items-center gap-4 py-2 px-5"
style={{
backgroundColor: item.id === selectedId ? '#f2f2f2' : 'transparent',
}}
>
<View className="w-10 h-10 rounded-full bg-gray-100 items-center justify-center">
<MoneyCategoryIcon name={item.category_icon} size={22} color="#000" />
</View>
<View className="flex-1">
<Text className="text-gray-800 font-medium text-base">{item.category_name}</Text>
{item.remark && <Text className="text-gray-400 text-sm">{item.remark}</Text>}
</View>
<View className="flex-row flex">
<Text className="text-sm text-gray-500">
{item.category_type === 1 ? '+' : '-'}
{' '}
{item.amount}
</Text>
</View>
<Badge size='sm' variant='solid' action='muted'>
<BadgeText>宝贝</BadgeText>
</Badge>
</View>
</Pressable>
)}
renderer={renderers.Popover}
rendererProps={{
placement: 'bottom',
preferredPlacement: 'bottom',
anchorStyle: { backgroundColor: 'transparent' },
}}
>
{isOpen && (
<>
<MenuItem
key="update"
textValue="update"
onPress={() => {
onUpdate?.(item)
}}
>
<LucideIcon icon="Pencil" size={14} className="mr-2" />
<MenuItemLabel size="sm">
修改
</MenuItemLabel>
</MenuItem>
<MenuItem
key="delete"
textValue="delete"
onPress={() => {
onDelete?.(item.id)
}}
>
<LucideIcon icon="Trash2" size={14} className="mr-2" />
<MenuItemLabel size="sm">
删除
</MenuItemLabel>
</MenuItem>
</>
)}
<MenuTrigger>
<View
className="flex-row items-center gap-4 py-2 px-5"
style={{
backgroundColor: item.id === selectedId ? '#f2f2f2' : 'transparent',
}}
>
<View className="w-10 h-10 rounded-full bg-gray-100 items-center justify-center">
<MoneyCategoryIcon name={item.category_icon} size={22} color="#000" />
</View>
<View className="flex-1">
<Text className="text-gray-800 font-medium text-base">{item.category_name}</Text>
{item.remark && <Text className="text-gray-400 text-sm">{item.remark}</Text>}
</View>
<View className="flex-row flex">
<Text className="text-sm text-gray-500">
{item.category_type === 1 ? '+' : '-'}
{' '}
{item.amount}
</Text>
</View>
<Badge size="sm" variant="solid" action="muted">
<BadgeText>宝贝</BadgeText>
</Badge>
</View>
</MenuTrigger>
<MenuOptions
customStyles={{
optionsContainer: {
backgroundColor: 'white',
minWidth: 160,
},
}}
>
<MenuOption
customStyles={{
optionTouchable: {
underlayColor: '#f0f0f0', // 按压时的背景色
activeOpacity: 0.7, // (可选)按压时的透明度
},
// 如果需要,也可以设置默认状态下的背景色
optionWrapper: {
backgroundColor: 'transparent', // 默认背景色
},
}}
>
<View className="flex flex-row items-center h-10 px-2">
<LucideIcon icon="Pencil" />
<Text className="ml-2 text-lg">更新</Text>
</View>
</MenuOption>
<MenuOption onSelect={() => alert(`Clicked Option B fo`)}>
<View className="flex flex-row items-center h-10 px-2">
<LucideIcon icon="Trash" />
<Text className=" ml-2 text-lg">删除</Text>
</View>
</MenuOption>
</MenuOptions>
</Menu>
)
}}
+36 -33
View File
@@ -6,6 +6,7 @@ import * as SplashScreen from 'expo-splash-screen'
import { StatusBar } from 'expo-status-bar'
import { useEffect } from 'react'
import { KeyboardProvider } from 'react-native-keyboard-controller'
import { MenuProvider } from 'react-native-popup-menu'
import { AButton } from '@/components/common/ao'
import EmptyState from '@/components/common/EmptyStatus'
import { GluestackUIProvider } from '@/components/ui/gluestack-ui-provider'
@@ -64,41 +65,43 @@ export default function RootLayout() {
return null
}
return (
<KeyboardProvider>
<GluestackUIProvider>
<ToastProvider>
<ToastProviderWrapper>
<Stack
screenOptions={{
headerTitleAlign: 'center',
animation: 'slide_from_right',
gestureEnabled: true,
gestureDirection: 'horizontal',
contentStyle: {
backgroundColor: '#fff',
},
}}
>
<Stack.Screen
name="(tabs)"
options={{
headerShown: false,
<MenuProvider>
<KeyboardProvider>
<GluestackUIProvider>
<ToastProvider>
<ToastProviderWrapper>
<Stack
screenOptions={{
headerTitleAlign: 'center',
animation: 'slide_from_right',
gestureEnabled: true,
gestureDirection: 'horizontal',
contentStyle: {
backgroundColor: '#fff',
},
}}
/>
>
<Stack.Screen
name="(tabs)"
options={{
headerShown: false,
}}
/>
<Stack.Screen
name="auth"
options={{
headerShown: false,
}}
/>
<Stack.Screen
name="auth"
options={{
headerShown: false,
}}
/>
<Stack.Screen name="+not-found" />
</Stack>
<StatusBar style="auto" />
</ToastProviderWrapper>
</ToastProvider>
</GluestackUIProvider>
</KeyboardProvider>
<Stack.Screen name="+not-found" />
</Stack>
<StatusBar style="auto" />
</ToastProviderWrapper>
</ToastProvider>
</GluestackUIProvider>
</KeyboardProvider>
</MenuProvider>
)
}
@@ -30,8 +30,8 @@ function isWhiteListed(url: string) {
}
const alovaInstance = createAlova({
// baseURL: 'http://192.168.5.6:8085/app',
baseURL: 'http://192.168.1.136:8085/app',
baseURL: 'http://192.168.5.6:8085/app',
// baseURL: 'http://192.168.1.136:8085/app',
requestAdapter: axiosRequestAdapter(),
timeout: 5000,
cacheFor: null,