Skip to content

Commit f1c48ad

Browse files
fix: check for invalid configuration in limit settings (#638)
* fix: check for invalid configuration in limit settings * fix: add limit check with warning * chore: pr improvements * fix: pr improvements * Remove outdated comment * Correct the minor typo --------- Co-authored-by: Bartosz Klonowski <[email protected]>
1 parent 472bc4d commit f1c48ad

File tree

7 files changed

+90
-37
lines changed

7 files changed

+90
-37
lines changed

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

Lines changed: 27 additions & 4 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;
@@ -104,6 +105,15 @@ private void disableStateListAnimatorIfNeeded() {
104105
updateAll();
105106
}
106107

108+
/*package*/ int getValidProgressValue(int progress) {
109+
if (progress < getLowerLimit()) {
110+
progress = getLowerLimit();
111+
} else if (progress > getUpperLimit()) {
112+
progress = getUpperLimit();
113+
}
114+
return progress;
115+
}
116+
107117
/* package */ void setValue(double value) {
108118
mValue = value;
109119
updateValue();
@@ -222,16 +232,29 @@ private void updateAll() {
222232
updateValue();
223233
}
224234

225-
/** 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+
*/
226238
private void updateLowerLimit() {
227239
double limit = Math.max(mRealLowerLimit, mMinValue);
228-
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.d("Invalid configuration", "upperLimit < lowerLimit; lowerLimit not set");
243+
}else {
244+
mLowerLimit = Math.min(lowerLimit, mUpperLimit);
245+
}
229246
}
230247

231-
/** Update limit based on props limit, max and min */
248+
/** Update limit based on props limit, max and min
249+
*/
232250
private void updateUpperLimit() {
233251
double limit = Math.min(mRealUpperLimit, mMaxValue);
234-
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.d("Invalid configuration", "upperLimit < lowerLimit; upperLimit not set");
255+
} else {
256+
mUpperLimit = upperLimit;
257+
}
235258
}
236259

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

package/android/src/newarch/java/com/reactnativecommunity/slider/ReactSliderManager.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,13 +48,8 @@ protected ViewManagerDelegate<ReactSlider> getDelegate() {
4848
public void onProgressChanged(SeekBar seekbar, int progress, boolean fromUser) {
4949
ReactSlider slider = (ReactSlider)seekbar;
5050

51-
if(progress < slider.getLowerLimit()) {
52-
progress = slider.getLowerLimit();
53-
seekbar.setProgress(progress);
54-
} else if (progress > slider.getUpperLimit()) {
55-
progress = slider.getUpperLimit();
56-
seekbar.setProgress(progress);
57-
}
51+
progress = slider.getValidProgressValue(progress);
52+
seekbar.setProgress(progress);
5853

5954
ReactContext reactContext = (ReactContext) seekbar.getContext();
6055
int reactTag = seekbar.getId();

package/android/src/oldarch/java/com/reactnativecommunity/slider/ReactSliderManager.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,8 @@ public class ReactSliderManager extends SimpleViewManager<ReactSlider> {
3030
public void onProgressChanged(SeekBar seekbar, int progress, boolean fromUser) {
3131
ReactSlider slider = (ReactSlider)seekbar;
3232

33-
if(progress < slider.getLowerLimit()) {
34-
progress = slider.getLowerLimit();
35-
seekbar.setProgress(progress);
36-
} else if(progress > slider.getUpperLimit()) {
37-
progress = slider.getUpperLimit();
38-
seekbar.setProgress(progress);
39-
}
33+
progress = slider.getValidProgressValue(progress);
34+
seekbar.setProgress(progress);
4035

4136
ReactContext reactContext = (ReactContext) seekbar.getContext();
4237
if(fromUser) {

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: 23 additions & 15 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,11 +176,19 @@ - (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;
179+
if (slider.lowerLimit != newScreenProps.lowerLimit) {
180+
if(newScreenProps.lowerLimit > slider.upperLimit){
181+
NSLog(@"Invalid configuration: upperLimit < lowerLimit; lowerLimit not set");
182+
} else {
183+
slider.lowerLimit = newScreenProps.lowerLimit;
184+
}
181185
}
182-
if (oldScreenProps.upperLimit != newScreenProps.upperLimit) {
183-
slider.upperLimit = newScreenProps.upperLimit;
186+
if (slider.upperLimit != newScreenProps.upperLimit) {
187+
if(newScreenProps.upperLimit < slider.lowerLimit){
188+
NSLog(@"Invalid configuration: upperLimit < lowerLimit; upperLimit not set");
189+
} else {
190+
slider.upperLimit = newScreenProps.upperLimit;
191+
}
184192
}
185193
if (oldScreenProps.tapToSeek != newScreenProps.tapToSeek) {
186194
slider.tapToSeek = newScreenProps.tapToSeek;

package/ios/RNCSliderManager.m

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,24 @@ - (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+
NSLog(@"Invalid configuration: upperLimit < lowerLimit; lowerLimit not set");
166+
} else {
167+
view.lowerLimit = lowerLimit;
168+
}
169+
}
170+
RCT_CUSTOM_VIEW_PROPERTY(upperLimit, float, RNCSlider) {
171+
float upperLimit = [RCTConvert float:json];
172+
173+
if (upperLimit < view.lowerLimit) {
174+
NSLog(@"Invalid configuration: upperLimit < lowerLimit; upperLimit not set");
175+
} else {
176+
view.upperLimit = upperLimit;
177+
}
178+
}
163179
RCT_EXPORT_VIEW_PROPERTY(minimumTrackTintColor, UIColor);
164180
RCT_EXPORT_VIEW_PROPERTY(maximumTrackTintColor, UIColor);
165181
RCT_EXPORT_VIEW_PROPERTY(onRNCSliderValueChange, RCTBubblingEventBlock);

package/src/Slider.tsx

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

284+
useEffect(() => {
285+
if (lowerLimit >= upperLimit) {
286+
console.warn(
287+
'Invalid configuration: lower limit is supposed to be smaller than upper limit',
288+
);
289+
}
290+
}, [lowerLimit, upperLimit]);
291+
284292
return (
285293
<View
286294
onLayout={(event) => {

0 commit comments

Comments
 (0)