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,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,