u
This commit is contained in:
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>
|
||||
)
|
||||
}}
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in new issue
Block a user