Skip to content

Commit 96ab103

Browse files
committed
fix(timepicker): selecting 12pm returns 24 hrs
1 parent 8ce85da commit 96ab103

File tree

5 files changed

+89
-48
lines changed

5 files changed

+89
-48
lines changed

src/Time/AmPmSwitcher.tsx

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,17 @@ import { View, StyleSheet } from 'react-native'
33
import { Text, TouchableRipple, useTheme } from 'react-native-paper'
44
import { useMemo } from 'react'
55
import Color from 'color'
6-
import { getHourType, hourTypes, useSwitchColors } from './timeUtils'
6+
import { useSwitchColors } from './timeUtils'
7+
import { DisplayModeContext } from './TimePicker'
78

89
export default function AmPmSwitcher({
9-
hours,
1010
onChange,
11+
hours,
1112
}: {
1213
hours: number
1314
onChange: (hours: number) => any
1415
}) {
16+
const { setMode, mode } = React.useContext(DisplayModeContext)
1517
const theme = useTheme()
1618
const backgroundColor = useMemo<string>(() => {
1719
if (theme.dark) {
@@ -20,10 +22,7 @@ export default function AmPmSwitcher({
2022
return Color(theme.colors.surface).darken(0.1).hex()
2123
}, [theme])
2224

23-
const hourType = getHourType(hours)
24-
const isAM = hourType === hourTypes.am
25-
const isPM = hourType === hourTypes.pm
26-
25+
const isAM = mode === 'AM'
2726
return (
2827
<View
2928
style={[
@@ -36,16 +35,26 @@ export default function AmPmSwitcher({
3635
>
3736
<SwitchButton
3837
label="AM"
39-
onPress={isAM ? undefined : () => onChange(hours - 12)}
38+
onPress={() => {
39+
setMode('AM')
40+
if (hours - 12 >= 0) {
41+
onChange(hours - 12)
42+
}
43+
}}
4044
selected={isAM}
4145
disabled={isAM}
4246
/>
4347
<View style={[styles.switchSeparator, { backgroundColor }]} />
4448
<SwitchButton
4549
label="PM"
46-
onPress={isPM ? undefined : () => onChange(hours + 12)}
47-
selected={isPM}
48-
disabled={isPM}
50+
onPress={() => {
51+
setMode('PM')
52+
if (hours + 12 <= 24) {
53+
onChange(hours + 12)
54+
}
55+
}}
56+
selected={!isAM}
57+
disabled={!isAM}
4958
/>
5059
</View>
5160
)

src/Time/AnalogClock.tsx

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,7 @@ import {
1212
getAngle,
1313
getHours,
1414
getHourType,
15-
getHourTypeFromOffset,
1615
getMinutes,
17-
hourTypes,
1816
PossibleClockTypes,
1917
} from './timeUtils'
2018
import * as React from 'react'
@@ -24,6 +22,7 @@ import AnalogClockHours from './AnalogClockHours'
2422

2523
import AnimatedClockSwitcher from './AnimatedClockSwitcher'
2624
import AnalogClockMinutes from './AnalogClockMinutes'
25+
import { DisplayModeContext } from './TimePicker'
2726

2827
function AnalogClock({
2928
hours,
@@ -47,7 +46,7 @@ function AnalogClock({
4746
}) => any
4847
}) {
4948
const theme = useTheme()
50-
49+
const { mode } = React.useContext(DisplayModeContext)
5150
// used to make pointer shorter if hours are selected and above 12
5251
const shortPointer = (hours === 0 || hours > 12) && is24Hour
5352

@@ -60,6 +59,7 @@ function AnalogClock({
6059
const minutesRef = useLatest(minutes)
6160
const focusedRef = useLatest(focused)
6261
const is24HourRef = useLatest(is24Hour)
62+
const modeRef = useLatest(mode)
6363

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

76-
let hourTypeFromOffset = getHourTypeFromOffset(x, y, circleSize)
77-
let hours24AndPM = hours24 && hourTypeFromOffset === hourTypes.pm
78-
let hours12AndPm = !hours24 && previousHourType === hourTypes.pm
79-
80-
// TODO: check which mode is switched on am/pm
81-
if (hours12AndPm || hours24AndPM) {
76+
let hours12AndPm = !hours24 && modeRef.current === 'PM'
77+
// Avoiding the "24h"
78+
// Should be 12h for 12 hours and PM mode
79+
if ((hours12AndPm || hours24) && pickedHours + 12 < 24) {
8280
pickedHours += 12
8381
}
8482

@@ -103,7 +101,7 @@ function AnalogClock({
103101
}
104102
}
105103
},
106-
[focusedRef, is24HourRef, hoursRef, onChangeRef, minutesRef]
104+
[focusedRef, is24HourRef, hoursRef, onChangeRef, minutesRef, modeRef]
107105
)
108106

109107
const panResponder = React.useRef(

src/Time/AnalogClockHours.tsx

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { View, StyleSheet } from 'react-native'
33
import { Text } from 'react-native-paper'
44
import { circleSize } from './timeUtils'
55
import { useTextColorOnPrimary } from '../utils'
6+
import { DisplayModeContext } from './TimePicker'
67

78
function AnalogClockHours({
89
is24Hour,
@@ -11,9 +12,11 @@ function AnalogClockHours({
1112
is24Hour: boolean
1213
hours: number
1314
}) {
14-
const outerRange = getHourNumbers(false, circleSize, 12)
15-
const innerRange = getHourNumbers(true, circleSize, 12)
15+
const { mode } = React.useContext(DisplayModeContext)
16+
const outerRange = getHourNumbers(false, circleSize, 12, 12)
17+
const innerRange = getHourNumbers(true, circleSize, 12, 12)
1618
const color = useTextColorOnPrimary()
19+
1720
return (
1821
<>
1922
{outerRange.map((a, i) => (
@@ -29,8 +32,9 @@ function AnalogClockHours({
2932
]}
3033
>
3134
<View style={styles.outerHourInner}>
35+
{/* Display 00 instead of 12 for AM hours */}
3236
<Text style={hours === i + 1 ? { color } : null} selectable={false}>
33-
{i + 1}
37+
{mode === 'AM' && i + 1 === 12 ? '00' : i + 1}
3438
</Text>
3539
</View>
3640
</View>
@@ -97,14 +101,19 @@ const styles = StyleSheet.create({
97101
innerHourText: { fontSize: 13 },
98102
})
99103

100-
function getHourNumbers(is24Hour: boolean, size: number, count: number) {
104+
function getHourNumbers(
105+
is24Hour: boolean,
106+
size: number,
107+
count: number,
108+
arrayLength: number
109+
) {
101110
let angle = 0
102111
let step = (2 * Math.PI) / count
103112
let radius = size / (is24Hour ? 4 : 2.5)
104113

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

107-
return Array(12)
116+
return Array(arrayLength)
108117
.fill(true)
109118
.map(() => {
110119
let x = Math.round(size / 2 + radius * Math.cos(angle))

src/Time/TimePicker.tsx

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ import AnalogClock from './AnalogClock'
1313
import { circleSize } from './timeUtils'
1414
import TimeInputs from './TimeInputs'
1515

16+
export const DisplayModeContext = React.createContext<{
17+
mode: 'AM' | 'PM' | undefined
18+
setMode: React.Dispatch<React.SetStateAction<'AM' | 'PM' | undefined>>
19+
}>({ mode: 'AM', setMode: () => {} })
20+
1621
type onChangeFunc = ({
1722
hours,
1823
minutes,
@@ -40,6 +45,9 @@ function TimePicker({
4045
onFocusInput: (type: PossibleClockTypes) => any
4146
onChange: onChangeFunc
4247
}) {
48+
const [displayMode, setDisplayMode] = React.useState<'AM' | 'PM' | undefined>(
49+
undefined
50+
)
4351
const dimensions = useWindowDimensions()
4452
const isLandscape = dimensions.width > dimensions.height
4553

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

65+
// Initialize display Mode according the hours value
66+
React.useEffect(() => {
67+
if (hours >= 12) {
68+
setDisplayMode('PM')
69+
} else {
70+
setDisplayMode('AM')
71+
}
72+
// eslint-disable-next-line react-hooks/exhaustive-deps
73+
}, [])
74+
5775
const onInnerChange = React.useCallback<onChangeFunc>(
5876
(params) => {
5977
params.hours = toHourOutputFormat(params.hours, hours, is24Hour)
@@ -63,28 +81,32 @@ function TimePicker({
6381
)
6482

6583
return (
66-
<View style={isLandscape ? styles.rootLandscape : styles.rootPortrait}>
67-
<TimeInputs
68-
inputType={inputType}
69-
hours={hours}
70-
minutes={minutes}
71-
is24Hour={is24Hour}
72-
onChange={onChange}
73-
onFocusInput={onFocusInput}
74-
focused={focused}
75-
/>
76-
{inputType === inputTypes.picker ? (
77-
<View style={styles.clockContainer}>
78-
<AnalogClock
79-
hours={toHourInputFormat(hours, is24Hour)}
80-
minutes={minutes}
81-
focused={focused}
82-
is24Hour={is24Hour}
83-
onChange={onInnerChange}
84-
/>
85-
</View>
86-
) : null}
87-
</View>
84+
<DisplayModeContext.Provider
85+
value={{ mode: displayMode, setMode: setDisplayMode }}
86+
>
87+
<View style={isLandscape ? styles.rootLandscape : styles.rootPortrait}>
88+
<TimeInputs
89+
inputType={inputType}
90+
hours={hours}
91+
minutes={minutes}
92+
is24Hour={is24Hour}
93+
onChange={onChange}
94+
onFocusInput={onFocusInput}
95+
focused={focused}
96+
/>
97+
{inputType === inputTypes.picker ? (
98+
<View style={styles.clockContainer}>
99+
<AnalogClock
100+
hours={toHourInputFormat(hours, is24Hour)}
101+
minutes={minutes}
102+
focused={focused}
103+
is24Hour={is24Hour}
104+
onChange={onInnerChange}
105+
/>
106+
</View>
107+
) : null}
108+
</View>
109+
</DisplayModeContext.Provider>
88110
)
89111
}
90112

src/Time/timeUtils.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,9 @@ export function useInputColors(highlighted: boolean) {
199199
}
200200

201201
export function toHourInputFormat(hours: number, is24Hour: boolean): number {
202+
if (hours === 24) {
203+
return 0
204+
}
202205
if (is24Hour) {
203206
return hours
204207
}
@@ -216,7 +219,7 @@ export function toHourOutputFormat(
216219
if (is24Hour) {
217220
return newHours
218221
}
219-
if (previousHours > 12 && newHours <= 12) {
222+
if (previousHours > 12 && newHours < 12) {
220223
return newHours + 12
221224
}
222225
return newHours

0 commit comments

Comments
 (0)