Skip to content

Commit 50519a7

Browse files
committed
🐛 further fixes for initial scroll index to cover new scenarios created by repeatNumbersNTimes variables. Resolves #35
1 parent 8ced933 commit 50519a7

File tree

6 files changed

+85
-55
lines changed

6 files changed

+85
-55
lines changed

src/components/DurationScroll/index.tsx

Lines changed: 39 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ import {
2222
generateNumbers,
2323
} from "../../utils/generateNumbers";
2424
import { getAdjustedLimit } from "../../utils/getAdjustedLimit";
25-
import { getScrollIndex } from "../../utils/getScrollIndex";
25+
import { getDurationAndIndexFromScrollOffset } from "../../utils/getDurationAndIndexFromScrollOffset";
26+
import { getInitialScrollIndex } from "../../utils/getInitialScrollIndex";
2627

2728
import type { DurationScrollProps, DurationScrollRef } from "./types";
2829

@@ -66,7 +67,7 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
6667
return Math.round(repeatNumbersNTimes);
6768
}, [disableInfiniteScroll, repeatNumbersNTimes]);
6869

69-
const data = useMemo(() => {
70+
const numbersForFlatList = useMemo(() => {
7071
if (is12HourPicker) {
7172
return generate12HourNumbers({
7273
padNumbersWithZero,
@@ -93,7 +94,7 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
9394

9495
const initialScrollIndex = useMemo(
9596
() =>
96-
getScrollIndex({
97+
getInitialScrollIndex({
9798
numberOfItems,
9899
padWithNItems,
99100
repeatNumbersNTimes: safeRepeatNumbersNTimes,
@@ -107,8 +108,6 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
107108
]
108109
);
109110

110-
console.log(numberOfItems, initialScrollIndex);
111-
112111
const adjustedLimited = useMemo(
113112
() => getAdjustedLimit(limit, numberOfItems),
114113
[limit, numberOfItems]
@@ -165,7 +164,7 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
165164
setValue: (value, options) => {
166165
flatListRef.current?.scrollToIndex({
167166
animated: options?.animated ?? false,
168-
index: getScrollIndex({
167+
index: getInitialScrollIndex({
169168
numberOfItems,
170169
padWithNItems,
171170
repeatNumbersNTimes: safeRepeatNumbersNTimes,
@@ -245,25 +244,23 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
245244
}
246245

247246
if (aggressivelyGetLatestDuration) {
248-
const newIndex = Math.round(
249-
e.nativeEvent.contentOffset.y /
250-
styles.pickerItemContainer.height
251-
);
252-
let newDuration =
253-
(disableInfiniteScroll
254-
? newIndex
255-
: newIndex + padWithNItems) %
256-
(numberOfItems + 1);
247+
const newValues = getDurationAndIndexFromScrollOffset({
248+
disableInfiniteScroll,
249+
itemHeight: styles.pickerItemContainer.height,
250+
numberOfItems,
251+
padWithNItems,
252+
yContentOffset: e.nativeEvent.contentOffset.y,
253+
});
257254

258-
if (newDuration !== latestDuration.current) {
255+
if (newValues.duration !== latestDuration.current) {
259256
// check limits
260-
if (newDuration > adjustedLimited.max) {
261-
newDuration = adjustedLimited.max;
262-
} else if (newDuration < adjustedLimited.min) {
263-
newDuration = adjustedLimited.min;
257+
if (newValues.duration > adjustedLimited.max) {
258+
newValues.duration = adjustedLimited.max;
259+
} else if (newValues.duration < adjustedLimited.min) {
260+
newValues.duration = adjustedLimited.min;
264261
}
265262

266-
latestDuration.current = newDuration;
263+
latestDuration.current = newValues.duration;
267264
}
268265
}
269266

@@ -311,21 +308,20 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
311308

312309
const onMomentumScrollEnd = useCallback(
313310
(e: NativeSyntheticEvent<NativeScrollEvent>) => {
314-
const newIndex = Math.round(
315-
e.nativeEvent.contentOffset.y /
316-
styles.pickerItemContainer.height
317-
);
318-
let newDuration =
319-
(disableInfiniteScroll
320-
? newIndex
321-
: newIndex + padWithNItems) %
322-
(numberOfItems + 1);
311+
const newValues = getDurationAndIndexFromScrollOffset({
312+
disableInfiniteScroll,
313+
itemHeight: styles.pickerItemContainer.height,
314+
numberOfItems,
315+
padWithNItems,
316+
yContentOffset: e.nativeEvent.contentOffset.y,
317+
});
323318

324319
// check limits
325-
if (newDuration > adjustedLimited.max) {
320+
if (newValues.duration > adjustedLimited.max) {
326321
// TODO (NOW): make this work for a quick scroll
327322
const targetScrollIndex =
328-
newIndex - (newDuration - adjustedLimited.max);
323+
newValues.index -
324+
(newValues.duration - adjustedLimited.max);
329325
flatListRef.current?.scrollToIndex({
330326
animated: true,
331327
index:
@@ -334,27 +330,28 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
334330
? targetScrollIndex
335331
: adjustedLimited.max - 1,
336332
}); // scroll down to max
337-
newDuration = adjustedLimited.max;
338-
} else if (newDuration < adjustedLimited.min) {
333+
newValues.duration = adjustedLimited.max;
334+
} else if (newValues.duration < adjustedLimited.min) {
339335
const targetScrollIndex =
340-
newIndex + (adjustedLimited.min - newDuration);
336+
newValues.index +
337+
(adjustedLimited.min - newValues.duration);
341338
flatListRef.current?.scrollToIndex({
342339
animated: true,
343340
index:
344341
// guard against scrolling beyond end of list
345-
targetScrollIndex <= data.length - 1
342+
targetScrollIndex <= numbersForFlatList.length - 1
346343
? targetScrollIndex
347344
: adjustedLimited.min,
348345
}); // scroll up to min
349-
newDuration = adjustedLimited.min;
346+
newValues.duration = adjustedLimited.min;
350347
}
351348

352-
onDurationChange(newDuration);
349+
onDurationChange(newValues.duration);
353350
},
354351
[
355352
adjustedLimited.max,
356353
adjustedLimited.min,
357-
data.length,
354+
numbersForFlatList.length,
358355
disableInfiniteScroll,
359356
numberOfItems,
360357
onDurationChange,
@@ -380,7 +377,7 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
380377
) {
381378
flatListRef.current?.scrollToIndex({
382379
animated: false,
383-
index: viewableItems[0].index - numberOfItems - 1,
380+
index: viewableItems[0].index - numberOfItems,
384381
});
385382
}
386383
},
@@ -419,7 +416,7 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
419416
testID={testID}>
420417
<FlatList
421418
ref={flatListRef}
422-
data={data}
419+
data={numbersForFlatList}
423420
decelerationRate={0.88}
424421
getItemLayout={getItemLayout}
425422
initialScrollIndex={initialScrollIndex}
@@ -433,7 +430,7 @@ const DurationScroll = forwardRef<DurationScrollRef, DurationScrollProps>(
433430
showsVerticalScrollIndicator={false}
434431
snapToAlignment="start"
435432
// used in place of snapToOffset due to bug on Android
436-
snapToOffsets={[...Array(data.length)].map(
433+
snapToOffsets={[...Array(numbersForFlatList.length)].map(
437434
(_, i) => i * styles.pickerItemContainer.height
438435
)}
439436
testID="duration-scroll-flatlist"

src/components/TimerPicker/index.tsx

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,15 @@ const TimerPicker = forwardRef<TimerPickerRef, TimerPickerProps>(
5454
if (padWithNItems < 0) {
5555
return 0;
5656
}
57-
// check if large values also work
57+
58+
const maxPadWithNItems = hideHours ? 30 : 12;
59+
60+
if (padWithNItems > maxPadWithNItems) {
61+
return maxPadWithNItems;
62+
}
5863

5964
return Math.round(padWithNItems);
60-
}, [padWithNItems]);
65+
}, [hideHours, padWithNItems]);
6166

6267
const styles = useMemo(
6368
() =>
@@ -151,7 +156,7 @@ const TimerPicker = forwardRef<TimerPickerRef, TimerPickerProps>(
151156
hourLabel ?? (!use12HourPicker ? "h" : undefined)
152157
}
153158
limit={hourLimit}
154-
numberOfItems={23}
159+
numberOfItems={24}
155160
onDurationChange={setSelectedHours}
156161
padNumbersWithZero={padHoursWithZero}
157162
padWithNItems={safePadWithNItems}
@@ -174,7 +179,7 @@ const TimerPicker = forwardRef<TimerPickerRef, TimerPickerProps>(
174179
isDisabled={minutesPickerIsDisabled}
175180
label={minuteLabel ?? "m"}
176181
limit={minuteLimit}
177-
numberOfItems={59}
182+
numberOfItems={60}
178183
onDurationChange={setSelectedMinutes}
179184
padNumbersWithZero={padMinutesWithZero}
180185
padWithNItems={safePadWithNItems}
@@ -196,7 +201,7 @@ const TimerPicker = forwardRef<TimerPickerRef, TimerPickerProps>(
196201
isDisabled={secondsPickerIsDisabled}
197202
label={secondLabel ?? "s"}
198203
limit={secondLimit}
199-
numberOfItems={59}
204+
numberOfItems={60}
200205
onDurationChange={setSelectedSeconds}
201206
padNumbersWithZero={padSecondsWithZero}
202207
padWithNItems={safePadWithNItems}

src/utils/generateNumbers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export const generateNumbers = (
1414
}
1515

1616
let numbers: string[] = [];
17-
for (let i = 0; i <= numberOfItems; i++) {
17+
for (let i = 0; i < numberOfItems; i++) {
1818
numbers.push(padNumber(i, { padWithZero: options.padNumbersWithZero }));
1919
}
2020

src/utils/getAdjustedLimit.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,23 +7,25 @@ export const getAdjustedLimit = (
77
max: number;
88
min: number;
99
} => {
10+
const maxIndex = numberOfItems - 1;
11+
1012
if (!limit || (!limit.max && !limit.min)) {
1113
return {
12-
max: numberOfItems,
14+
max: maxIndex,
1315
min: 0,
1416
};
1517
}
1618

1719
// guard against limits that are out of bounds
1820
const adjustedMaxLimit = limit.max
19-
? Math.min(limit.max, numberOfItems)
20-
: numberOfItems;
21+
? Math.min(limit.max, maxIndex)
22+
: maxIndex;
2123
const adjustedMinLimit = limit.min ? Math.max(limit.min, 0) : 0;
2224

2325
// guard against invalid limits
2426
if (adjustedMaxLimit < adjustedMinLimit) {
2527
return {
26-
max: numberOfItems,
28+
max: maxIndex,
2729
min: 0,
2830
};
2931
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
export const getDurationAndIndexFromScrollOffset = (variables: {
2+
disableInfiniteScroll: boolean;
3+
itemHeight: number;
4+
numberOfItems: number;
5+
padWithNItems: number;
6+
yContentOffset: number;
7+
}) => {
8+
const {
9+
disableInfiniteScroll,
10+
itemHeight,
11+
numberOfItems,
12+
padWithNItems,
13+
yContentOffset,
14+
} = variables;
15+
16+
const index = Math.round(yContentOffset / itemHeight);
17+
18+
const duration =
19+
(disableInfiniteScroll ? index : index + padWithNItems) % numberOfItems;
20+
21+
return {
22+
duration,
23+
index,
24+
};
25+
};
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export const getScrollIndex = (variables: {
1+
export const getInitialScrollIndex = (variables: {
22
numberOfItems: number;
33
padWithNItems: number;
44
repeatNumbersNTimes: number;
@@ -8,8 +8,9 @@ export const getScrollIndex = (variables: {
88
variables;
99

1010
return Math.max(
11-
((value + numberOfItems) % (numberOfItems * repeatNumbersNTimes)) -
12-
(padWithNItems - 1),
11+
numberOfItems * Math.floor(repeatNumbersNTimes / 2) +
12+
((value + numberOfItems) % numberOfItems) -
13+
padWithNItems,
1314
0
1415
);
1516
};

0 commit comments

Comments
 (0)