Skip to content

Commit 7988085

Browse files
author
maciej.lodygowski
committed
fix: add limit check with warning
1 parent 478e950 commit 7988085

File tree

5 files changed

+91
-32
lines changed

5 files changed

+91
-32
lines changed

package/android/src/main/java/com/reactnativecommunity/slider/ReactSlider.java

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import android.graphics.BitmapFactory;
1212
import android.graphics.drawable.BitmapDrawable;
1313
import android.os.Build;
14+
import android.util.Log;
1415
import android.util.AttributeSet;
1516
import android.view.accessibility.AccessibilityEvent;
1617
import android.view.accessibility.AccessibilityManager;
@@ -105,15 +106,13 @@ private void disableStateListAnimatorIfNeeded() {
105106
}
106107

107108
/*package*/ int getValidProgressValue(int progress) {
108-
if (getLowerLimit() <= getUpperLimit()) {
109-
if (progress < getLowerLimit()) {
110-
progress = getLowerLimit();
111-
} else if (progress > getUpperLimit()) {
112-
progress = getUpperLimit();
113-
}
109+
if (progress < getLowerLimit()) {
110+
progress = getLowerLimit();
111+
} else if (progress > getUpperLimit()) {
112+
progress = getUpperLimit();
114113
}
115114
return progress;
116-
}
115+
}
117116

118117
/* package */ void setValue(double value) {
119118
mValue = value;
@@ -233,16 +232,28 @@ private void updateAll() {
233232
updateValue();
234233
}
235234

236-
/** Update limit based on props limit, max and min */
235+
/** Update limit based on props limit, max and min
236+
* Fallback to upper limit if invalid configuration provided
237+
*/
237238
private void updateLowerLimit() {
238239
double limit = Math.max(mRealLowerLimit, mMinValue);
239-
mLowerLimit = (int) Math.round((limit - mMinValue) / (mMaxValue - mMinValue) * getTotalSteps());
240+
int lowerLimit = (int) Math.round((limit - mMinValue) / (mMaxValue - mMinValue) * getTotalSteps());
241+
if(lowerLimit > mUpperLimit) {
242+
Log.w("Invalid configuration", "reverting lower limit to upper limit");
243+
}
244+
mLowerLimit = Math.min(lowerLimit, mUpperLimit);
240245
}
241246

242-
/** Update limit based on props limit, max and min */
247+
/** Update limit based on props limit, max and min
248+
* Fallback to lower limit if invalid configuration provided
249+
*/
243250
private void updateUpperLimit() {
244251
double limit = Math.min(mRealUpperLimit, mMaxValue);
245-
mUpperLimit = (int) Math.round((limit - mMinValue) / (mMaxValue - mMinValue) * getTotalSteps());
252+
int upperLimit = (int) Math.round((limit - mMinValue) / (mMaxValue - mMinValue) * getTotalSteps());
253+
if(mLowerLimit > upperLimit) {
254+
Log.w("Invalid configuration", "reverting upper limit to equal to lower limit");
255+
}
256+
mUpperLimit = Math.max(upperLimit, mLowerLimit);
246257
}
247258

248259
/** Update value only (optimization in case only value is set). */

package/ios/RNCSlider.m

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ @implementation RNCSlider
1414
bool _maximumTrackImageSet;
1515
}
1616

17+
- (instancetype)init {
18+
if (self = [super init]) {
19+
_upperLimit = FLT_MAX;
20+
_lowerLimit = FLT_MIN;
21+
}
22+
return self;
23+
}
24+
1725
- (instancetype)initWithFrame:(CGRect)frame
1826
{
1927
return [super initWithFrame:frame];
@@ -46,7 +54,7 @@ - (void)setupAccessibility:(float)value
4654
if (sliderValue && [sliderValue intValue] == 1) {
4755
spokenUnits = [spokenUnits substringToIndex:stringLength-1];
4856
}
49-
57+
5058
self.accessibilityValue = [NSString stringWithFormat:@"%@ %@", sliderValue, spokenUnits];
5159
}
5260
}

package/ios/RNCSliderComponentView.mm

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,12 @@ - (instancetype)initWithFrame:(CGRect)frame
4747
forControlEvents:(UIControlEventTouchUpInside |
4848
UIControlEventTouchUpOutside |
4949
UIControlEventTouchCancel)];
50-
50+
5151
UITapGestureRecognizer *tapGesturer;
5252
tapGesturer = [[UITapGestureRecognizer alloc] initWithTarget: self action:@selector(tapHandler:)];
5353
[tapGesturer setNumberOfTapsRequired: 1];
5454
[slider addGestureRecognizer:tapGesturer];
55-
55+
5656
slider.value = (float)defaultProps->value;
5757
self.contentView = slider;
5858
}
@@ -65,12 +65,12 @@ - (void)tapHandler:(UITapGestureRecognizer *)gesture {
6565
}
6666
RNCSlider *slider = (RNCSlider *)gesture.view;
6767
slider.isSliding = _isSliding;
68-
68+
6969
// Ignore this tap if in the middle of a slide.
7070
if (_isSliding) {
7171
return;
7272
}
73-
73+
7474
if (!slider.tapToSeek) {
7575
return;
7676
}
@@ -88,14 +88,14 @@ - (void)tapHandler:(UITapGestureRecognizer *)gesture {
8888
}
8989

9090
[slider setValue:[slider discreteValue:value] animated: YES];
91-
91+
9292
std::dynamic_pointer_cast<const RNCSliderEventEmitter>(_eventEmitter)
9393
->onRNCSliderSlidingStart(RNCSliderEventEmitter::OnRNCSliderSlidingStart{.value = static_cast<Float>(slider.lastValue)});
94-
94+
9595
// Trigger onValueChange to address https://github.com/react-native-community/react-native-slider/issues/212
9696
std::dynamic_pointer_cast<const RNCSliderEventEmitter>(_eventEmitter)
9797
->onRNCSliderValueChange(RNCSliderEventEmitter::OnRNCSliderValueChange{.value = static_cast<Float>(slider.value)});
98-
98+
9999
std::dynamic_pointer_cast<const RNCSliderEventEmitter>(_eventEmitter)
100100
->onRNCSliderSlidingComplete(RNCSliderEventEmitter::OnRNCSliderSlidingComplete{.value = static_cast<Float>(slider.value)});
101101
}
@@ -122,7 +122,7 @@ - (void)sliderTouchEnd:(RNCSlider *)sender
122122
- (void)RNCSendSliderEvent:(RNCSlider *)sender withContinuous:(BOOL)continuous isSlidingStart:(BOOL)isSlidingStart
123123
{
124124
float value = [sender discreteValue:sender.value];
125-
125+
126126
if (value < sender.lowerLimit) {
127127
value = sender.lowerLimit;
128128
[sender setValue:value animated:NO];
@@ -134,7 +134,7 @@ - (void)RNCSendSliderEvent:(RNCSlider *)sender withContinuous:(BOOL)continuous i
134134
if(!sender.isSliding) {
135135
[sender setValue:value animated:NO];
136136
}
137-
137+
138138
if (continuous) {
139139
if (sender.lastValue != value) {
140140
std::dynamic_pointer_cast<const RNCSliderEventEmitter>(_eventEmitter)
@@ -150,15 +150,15 @@ - (void)RNCSendSliderEvent:(RNCSlider *)sender withContinuous:(BOOL)continuous i
150150
->onRNCSliderSlidingStart(RNCSliderEventEmitter::OnRNCSliderSlidingStart{.value = static_cast<Float>(value)});
151151
}
152152
}
153-
153+
154154
sender.lastValue = value;
155155
}
156156

157157
- (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &)oldProps
158158
{
159159
const auto &oldScreenProps = *std::static_pointer_cast<const RNCSliderProps>(_props);
160160
const auto &newScreenProps = *std::static_pointer_cast<const RNCSliderProps>(props);
161-
161+
162162
if (oldScreenProps.value != newScreenProps.value) {
163163
if (!slider.isSliding) {
164164
slider.value = newScreenProps.value;
@@ -176,12 +176,7 @@ - (void)updateProps:(const Props::Shared &)props oldProps:(const Props::Shared &
176176
if (oldScreenProps.maximumValue != newScreenProps.maximumValue) {
177177
[slider setMaximumValue:newScreenProps.maximumValue];
178178
}
179-
if (oldScreenProps.lowerLimit != newScreenProps.lowerLimit) {
180-
slider.lowerLimit = newScreenProps.lowerLimit;
181-
}
182-
if (oldScreenProps.upperLimit != newScreenProps.upperLimit) {
183-
slider.upperLimit = newScreenProps.upperLimit;
184-
}
179+
updateLimits(slider, newScreenProps.lowerLimit, newScreenProps.upperLimit);
185180
if (oldScreenProps.tapToSeek != newScreenProps.tapToSeek) {
186181
slider.tapToSeek = newScreenProps.tapToSeek;
187182
}
@@ -272,6 +267,21 @@ - (void)loadImageFromImageSource:(ImageSource)source completionBlock:(RNCLoadIma
272267
}
273268
}
274269

270+
void updateLimits(RNCSlider *slider, float newLowerLimit, float newUpperLimit) {
271+
if (slider.lowerLimit != newLowerLimit) {
272+
slider.lowerLimit = newLowerLimit;
273+
}
274+
275+
if (slider.upperLimit != newUpperLimit) {
276+
slider.upperLimit = newUpperLimit;
277+
}
278+
279+
if (slider.lowerLimit > slider.upperLimit) {
280+
NSLog(@"Invalid configuration: lowerLimit > upperLimit, reverting lowerLimit to upperLimit.");
281+
slider.lowerLimit = slider.upperLimit;
282+
}
283+
}
284+
275285
- (void)setInverted:(BOOL)inverted
276286
{
277287
if (inverted) {

package/ios/RNCSliderManager.m

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,26 @@ - (void)sliderTouchEnd:(RNCSlider *)sender
158158
RCT_EXPORT_VIEW_PROPERTY(maximumTrackImage, UIImage);
159159
RCT_EXPORT_VIEW_PROPERTY(minimumValue, float);
160160
RCT_EXPORT_VIEW_PROPERTY(maximumValue, float);
161-
RCT_EXPORT_VIEW_PROPERTY(lowerLimit, float);
162-
RCT_EXPORT_VIEW_PROPERTY(upperLimit, float);
161+
RCT_CUSTOM_VIEW_PROPERTY(lowerLimit, float, RNCSlider) {
162+
float lowerLimit = [RCTConvert float:json];
163+
164+
if (lowerLimit > view.upperLimit) {
165+
lowerLimit = view.upperLimit;
166+
NSLog(@"Invalid configuration: reverting upper limit to equal to lower limit")
167+
}
168+
169+
view.lowerLimit = lowerLimit;
170+
}
171+
RCT_CUSTOM_VIEW_PROPERTY(upperLimit, float, RNCSlider) {
172+
float upperLimit = [RCTConvert float:json];
173+
174+
if (upperLimit < view.lowerLimit) {
175+
upperLimit = view.lowerLimit;
176+
NSLog(@"Invalid configuration: reverting lower limit to equal to upper limit")
177+
}
178+
179+
view.upperLimit = upperLimit;
180+
}
163181
RCT_EXPORT_VIEW_PROPERTY(minimumTrackTintColor, UIColor);
164182
RCT_EXPORT_VIEW_PROPERTY(maximumTrackTintColor, UIColor);
165183
RCT_EXPORT_VIEW_PROPERTY(onRNCSliderValueChange, RCTBubblingEventBlock);

package/src/Slider.tsx

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, {useState} from 'react';
1+
import React, {useCallback, useEffect, useState} from 'react';
22
import {
33
Image,
44
Platform,
@@ -281,6 +281,18 @@ const SliderComponent = (
281281
default: constants.LIMIT_MAX_VALUE,
282282
});
283283

284+
const limitCheck = useCallback(() => {
285+
if (lowerLimit >= upperLimit) {
286+
console.warn(
287+
'Invalid configuration: lower limit is supposed to me smaller than upper limit',
288+
);
289+
}
290+
}, [lowerLimit, upperLimit]);
291+
292+
useEffect(() => {
293+
limitCheck();
294+
}, [limitCheck, localProps]);
295+
284296
return (
285297
<View
286298
onLayout={(event) => {

0 commit comments

Comments
 (0)