Untitled

mail@pastecode.io avatar
unknown
plain_text
a month ago
3.8 kB
1
Indexable
Never
import { ThemedText } from '@/components/ThemedText'
import { ThemedView } from '@/components/ThemedView'
import React, { FC, useState } from 'react'
import { FlatList, NativeScrollEvent, NativeSyntheticEvent, StyleSheet, View } from 'react-native'
import { SharedValue, useSharedValue } from 'react-native-reanimated'

const hoursArray = Array.from({ length: 12 }, (_, i) => (i + 1).toString().padStart(2, '0'))
const minutesArray = Array.from({ length: 60 }, (_, i) => i.toString().padStart(2, '0'))

const ranges = [['AM', 'PM'], hoursArray, minutesArray]

const ITEM_HEIGHT = 60

type ListComponentProps = {
  item: string
  index: number
  contentOffset: SharedValue<number>
}

const ListComponent: FC<ListComponentProps> = ({ item, index, contentOffset }) => {
  // const animatedStyle = useAnimatedStyle(() => ({
  //   opacity: interpolate(
  //     contentOffset.value,
  //     [index * ITEM_HEIGHT - ITEM_HEIGHT, index * ITEM_HEIGHT, index * ITEM_HEIGHT + ITEM_HEIGHT],
  //     [0.25, 1, 0.25],
  //     'clamp'
  //   ),
  // }))

  return (
    <View
      style={[
        styles.viewText,
        { height: ITEM_HEIGHT, opacity: contentOffset.value === index * ITEM_HEIGHT ? 1 : 0.25 },
      ]}
    >
      <ThemedText style={styles.text}>{item}</ThemedText>
    </View>
  )
}

const Time = () => {
  //
  const [output, setOutput] = useState({
    hours: '00',
    minutes: '00',
    ampm: 'AM',
  })

  function handleChange(e: NativeSyntheticEvent<NativeScrollEvent>, rangeIndex: number) {
    const value = e.nativeEvent.contentOffset.y
    const itemIndex = Math.round(value / ITEM_HEIGHT)

    if (rangeIndex === 0) {
      setOutput(prev => ({ ...prev, ampm: ranges[rangeIndex][itemIndex] }))
    } else if (rangeIndex === 1) {
      setOutput(prev => ({ ...prev, hours: ranges[rangeIndex][itemIndex] }))
    } else {
      setOutput(prev => ({ ...prev, minutes: ranges[rangeIndex][itemIndex] }))
    }
  }

  return (
    <ThemedView style={styles.container}>
      <View
        style={[
          styles.verticalSplitter,
          {
            height: ITEM_HEIGHT * 3, // 5 items rendered, just to have a longer scroll area
          },
        ]}
      >
        {ranges.map((range, rangeIndex) => {
          const paddingVertical = ITEM_HEIGHT
          const contentOffset = useSharedValue(0)

          return (
            <FlatList
              key={rangeIndex}
              data={range}
              contentContainerStyle={{
                alignItems: 'center',
                paddingVertical,
              }}
              keyExtractor={(item, idx) => rangeIndex + idx + item}
              renderItem={props => <ListComponent {...props} contentOffset={contentOffset} />}
              snapToInterval={ITEM_HEIGHT}
              decelerationRate={'fast'}
              overScrollMode='never'
              bounces={false}
              scrollEventThrottle={16}
              onScroll={e => {
                contentOffset.value = e.nativeEvent.contentOffset.y
              }}
              showsVerticalScrollIndicator={false}
              onScrollEndDrag={e => handleChange(e, rangeIndex)}
              onMomentumScrollEnd={e => handleChange(e, rangeIndex)}
            />
          )
        })}
      </View>

      <ThemedText>{`Output: ${output.hours} ${output.minutes} ${output.ampm}`}</ThemedText>
    </ThemedView>
  )
}

export default Time

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  verticalSplitter: {
    width: '100%',
    flexDirection: 'row',
    justifyContent: 'space-evenly',
  },
  viewText: {
    justifyContent: 'center',
    alignItems: 'center',
  },
  text: {
    fontSize: 48,
    lineHeight: 48,
    fontWeight: '700',
  },
})
Leave a Comment