This commit is contained in:
oneao committed 2025-11-14 17:31:42 +08:00
1 parent 06d79d186a
commit 737aa98d18
85 files changed
+21476 -66

No files matched your search

-1
View File
@@ -17,7 +17,6 @@
"supportsTablet": true
},
"android": {
"softwareKeyboardLayoutMode": "pan",
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#ffffff"
+1
View File
@@ -36,6 +36,7 @@
"react-native": "0.81.5",
"react-native-calendars": "^1.1313.0",
"react-native-date-picker": "^5.0.13",
"react-native-daterange-picker": "^1.5.1",
"react-native-dates-picker": "^0.2.0",
"react-native-gesture-handler": "~2.28.0",
"react-native-keyboard-aware-scroll-view": "^0.9.5",
+25 -2
View File
@@ -86,6 +86,9 @@ importers:
react-native-date-picker:
specifier: ^5.0.13
version: 5.0.13(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
react-native-daterange-picker:
specifier: ^1.5.1
version: 1.5.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
react-native-dates-picker:
specifier: ^0.2.0
version: 0.2.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0)
@@ -3755,48 +3758,56 @@ packages:
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
libc: [glibc]
lightningcss-linux-arm64-gnu@1.30.2:
resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
libc: [glibc]
lightningcss-linux-arm64-musl@1.27.0:
resolution: {integrity: sha512-rCGBm2ax7kQ9pBSeITfCW9XSVF69VX+fm5DIpvDZQl4NnQoMQyRwhZQm9pd59m8leZ1IesRqWk2v/DntMo26lg==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
libc: [musl]
lightningcss-linux-arm64-musl@1.30.2:
resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==}
engines: {node: '>= 12.0.0'}
cpu: [arm64]
os: [linux]
libc: [musl]
lightningcss-linux-x64-gnu@1.27.0:
resolution: {integrity: sha512-Dk/jovSI7qqhJDiUibvaikNKI2x6kWPN79AQiD/E/KeQWMjdGe9kw51RAgoWFDi0coP4jinaH14Nrt/J8z3U4A==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
libc: [glibc]
lightningcss-linux-x64-gnu@1.30.2:
resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
libc: [glibc]
lightningcss-linux-x64-musl@1.27.0:
resolution: {integrity: sha512-QKjTxXm8A9s6v9Tg3Fk0gscCQA1t/HMoF7Woy1u68wCk5kS4fR+q3vXa1p3++REW784cRAtkYKrPy6JKibrEZA==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
libc: [musl]
lightningcss-linux-x64-musl@1.30.2:
resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==}
engines: {node: '>= 12.0.0'}
cpu: [x64]
os: [linux]
libc: [musl]
lightningcss-win32-arm64-msvc@1.27.0:
resolution: {integrity: sha512-/wXegPS1hnhkeG4OXQKEMQeJd48RDC3qdh+OA8pCuOPCyvnm/yEayrJdJVqzBsqpy1aJklRCVxscpFur80o6iQ==}
@@ -4658,6 +4669,12 @@ packages:
react: '>= 17.0.1'
react-native: '>= 0.64.3'
react-native-daterange-picker@1.5.1:
resolution: {integrity: sha512-Oq02ApRw4XTIo1Hyw3R5vKm7zyntRSqBvmOzlzXDUxS7K9GLstvTD8U3asj23ZmAGy6OR+Ye5mghnUpJoIrjfw==}
peerDependencies:
react: ^16.13.1
react-native: ^0.63.2
react-native-dates-picker@0.2.0:
resolution: {integrity: sha512-dO7HGami3fhKa/WVtd5jj0xfekbNJZzka++4+0pBUW8br2/t9YzyJ7DYPcZ7vGdRy6bw/qkBG6EASRq8DJP/5Q==}
engines: {node: '>= 16.0.0'}
@@ -11022,8 +11039,7 @@ snapshots:
pkg-types: 1.3.1
ufo: 1.6.1
moment@2.30.1:
optional: true
moment@2.30.1: {}
ms@2.0.0: {}
@@ -11470,6 +11486,13 @@ snapshots:
react: 19.1.0
react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0)
react-native-daterange-picker@1.5.1(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0):
dependencies:
lodash: 4.17.21
moment: 2.30.1
react: 19.1.0
react-native: 0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0)
react-native-dates-picker@0.2.0(react-native@0.81.5(@babel/core@7.28.5)(@types/react@19.1.17)(react@19.1.0))(react@19.1.0):
dependencies:
dayjs: 1.11.19
@@ -1,64 +1,375 @@
import type {
TextInputProps,
} from 'react-native'
import React from 'react'
import type { DateType, ModeType } from 'react-native-dates-picker'
import type { ITheme } from './components/ThemeSelector'
import dayjs from 'dayjs'
import { useCallback, useState } from 'react'
import {
Pressable,
SafeAreaView,
StyleSheet,
TextInput as TextInputRN,
Switch,
Text,
TouchableOpacity,
View,
} from 'react-native'
import { KeyboardAwareScrollView } from 'react-native-keyboard-controller'
import DateTimePicker from 'react-native-dates-picker'
import LocaleSelector from './components/LocaleSelector'
import ThemeSelector from './components/ThemeSelector'
import 'dayjs/locale/zh-cn'
import 'dayjs/locale/en'
import 'dayjs/locale/de'
import 'dayjs/locale/es'
function TextInput(props: TextInputProps) {
return (
<TextInputRN
placeholderTextColor="#6c6c6c"
style={styles.textInput}
multiline
numberOfLines={2}
testID={props.placeholder}
{...props}
placeholder={`${props.placeholder} (${
props.keyboardType === 'default' ? 'text' : 'numeric'
})`}
/>
const Themes: ITheme[] = [
{ mainColor: '#0047FF', activeTextColor: '#fff' },
{ mainColor: '#00D27A', activeTextColor: '#fff' },
{ mainColor: '#F5803E', activeTextColor: '#fff' },
{ mainColor: '#E63757', activeTextColor: '#fff' },
{ mainColor: '#D8E3FF', activeTextColor: '#0047FF' },
{ mainColor: '#CCF6E4', activeTextColor: '#00864E' },
{ mainColor: '#FDE6D8', activeTextColor: '#9D5228' },
{ mainColor: '#FAD7DD', activeTextColor: '#932338' },
]
export default function App() {
const [mode, setMode] = useState<ModeType>('single')
const [timePicker, setTimePicker] = useState(false)
const [date, setDate] = useState<DateType | undefined>()
const [range, setRange] = useState<{
startDate: DateType
endDate: DateType
}>({ startDate: undefined, endDate: undefined })
const [dates, setDates] = useState<DateType[] | undefined>()
const [theme, setTheme] = useState<ITheme | undefined>(Themes[0])
const [locale, setLocale] = useState('zh-cn')
const onChangeMode = useCallback(
(value: ModeType) => {
setDate(undefined)
setRange({ startDate: undefined, endDate: undefined })
setDates(undefined)
setMode(value)
},
[setMode, setDate, setRange, setDates],
)
const onChange = useCallback(
(params) => {
if (mode === 'single' || mode === 'wheel')
setDate(params.date)
else if (mode === 'range')
setRange(params)
else if (mode === 'multiple')
setDates(params.dates)
},
[mode],
)
}
export default function AwareScrollView() {
return (
<KeyboardAwareScrollView
bottomOffset={50}
style={styles.container}
contentContainerStyle={styles.content}
>
{Array.from({ length: 10 }).fill(0).map((_, i) => (
<TextInput
key={i}
placeholder={`TextInput#${i}`}
keyboardType={i % 2 === 0 ? 'numeric' : 'default'}
<SafeAreaView style={styles.container}>
<View style={styles.body}>
<View style={styles.titleContainer}>
<Text style={styles.title}>React Native Dates Picker</Text>
</View>
<ThemeSelector themes={Themes} setTheme={setTheme} />
<LocaleSelector
locale={locale}
setLocale={setLocale}
mainColor={theme?.mainColor}
activeTextColor={theme?.activeTextColor}
/>
))}
</KeyboardAwareScrollView>
<View style={styles.modesContainer}>
<Text style={{ marginRight: 8 }}>Mode:</Text>
<TouchableOpacity
style={[
styles.modeSelect,
{
backgroundColor:
mode === 'single' ? theme?.mainColor : undefined,
},
]}
onPress={() => onChangeMode('single')}
>
<Text
style={[
styles.modeSelectText,
mode === 'single' && { color: theme?.activeTextColor },
]}
>
Single
</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.modeSelect,
{
backgroundColor:
mode === 'range' ? theme?.mainColor : undefined,
},
]}
onPress={() => onChangeMode('range')}
>
<Text
style={[
styles.modeSelectText,
mode === 'range' && { color: theme?.activeTextColor },
]}
>
Range
</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.modeSelect,
{
backgroundColor:
mode === 'multiple' ? theme?.mainColor : undefined,
},
]}
onPress={() => onChangeMode('multiple')}
>
<Text
style={[
styles.modeSelectText,
mode === 'multiple' && { color: theme?.activeTextColor },
]}
>
Multiple
</Text>
</TouchableOpacity>
<TouchableOpacity
style={[
styles.modeSelect,
{
backgroundColor:
mode === 'wheel' ? theme?.mainColor : undefined,
},
]}
onPress={() => onChangeMode('wheel')}
>
<Text
style={[
styles.modeSelectText,
mode === 'wheel' && { color: theme?.activeTextColor },
]}
>
Wheel
</Text>
</TouchableOpacity>
</View>
<View
style={{
flexDirection: 'row',
alignItems: 'center',
gap: 10,
marginBottom: 20,
}}
>
<View
style={{
flexDirection: 'row',
alignItems: 'center',
gap: 10,
}}
>
<Switch
value={timePicker}
style={{ transform: [{ scale: 0.65 }] }}
onValueChange={() => setTimePicker(!timePicker)}
disabled={mode !== 'single'}
/>
<Text
style={{
fontSize: 14,
color: '#000',
marginLeft: -8,
textDecorationLine: 'none',
}}
>
Time Picker
</Text>
</View>
<Text style={{ fontSize: 13, color: 'gray' }}>
(Works in Single mode)
</Text>
</View>
<View style={styles.datePickerContainer}>
<View style={styles.datePicker}>
<DateTimePicker
mode={mode}
date={date}
locale={locale}
startDate={range.startDate}
endDate={range.endDate}
dates={dates}
displayFullDays
timePicker={timePicker}
// minDate={range.startDate}
maxDate={new Date()}
// firstDayOfWeek={1}
// columns={['year', 'month', 'day', 'hour', 'minute', 'second']}
onChange={onChange}
headerButtonColor={theme?.mainColor}
selectedItemColor={theme?.mainColor}
selectedTextStyle={{
fontWeight: 'bold',
color: theme?.activeTextColor,
}}
wheelPickerItemStyle={{ paddingHorizontal: 0 }}
todayContainerStyle={{
borderWidth: 1,
}}
/>
<View style={styles.footer}>
{mode === 'single' || mode === 'wheel'
? (
<View style={styles.footerContainer}>
<Text>
{date
? dayjs(date)
.locale(locale)
.format(
timePicker
? 'MMMM, DD, YYYY - HH:mm'
: 'MMMM, DD, YYYY',
)
: '...'}
</Text>
<Pressable
onPress={() => setDate(dayjs() as DateType)}
accessibilityRole="button"
accessibilityLabel="Today"
>
<View
style={[
styles.todayButton,
{ backgroundColor: theme?.mainColor },
]}
>
<Text
style={[
styles.todayButtonText,
{ color: theme?.activeTextColor },
]}
>
Today
</Text>
</View>
</Pressable>
</View>
)
: mode === 'range'
? (
<View style={{ gap: 3 }}>
<Text>
<Text style={{ marginRight: 5, fontWeight: 'bold' }}>
Start Date:
</Text>
{range.startDate
? dayjs(range.startDate)
.locale(locale)
.format('MMMM, DD, YYYY')
: '...'}
</Text>
<Text>
<Text style={{ marginRight: 5, fontWeight: 'bold' }}>
End Date:
</Text>
{range.endDate
? dayjs(range.endDate)
.locale(locale)
.format('MMMM, DD, YYYY')
: '...'}
</Text>
</View>
)
: mode === 'multiple'
? (
<View style={{ gap: 3 }}>
<Text style={{ fontWeight: 'bold' }}>Selected Dates:</Text>
{dates
&& dates.map((d, index) => (
<Text key={index}>
{dayjs(d).locale(locale).format('MMMM, DD, YYYY')}
</Text>
))}
</View>
)
: null}
</View>
</View>
</View>
</View>
</SafeAreaView>
)
}
const styles = StyleSheet.create({
container: {
paddingHorizontal: 16,
flex: 1,
backgroundColor: '#F5FCFF',
},
content: {
paddingTop: 50,
body: {
flex: 1,
backgroundColor: '#F5FCFF',
alignItems: 'center',
},
textInput: {
titleContainer: {
paddingVertical: 20,
alignItems: 'center',
backgroundColor: '#fff',
marginBottom: 20,
width: '100%',
minHeight: 50,
maxHeight: 200,
marginBottom: 50,
borderColor: 'black',
borderWidth: 2,
marginRight: 160,
borderRadius: 10,
color: 'black',
paddingHorizontal: 12,
},
title: { fontSize: 18, fontWeight: 'bold' },
modesContainer: {
flexDirection: 'row',
alignItems: 'center',
gap: 6,
marginBottom: 20,
},
modeSelect: {
paddingHorizontal: 15,
paddingVertical: 8,
borderRadius: 20,
},
modeSelectText: {
fontSize: 13,
fontWeight: 'bold',
},
datePickerContainer: {
alignItems: 'center',
},
datePicker: {
width: 375,
backgroundColor: '#fff',
padding: 1,
borderRadius: 15,
shadowRadius: 20,
shadowColor: '#000',
shadowOpacity: 0.1,
shadowOffset: { width: 0, height: 0 },
},
footer: {
paddingHorizontal: 5,
paddingVertical: 5,
marginTop: 15,
},
footerContainer: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
todayButton: {
paddingHorizontal: 16,
paddingVertical: 10,
borderRadius: 8,
},
todayButtonText: {
fontWeight: 'bold',
},
})
@@ -2,7 +2,8 @@ import type { MoneyCategoryResult } from '@/request/api/money'
import type { MoneyCategory } from '@/types/money'
import Big from 'big.js'
import { useEffect, useRef, useState } from 'react'
import { Keyboard, KeyboardAvoidingView, Platform, Pressable, StyleSheet, Text, TouchableWithoutFeedback, View } from 'react-native'
import { Keyboard, Pressable, StyleSheet, Text, TouchableWithoutFeedback, View } from 'react-native'
import { KeyboardAvoidingView } from 'react-native-keyboard-controller'
import { useSafeAreaInsets } from 'react-native-safe-area-context'
import { AInput, LucideIcon } from '@/components/common/ao'
import SegmentedTabs from '@/components/common/ao/SegmentedTabs'
@@ -71,6 +72,7 @@ export default function AddMoneyDrawer({
})
const keyboardHeight = useKeyboardHeight()
console.log(keyboardHeight)
function selectCategory(item: MoneyCategory) {
setSelectedCategoryId(item.id)
setShowKeydown(true)
@@ -291,7 +293,7 @@ export default function AddMoneyDrawer({
useEffect(() => {
const sub = Keyboard.addListener('keyboardDidHide', () => {
if (inputRef.current) {
inputRef.current.blur() // 收起键盘时失去焦点
inputRef.current.blur()
setIsFocused(false)
}
})
@@ -367,7 +369,7 @@ export default function AddMoneyDrawer({
{showKeydown && (
<View>
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View className="p-4 h-28">
<View className="h-28 flex pl-4 pr-4 justify-center">
<View className="flex flex-row items-center justify-between">
<Pressable
className="flex flex-row items-center gap-1.5 px-2 py-1.5 rounded-md bg-gray-50 active:opacity-70"
@@ -389,9 +391,9 @@ export default function AddMoneyDrawer({
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
/>
</View>
</TouchableWithoutFeedback>
<View className="flex flex-row flex-wrap" style={{ height: 220 }}>
{keys.map((item, idx) => {
const isFirstCol = idx % 4 === 0
@@ -436,15 +438,8 @@ export default function AddMoneyDrawer({
})}
</View>
{isFocused && (
<View style={{ height:
keyboardHeight + 10 - 220 }}
>
</View>
)}
</View>
)}
</DrawerContent>
</Drawer>
)
@@ -1,6 +1,6 @@
import { router, Stack } from 'expo-router'
import { ArrowLeft } from 'lucide-react-native'
import { EmptyState } from '@/components/common/EmptyStatus'
import EmptyState from '@/components/common/EmptyStatus'
export default function NotFound() {
return (
@@ -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,