Skip to content

Commit

Permalink
Merge pull request #110 from J3j3m/Fixes/#105
Browse files Browse the repository at this point in the history
fix(timepicker): selecting 12pm returns 24 hrs
  • Loading branch information
RichardLindhout committed Oct 20, 2021
2 parents 8ce85da + 96ab103 commit c779747
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 48 deletions.
29 changes: 19 additions & 10 deletions src/Time/AmPmSwitcher.tsx
Expand Up @@ -3,15 +3,17 @@ import { View, StyleSheet } from 'react-native'
import { Text, TouchableRipple, useTheme } from 'react-native-paper'
import { useMemo } from 'react'
import Color from 'color'
import { getHourType, hourTypes, useSwitchColors } from './timeUtils'
import { useSwitchColors } from './timeUtils'
import { DisplayModeContext } from './TimePicker'

export default function AmPmSwitcher({
hours,
onChange,
hours,
}: {
hours: number
onChange: (hours: number) => any
}) {
const { setMode, mode } = React.useContext(DisplayModeContext)
const theme = useTheme()
const backgroundColor = useMemo<string>(() => {
if (theme.dark) {
Expand All @@ -20,10 +22,7 @@ export default function AmPmSwitcher({
return Color(theme.colors.surface).darken(0.1).hex()
}, [theme])

const hourType = getHourType(hours)
const isAM = hourType === hourTypes.am
const isPM = hourType === hourTypes.pm

const isAM = mode === 'AM'
return (
<View
style={[
Expand All @@ -36,16 +35,26 @@ export default function AmPmSwitcher({
>
<SwitchButton
label="AM"
onPress={isAM ? undefined : () => onChange(hours - 12)}
onPress={() => {
setMode('AM')
if (hours - 12 >= 0) {
onChange(hours - 12)
}
}}
selected={isAM}
disabled={isAM}
/>
<View style={[styles.switchSeparator, { backgroundColor }]} />
<SwitchButton
label="PM"
onPress={isPM ? undefined : () => onChange(hours + 12)}
selected={isPM}
disabled={isPM}
onPress={() => {
setMode('PM')
if (hours + 12 <= 24) {
onChange(hours + 12)
}
}}
selected={!isAM}
disabled={!isAM}
/>
</View>
)
Expand Down
18 changes: 8 additions & 10 deletions src/Time/AnalogClock.tsx
Expand Up @@ -12,9 +12,7 @@ import {
getAngle,
getHours,
getHourType,
getHourTypeFromOffset,
getMinutes,
hourTypes,
PossibleClockTypes,
} from './timeUtils'
import * as React from 'react'
Expand All @@ -24,6 +22,7 @@ import AnalogClockHours from './AnalogClockHours'

import AnimatedClockSwitcher from './AnimatedClockSwitcher'
import AnalogClockMinutes from './AnalogClockMinutes'
import { DisplayModeContext } from './TimePicker'

function AnalogClock({
hours,
Expand All @@ -47,7 +46,7 @@ function AnalogClock({
}) => any
}) {
const theme = useTheme()

const { mode } = React.useContext(DisplayModeContext)
// used to make pointer shorter if hours are selected and above 12
const shortPointer = (hours === 0 || hours > 12) && is24Hour

Expand All @@ -60,6 +59,7 @@ function AnalogClock({
const minutesRef = useLatest(minutes)
const focusedRef = useLatest(focused)
const is24HourRef = useLatest(is24Hour)
const modeRef = useLatest(mode)

const onPointerMove = React.useCallback(
(e: GestureResponderEvent, final: boolean) => {
Expand All @@ -73,12 +73,10 @@ function AnalogClock({
let previousHourType = getHourType(hoursRef.current)
let pickedHours = getHours(angle, previousHourType)

let hourTypeFromOffset = getHourTypeFromOffset(x, y, circleSize)
let hours24AndPM = hours24 && hourTypeFromOffset === hourTypes.pm
let hours12AndPm = !hours24 && previousHourType === hourTypes.pm

// TODO: check which mode is switched on am/pm
if (hours12AndPm || hours24AndPM) {
let hours12AndPm = !hours24 && modeRef.current === 'PM'
// Avoiding the "24h"
// Should be 12h for 12 hours and PM mode
if ((hours12AndPm || hours24) && pickedHours + 12 < 24) {
pickedHours += 12
}

Expand All @@ -103,7 +101,7 @@ function AnalogClock({
}
}
},
[focusedRef, is24HourRef, hoursRef, onChangeRef, minutesRef]
[focusedRef, is24HourRef, hoursRef, onChangeRef, minutesRef, modeRef]
)

const panResponder = React.useRef(
Expand Down
19 changes: 14 additions & 5 deletions src/Time/AnalogClockHours.tsx
Expand Up @@ -3,6 +3,7 @@ import { View, StyleSheet } from 'react-native'
import { Text } from 'react-native-paper'
import { circleSize } from './timeUtils'
import { useTextColorOnPrimary } from '../utils'
import { DisplayModeContext } from './TimePicker'

function AnalogClockHours({
is24Hour,
Expand All @@ -11,9 +12,11 @@ function AnalogClockHours({
is24Hour: boolean
hours: number
}) {
const outerRange = getHourNumbers(false, circleSize, 12)
const innerRange = getHourNumbers(true, circleSize, 12)
const { mode } = React.useContext(DisplayModeContext)
const outerRange = getHourNumbers(false, circleSize, 12, 12)
const innerRange = getHourNumbers(true, circleSize, 12, 12)
const color = useTextColorOnPrimary()

return (
<>
{outerRange.map((a, i) => (
Expand All @@ -29,8 +32,9 @@ function AnalogClockHours({
]}
>
<View style={styles.outerHourInner}>
{/* Display 00 instead of 12 for AM hours */}
<Text style={hours === i + 1 ? { color } : null} selectable={false}>
{i + 1}
{mode === 'AM' && i + 1 === 12 ? '00' : i + 1}
</Text>
</View>
</View>
Expand Down Expand Up @@ -97,14 +101,19 @@ const styles = StyleSheet.create({
innerHourText: { fontSize: 13 },
})

function getHourNumbers(is24Hour: boolean, size: number, count: number) {
function getHourNumbers(
is24Hour: boolean,
size: number,
count: number,
arrayLength: number
) {
let angle = 0
let step = (2 * Math.PI) / count
let radius = size / (is24Hour ? 4 : 2.5)

angle = (-90 * Math.PI) / 180 + Math.PI / 6

return Array(12)
return Array(arrayLength)
.fill(true)
.map(() => {
let x = Math.round(size / 2 + radius * Math.cos(angle))
Expand Down
66 changes: 44 additions & 22 deletions src/Time/TimePicker.tsx
Expand Up @@ -13,6 +13,11 @@ import AnalogClock from './AnalogClock'
import { circleSize } from './timeUtils'
import TimeInputs from './TimeInputs'

export const DisplayModeContext = React.createContext<{
mode: 'AM' | 'PM' | undefined
setMode: React.Dispatch<React.SetStateAction<'AM' | 'PM' | undefined>>
}>({ mode: 'AM', setMode: () => {} })

type onChangeFunc = ({
hours,
minutes,
Expand Down Expand Up @@ -40,6 +45,9 @@ function TimePicker({
onFocusInput: (type: PossibleClockTypes) => any
onChange: onChangeFunc
}) {
const [displayMode, setDisplayMode] = React.useState<'AM' | 'PM' | undefined>(
undefined
)
const dimensions = useWindowDimensions()
const isLandscape = dimensions.width > dimensions.height

Expand All @@ -54,6 +62,16 @@ function TimePicker({
return formatted.includes('23')
}, [locale])

// Initialize display Mode according the hours value
React.useEffect(() => {
if (hours >= 12) {
setDisplayMode('PM')
} else {
setDisplayMode('AM')
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])

const onInnerChange = React.useCallback<onChangeFunc>(
(params) => {
params.hours = toHourOutputFormat(params.hours, hours, is24Hour)
Expand All @@ -63,28 +81,32 @@ function TimePicker({
)

return (
<View style={isLandscape ? styles.rootLandscape : styles.rootPortrait}>
<TimeInputs
inputType={inputType}
hours={hours}
minutes={minutes}
is24Hour={is24Hour}
onChange={onChange}
onFocusInput={onFocusInput}
focused={focused}
/>
{inputType === inputTypes.picker ? (
<View style={styles.clockContainer}>
<AnalogClock
hours={toHourInputFormat(hours, is24Hour)}
minutes={minutes}
focused={focused}
is24Hour={is24Hour}
onChange={onInnerChange}
/>
</View>
) : null}
</View>
<DisplayModeContext.Provider
value={{ mode: displayMode, setMode: setDisplayMode }}
>
<View style={isLandscape ? styles.rootLandscape : styles.rootPortrait}>
<TimeInputs
inputType={inputType}
hours={hours}
minutes={minutes}
is24Hour={is24Hour}
onChange={onChange}
onFocusInput={onFocusInput}
focused={focused}
/>
{inputType === inputTypes.picker ? (
<View style={styles.clockContainer}>
<AnalogClock
hours={toHourInputFormat(hours, is24Hour)}
minutes={minutes}
focused={focused}
is24Hour={is24Hour}
onChange={onInnerChange}
/>
</View>
) : null}
</View>
</DisplayModeContext.Provider>
)
}

Expand Down
5 changes: 4 additions & 1 deletion src/Time/timeUtils.ts
Expand Up @@ -199,6 +199,9 @@ export function useInputColors(highlighted: boolean) {
}

export function toHourInputFormat(hours: number, is24Hour: boolean): number {
if (hours === 24) {
return 0
}
if (is24Hour) {
return hours
}
Expand All @@ -216,7 +219,7 @@ export function toHourOutputFormat(
if (is24Hour) {
return newHours
}
if (previousHours > 12 && newHours <= 12) {
if (previousHours > 12 && newHours < 12) {
return newHours + 12
}
return newHours
Expand Down

0 comments on commit c779747

Please sign in to comment.