Skip to content

Commit

Permalink
feat: 定时关闭样式优化
Browse files Browse the repository at this point in the history
  • Loading branch information
maotoumao committed Mar 21, 2023
1 parent 0b2db06 commit b6622f0
Showing 1 changed file with 204 additions and 40 deletions.
244 changes: 204 additions & 40 deletions src/components/panels/types/timingClose.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,41 @@
import React, {useMemo, useState} from 'react';
import React, {useCallback, useEffect, useMemo, useRef} from 'react';
import {StyleSheet, View} from 'react-native';
import rpx from '@/utils/rpx';
import {Divider, TextInput, useTheme} from 'react-native-paper';
import {Divider, useTheme} from 'react-native-paper';
import ThemeText from '@/components/base/themeText';

import {setTimingClose, useTimingClose} from '@/utils/timingClose';
import ThemeSwitch from '@/components/base/switch';
import timeformat from '@/utils/timeformat';
import PanelBase from '../base/panelBase';
import {TouchableOpacity} from 'react-native-gesture-handler';
import {FlatList, TouchableOpacity} from 'react-native-gesture-handler';
import Color from 'color';
import {atom, useAtom, useAtomValue} from 'jotai';
import {atom, useAtom, useAtomValue, useSetAtom} from 'jotai';
import {debounce} from 'lodash';

// const hours = Array(24).fill(1).map(_ => _.index);
// const mins = Array(60).fill(1).map(_ => _.index);

const shortCutTimes = [null, 15, 30, 45, 60] as const;

const selectedHourAtom = atom('0');
const selectMinAtom = atom('15');
const shortCutAtom = atom<15 | 30 | 45 | 60 | null>(null);

// 全局的时间
let selectedHour = '0';
let selectedMin = '15';

function getDeadlineTimestamp(hour: string | number, min: string | number) {
const [_hour, _min] = [+hour, +min];
if (!_hour && !_min) {
return Date.now() + 60000;
}

return Date.now() + (_hour * 60 + _min) * 60000;
}

function CountDownHeader() {
const countDown = useTimingClose();
const selectedHour = useAtomValue(selectedHourAtom);
const selectedMin = useAtomValue(selectMinAtom);
const shortCutValue = useAtomValue(shortCutAtom);

return (
<View style={style.header}>
Expand All @@ -34,14 +46,16 @@ function CountDownHeader() {
</ThemeText>
<ThemeSwitch
value={countDown !== null}
onChange={console.log}
onValueChange={val => {
if (val === true) {
if (shortCutValue) {
setTimingClose(
getDeadlineTimestamp(0, shortCutValue),
);
return;
}
setTimingClose(
Date.now() +
((+selectedHour || 0) * 60 +
(+selectedMin || 1)) *
60000,
getDeadlineTimestamp(selectedHour, selectedMin),
);
} else {
setTimingClose(null);
Expand All @@ -52,18 +66,189 @@ function CountDownHeader() {
);
}

const ITEM_HEIGHT = rpx(72);
const hours = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
const minutes = Array(60)
.fill(0)
.map((_, index) => index);

const EmptyItem = () => <View style={numScrollStyles.emptyItem} />;

function NumScrollView() {
const setShortCut = useSetAtom(shortCutAtom);

const minListRef = useRef<FlatList<number> | null>();
const minOffsetYRef = useRef<number>(0);

const resetTimer = () => {
setShortCut(null);
setTimingClose(null);
};

const onMinMomentumScrollEnd = useCallback(
debounce(
() => {
selectedMin = `${(minOffsetYRef.current / ITEM_HEIGHT).toFixed(
0,
)}`;
minListRef.current?.scrollToIndex({
index: +selectedMin,
});
},
50,
{
leading: false,
trailing: true,
},
),
[],
);

return (
<View style={numScrollStyles.customTime}>
<View style={numScrollStyles.listWrapper}>
<FlatList
ListHeaderComponent={EmptyItem}
ListFooterComponent={EmptyItem}
getItemLayout={(_, index) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index,
})}
onMomentumScrollEnd={e => {
selectedHour = `${(
e.nativeEvent.contentOffset.y / ITEM_HEIGHT
).toFixed(0)}`;
}}
onScrollEndDrag={e => {
selectedHour = `${(
e.nativeEvent.contentOffset.y / ITEM_HEIGHT
).toFixed(0)}`;
}}
onScrollBeginDrag={() => {
resetTimer();
}}
disableIntervalMomentum
snapToInterval={ITEM_HEIGHT}
style={numScrollStyles.list}
contentContainerStyle={numScrollStyles.listContent}
data={hours}
renderItem={({item}) => (
<ThemeText style={numScrollStyles.item}>
{item}
</ThemeText>
)}
/>
<FlatList
ref={ref => {
minListRef.current = ref;
}}
ListHeaderComponent={EmptyItem}
ListFooterComponent={EmptyItem}
style={[numScrollStyles.list, numScrollStyles.minList]}
contentContainerStyle={numScrollStyles.listContent}
getItemLayout={(_, index) => ({
length: ITEM_HEIGHT,
offset: ITEM_HEIGHT * index,
index,
})}
initialScrollIndex={15}
onScrollBeginDrag={() => {
resetTimer();
}}
onMomentumScrollEnd={e => {
minOffsetYRef.current = e.nativeEvent.contentOffset.y;
onMinMomentumScrollEnd();
}}
onScrollEndDrag={e => {
selectedMin = `${(
e.nativeEvent.contentOffset.y / ITEM_HEIGHT
).toFixed(0)}`;
}}
data={minutes}
renderItem={({item}) => (
<ThemeText style={numScrollStyles.item}>
{item}
</ThemeText>
)}
/>
<View
style={numScrollStyles.topBanner}
pointerEvents={'none'}
/>
<View
style={numScrollStyles.bottomBanner}
pointerEvents={'none'}
/>
</View>
</View>
);
}

const numScrollStyles = StyleSheet.create({
customTime: {
marginTop: rpx(72),
flex: 1,
},
listWrapper: {
flexDirection: 'row',
},
emptyItem: {
width: '100%',
height: ITEM_HEIGHT,
},
list: {
height: 3 * ITEM_HEIGHT,
},
minList: {
marginLeft: rpx(28),
},
listContent: {
width: '100%',
},
item: {
height: ITEM_HEIGHT,
width: rpx(120),
textAlign: 'center',
textAlignVertical: 'center',
},
topBanner: {
position: 'absolute',
height: ITEM_HEIGHT,
width: '100%',
top: 0,
left: 0,
backgroundColor: '#aaaaaa33',
borderBottomColor: '#666666',
borderBottomWidth: 1,
},
bottomBanner: {
position: 'absolute',
height: ITEM_HEIGHT,
width: '100%',
borderTopColor: '#666666',
borderTopWidth: 1,
bottom: 0,
left: 0,
backgroundColor: '#aaaaaa33',
},
});

export default function TimingClose() {
const {colors} = useTheme();
const highlightBgColor = useMemo(
() => Color(colors.textHighlight).alpha(0.3).toString(),
[colors],
);

const [selectedHour, setSelectedHour] = useAtom(selectedHourAtom);
const [selectedMin, setSelectedMin] = useAtom(selectMinAtom);
const [selectedShortCut, setSelectedShortCut] = useState<
15 | 30 | 45 | 60 | null
>(null);
const [selectedShortCut, setSelectedShortCut] = useAtom(shortCutAtom);

useEffect(() => {
return () => {
selectedHour = '0';
selectedMin = '15';
};
}, []);

return (
<PanelBase
Expand Down Expand Up @@ -118,28 +303,7 @@ export default function TimingClose() {
</TouchableOpacity>
))}
</View>
<View style={style.customTime}>
<TextInput
style={style.textInput}
keyboardType="number-pad"
maxLength={2}
value={selectedHour ?? ''}
onChangeText={t => {
setSelectedHour(t.trim());
}}
/>
<ThemeText>小时</ThemeText>
<TextInput
style={style.textInput}
maxLength={2}
keyboardType="number-pad"
value={selectedMin ?? ''}
onChangeText={t => {
setSelectedMin(t.trim());
}}
/>
<ThemeText>分钟</ThemeText>
</View>
<NumScrollView />
</View>
</>
)}
Expand Down

0 comments on commit b6622f0

Please sign in to comment.