• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "frameworks/bridge/declarative_frontend/jsview/js_slider.h"
17 
18 #include "bridge/declarative_frontend/jsview/js_linear_gradient.h"
19 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
20 #include "bridge/declarative_frontend/jsview/models/slider_model_impl.h"
21 #include "core/components/slider/render_slider.h"
22 #include "core/components/slider/slider_element.h"
23 #include "core/components_ng/pattern/slider/slider_model_ng.h"
24 #include "core/components_ng/pattern/slider/slider_custom_content_options.h"
25 #include "frameworks/bridge/common/utils/engine_helper.h"
26 #include "frameworks/bridge/declarative_frontend/engine/functions/js_function.h"
27 #include "frameworks/bridge/declarative_frontend/jsview/js_shape_abstract.h"
28 
29 namespace OHOS::Ace {
30 namespace {
31 constexpr int NUM_0 = 0;
32 constexpr int NUM_1 = 1;
33 constexpr int SLIDER_SHOW_TIPS_MAX_PARAMS = 2;
34 constexpr char STEPS_STRING[] = "stepsAccessibility";
35 constexpr char ENTRIES_STRING[] = "entries";
36 constexpr char NEXT_STRING[] = "next";
37 constexpr char VALUE_STRING[] = "value";
38 constexpr char TEXT_STRING[] = "text";
39 constexpr char DONE_STRING[] = "done";
40 } // namespace
41 
42 std::unique_ptr<SliderModel> SliderModel::instance_ = nullptr;
43 std::mutex SliderModel::mutex_;
44 
GetInstance()45 SliderModel* SliderModel::GetInstance()
46 {
47     if (!instance_) {
48         std::lock_guard<std::mutex> lock(mutex_);
49         if (!instance_) {
50 #ifdef NG_BUILD
51             instance_.reset(new NG::SliderModelNG());
52 #else
53             if (Container::IsCurrentUseNewPipeline()) {
54                 instance_.reset(new NG::SliderModelNG());
55             } else {
56                 instance_.reset(new Framework::SliderModelImpl());
57             }
58 #endif
59         }
60     }
61     return instance_.get();
62 }
63 
64 } // namespace OHOS::Ace
65 
66 namespace OHOS::Ace::Framework {
67 
JSBind(BindingTarget globalObj)68 void JSSlider::JSBind(BindingTarget globalObj)
69 {
70     JSClass<JSSlider>::Declare("Slider");
71     MethodOptions opt = MethodOptions::NONE;
72     JSClass<JSSlider>::StaticMethod("create", &JSSlider::Create, opt);
73     JSClass<JSSlider>::StaticMethod("blockColor", &JSSlider::SetBlockColor);
74     JSClass<JSSlider>::StaticMethod("trackColor", &JSSlider::SetTrackColor);
75     JSClass<JSSlider>::StaticMethod("trackThickness", &JSSlider::SetThickness);
76     JSClass<JSSlider>::StaticMethod("selectedColor", &JSSlider::SetSelectedColor);
77     JSClass<JSSlider>::StaticMethod("minLabel", &JSSlider::SetMinLabel);
78     JSClass<JSSlider>::StaticMethod("maxLabel", &JSSlider::SetMaxLabel);
79     JSClass<JSSlider>::StaticMethod("minResponsiveDistance", &JSSlider::SetMinResponsiveDistance);
80     JSClass<JSSlider>::StaticMethod("showSteps", &JSSlider::SetShowSteps);
81     JSClass<JSSlider>::StaticMethod("showTips", &JSSlider::SetShowTips);
82     JSClass<JSSlider>::StaticMethod("blockBorderColor", &JSSlider::SetBlockBorderColor);
83     JSClass<JSSlider>::StaticMethod("blockBorderWidth", &JSSlider::SetBlockBorderWidth);
84     JSClass<JSSlider>::StaticMethod("stepColor", &JSSlider::SetStepColor);
85     JSClass<JSSlider>::StaticMethod("trackBorderRadius", &JSSlider::SetTrackBorderRadius);
86     JSClass<JSSlider>::StaticMethod("selectedBorderRadius", &JSSlider::SetSelectedBorderRadius);
87     JSClass<JSSlider>::StaticMethod("blockSize", &JSSlider::SetBlockSize);
88     JSClass<JSSlider>::StaticMethod("blockStyle", &JSSlider::SetBlockStyle);
89     JSClass<JSSlider>::StaticMethod("stepSize", &JSSlider::SetStepSize);
90     JSClass<JSSlider>::StaticMethod("sliderInteractionMode", &JSSlider::SetSliderInteractionMode);
91     JSClass<JSSlider>::StaticMethod("slideRange", &JSSlider::SetValidSlideRange);
92     JSClass<JSSlider>::StaticMethod("digitalCrownSensitivity", &JSSlider::SetDigitalCrownSensitivity);
93     JSClass<JSSlider>::StaticMethod("onChange", &JSSlider::OnChange);
94     JSClass<JSSlider>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
95     JSClass<JSSlider>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
96     JSClass<JSSlider>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
97     JSClass<JSSlider>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
98     JSClass<JSSlider>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
99     JSClass<JSSlider>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
100     JSClass<JSSlider>::StaticMethod("enableHapticFeedback", &JSSlider::SetEnableHapticFeedback);
101     JSClass<JSSlider>::StaticMethod("prefix", &JSSlider::SetPrefix);
102     JSClass<JSSlider>::StaticMethod("suffix", &JSSlider::SetSuffix);
103     JSClass<JSSlider>::InheritAndBind<JSViewAbstract>(globalObj);
104 }
105 
GetStep(double step,double max,double min)106 double GetStep(double step, double max, double min)
107 {
108     if (LessOrEqual(step, 0.0) || step > max - min) {
109         step = 1;
110     }
111     return step;
112 }
113 
GetValue(double value,double max,double min)114 double GetValue(double value, double max, double min)
115 {
116     if (value < min) {
117         value = min;
118     }
119 
120     if (value > max) {
121         value = max;
122     }
123     return value;
124 }
125 
ParseSliderValueObject(const JSCallbackInfo & info,const JSRef<JSVal> & changeEventVal)126 void ParseSliderValueObject(const JSCallbackInfo& info, const JSRef<JSVal>& changeEventVal)
127 {
128     CHECK_NULL_VOID(changeEventVal->IsFunction());
129 
130     JsEventCallback<void(float)> onChangeEvent(info.GetExecutionContext(), JSRef<JSFunc>::Cast(changeEventVal));
131     SliderModel::GetInstance()->SetOnChangeEvent(std::move(onChangeEvent));
132 }
133 
Create(const JSCallbackInfo & info)134 void JSSlider::Create(const JSCallbackInfo& info)
135 {
136     static const double valueMin = -1000000.0f;
137     double value = valueMin; // value:Current progress value. The default value is min.
138     double min = 0;   // min:Set the minimum value. The default value is 0.
139     double max = 100; // max:Set the maximum value. The default value is 100.
140     double step = 1;  // step:Sets the sliding jump value of the slider. The default value is 1.
141     bool reverse = false;
142 
143     if (!info[0]->IsObject()) {
144         SliderModel::GetInstance()->Create(
145             static_cast<float>(value), static_cast<float>(step), static_cast<float>(min), static_cast<float>(max));
146         return;
147     }
148 
149     auto paramObject = JSRef<JSObject>::Cast(info[0]);
150     auto getValue = paramObject->GetProperty("value");
151     auto getMin = paramObject->GetProperty("min");
152     auto getMax = paramObject->GetProperty("max");
153     auto getStep = paramObject->GetProperty("step");
154     auto getStyle = paramObject->GetProperty("style");
155     auto direction = paramObject->GetProperty("direction");
156     auto isReverse = paramObject->GetProperty("reverse");
157     JSRef<JSVal> changeEventVal;
158 
159     if (!getValue->IsNull() && getValue->IsObject()) {
160         JSRef<JSObject> valueObj = JSRef<JSObject>::Cast(getValue);
161         changeEventVal = valueObj->GetProperty("changeEvent");
162         auto valueProperty = valueObj->GetProperty("value");
163         value = valueProperty->ToNumber<double>();
164     } else if (paramObject->HasProperty("$value")) {
165         changeEventVal = paramObject->GetProperty("$value");
166         value = getValue->ToNumber<double>();
167     } else if (!getValue->IsNull() && getValue->IsNumber()) {
168         value = getValue->ToNumber<double>();
169     }
170 
171     if (!getMin->IsNull() && getMin->IsNumber()) {
172         min = getMin->ToNumber<double>();
173     }
174 
175     if (!getMax->IsNull() && getMax->IsNumber()) {
176         max = getMax->ToNumber<double>();
177     }
178 
179     if (!getStep->IsNull() && getStep->IsNumber()) {
180         step = getStep->ToNumber<double>();
181     }
182 
183     if (!isReverse->IsNull() && isReverse->IsBoolean()) {
184         reverse = isReverse->ToBoolean();
185     }
186 
187     if (GreatOrEqual(min, max)) {
188         min = 0;
189         max = 100;
190     }
191 
192     step = GetStep(step, max, min);
193 
194     if (!Container::IsCurrentUseNewPipeline()) {
195         value = GetValue(value, max, min);
196     }
197 
198     auto sliderStyle = SliderStyle::OUTSET;
199     auto sliderMode = SliderModel::SliderMode::OUTSET;
200     if (!getStyle->IsNull() && getStyle->IsNumber()) {
201         sliderStyle = static_cast<SliderStyle>(getStyle->ToNumber<int32_t>());
202     }
203     if (sliderStyle == SliderStyle::INSET) {
204         sliderMode = SliderModel::SliderMode::INSET;
205     } else if (sliderStyle == SliderStyle::CAPSULE) {
206         sliderMode = SliderModel::SliderMode::CAPSULE;
207     } else if (sliderStyle == SliderStyle::NONE) {
208         sliderMode = SliderModel::SliderMode::NONE;
209     } else {
210         sliderMode = SliderModel::SliderMode::OUTSET;
211     }
212 
213     auto sliderDirection = Axis::HORIZONTAL;
214     if (!direction->IsNull() && direction->IsNumber()) {
215         sliderDirection = static_cast<Axis>(direction->ToNumber<int32_t>());
216     }
217     if (sliderDirection != Axis::VERTICAL) {
218         sliderDirection = Axis::HORIZONTAL;
219     }
220 
221     SliderModel::GetInstance()->Create(
222         static_cast<float>(value), static_cast<float>(step), static_cast<float>(min), static_cast<float>(max));
223     SliderModel::GetInstance()->SetSliderMode(sliderMode);
224     SliderModel::GetInstance()->SetDirection(sliderDirection);
225     SliderModel::GetInstance()->SetReverse(reverse);
226     if (!changeEventVal->IsUndefined() && changeEventVal->IsFunction()) {
227         ParseSliderValueObject(info, changeEventVal);
228     }
229 }
230 
SetThickness(const JSCallbackInfo & info)231 void JSSlider::SetThickness(const JSCallbackInfo& info)
232 {
233     if (info.Length() < 1) {
234         return;
235     }
236     CalcDimension value;
237     if (!ParseJsDimensionVp(info[0], value)) {
238         value = CalcDimension(0.0);
239     }
240     SliderModel::GetInstance()->SetThickness(value);
241 }
242 
SetBlockColor(const JSCallbackInfo & info)243 void JSSlider::SetBlockColor(const JSCallbackInfo& info)
244 {
245     if (info.Length() < 1) {
246         return;
247     }
248     Color colorVal;
249     RefPtr<ResourceObject> resObj;
250     if (!ParseJsColor(info[0], colorVal, resObj)) {
251         SliderModel::GetInstance()->ResetBlockColor();
252     } else {
253         SliderModel::GetInstance()->SetBlockColor(colorVal);
254     }
255     if (SystemProperties::ConfigChangePerform()) {
256         SliderModel::GetInstance()->CreateWithColorResourceObj(resObj, SliderColorType::BLOCK_COLOR);
257     }
258 }
259 
SetTrackColor(const JSCallbackInfo & info)260 void JSSlider::SetTrackColor(const JSCallbackInfo& info)
261 {
262     if (info.Length() < 1) {
263         return;
264     }
265     NG::Gradient gradient;
266     bool isResourceColor = false;
267     RefPtr<ResourceObject> resObj;
268     if (!ConvertGradientColor(info[0], gradient)) {
269         Color colorVal;
270         if (info[0]->IsNull() || info[0]->IsUndefined() || !ParseJsColor(info[0], colorVal, resObj)) {
271             SliderModel::GetInstance()->ResetTrackColor();
272             if (SystemProperties::ConfigChangePerform()) {
273                 SliderModel::GetInstance()->CreateWithColorResourceObj(resObj, SliderColorType::TRACK_COLOR);
274             }
275             return;
276         }
277         isResourceColor = true;
278         gradient = NG::SliderModelNG::CreateSolidGradient(colorVal);
279         // Set track color to Framework::SliderModelImpl. Need to backward compatibility with old pipeline.
280         SliderModel::GetInstance()->SetTrackBackgroundColor(colorVal);
281     }
282     // Set track gradient color to NG::SliderModelNG
283     SliderModel::GetInstance()->SetTrackBackgroundColor(gradient, isResourceColor);
284     if (SystemProperties::ConfigChangePerform()) {
285         SliderModel::GetInstance()->CreateWithColorResourceObj(resObj, SliderColorType::TRACK_COLOR);
286     }
287 }
288 
ConvertGradientColor(const JsiRef<JsiValue> & param,NG::Gradient & gradient)289 bool JSSlider::ConvertGradientColor(const JsiRef<JsiValue>& param, NG::Gradient& gradient)
290 {
291     if (param->IsNull() || param->IsUndefined() || !param->IsObject()) {
292         return false;
293     }
294 
295     JSLinearGradient* jsLinearGradient = JSRef<JSObject>::Cast(param)->Unwrap<JSLinearGradient>();
296     if (!jsLinearGradient || jsLinearGradient->GetGradient().empty()) {
297         return false;
298     }
299 
300     size_t size = jsLinearGradient->GetGradient().size();
301     if (size == 1) {
302         // If there is only one color, then this color is used for both the begin and end side.
303         NG::GradientColor gradientColor;
304         gradientColor.SetLinearColor(LinearColor(jsLinearGradient->GetGradient().front().first));
305         gradientColor.SetDimension(jsLinearGradient->GetGradient().front().second);
306         gradient.AddColor(gradientColor);
307         gradient.AddColor(gradientColor);
308         return true;
309     }
310 
311     for (size_t colorIndex = 0; colorIndex < size; colorIndex++) {
312         NG::GradientColor gradientColor;
313         gradientColor.SetLinearColor(LinearColor(jsLinearGradient->GetGradient().at(colorIndex).first));
314         gradientColor.SetDimension(jsLinearGradient->GetGradient().at(colorIndex).second);
315         gradient.AddColor(gradientColor);
316     }
317     return true;
318 }
319 
SetSelectedColor(const JSCallbackInfo & info)320 void JSSlider::SetSelectedColor(const JSCallbackInfo& info)
321 {
322     if (info.Length() < 1) {
323         return;
324     }
325     NG::Gradient gradient;
326     bool isResourceColor = false;
327     if (!ConvertGradientColor(info[0], gradient)) {
328         Color colorVal;
329         RefPtr<ResourceObject> resObj;
330         if (!ParseJsColor(info[0], colorVal, resObj)) {
331             SliderModel::GetInstance()->ResetSelectColor();
332             if (SystemProperties::ConfigChangePerform()) {
333                 SliderModel::GetInstance()->CreateWithColorResourceObj(resObj, SliderColorType::SELECT_COLOR);
334             }
335             return;
336         }
337         isResourceColor = true;
338         gradient = NG::SliderModelNG::CreateSolidGradient(colorVal);
339         SliderModel::GetInstance()->SetSelectColor(colorVal);
340         if (SystemProperties::ConfigChangePerform()) {
341             SliderModel::GetInstance()->CreateWithColorResourceObj(resObj, SliderColorType::SELECT_COLOR);
342         }
343     }
344     SliderModel::GetInstance()->SetSelectColor(gradient, isResourceColor);
345 }
346 
SetMinLabel(const JSCallbackInfo & info)347 void JSSlider::SetMinLabel(const JSCallbackInfo& info)
348 {
349     if (!info[0]->IsString() && !info[0]->IsNumber()) {
350         return;
351     }
352     SliderModel::GetInstance()->SetMinLabel(info[0]->ToNumber<float>());
353 }
354 
SetMaxLabel(const JSCallbackInfo & info)355 void JSSlider::SetMaxLabel(const JSCallbackInfo& info)
356 {
357     if (!info[0]->IsString() && !info[0]->IsNumber()) {
358         return;
359     }
360     SliderModel::GetInstance()->SetMaxLabel(info[0]->ToNumber<float>());
361 }
362 
SetValidSlideRange(const JSCallbackInfo & info)363 void JSSlider::SetValidSlideRange(const JSCallbackInfo& info)
364 {
365     if (!info[0]->IsObject()) {
366         SliderModel::GetInstance()->ResetValidSlideRange();
367         return;
368     }
369 
370     auto paramObject = JSRef<JSObject>::Cast(info[0]);
371     auto getValueRangeFrom = paramObject->GetProperty("from");
372     auto getValueRangeTo = paramObject->GetProperty("to");
373     float rangeFromValue = std::numeric_limits<float>::quiet_NaN();
374     float rangeToValue = std::numeric_limits<float>::quiet_NaN();
375     if (getValueRangeFrom->IsEmpty()) {
376         rangeFromValue = std::numeric_limits<float>::infinity();
377     } else if (getValueRangeFrom->IsNumber()) {
378         rangeFromValue = getValueRangeFrom->ToNumber<double>();
379     }
380     if (getValueRangeTo->IsEmpty()) {
381         rangeToValue = std::numeric_limits<float>::infinity();
382     } else if (getValueRangeTo->IsNumber()) {
383         rangeToValue = getValueRangeTo->ToNumber<double>();
384     }
385 
386     if (std::isnan(rangeFromValue) || std::isnan(rangeToValue) ||
387         (std::isinf(rangeFromValue) && std::isinf(rangeToValue))) {
388         SliderModel::GetInstance()->ResetValidSlideRange();
389         return;
390     }
391     SliderModel::GetInstance()->SetValidSlideRange(rangeFromValue, rangeToValue);
392 }
393 
SetMinResponsiveDistance(const JSCallbackInfo & info)394 void JSSlider::SetMinResponsiveDistance(const JSCallbackInfo& info)
395 {
396     if (info.Length() < 1) {
397         SliderModel::GetInstance()->ResetMinResponsiveDistance();
398         return;
399     }
400     float value = 0.0f;
401     if (info[0]->IsString() || info[0]->IsNumber()) {
402         value = info[0]->ToNumber<float>();
403         value = std::isfinite(value) ? value : 0.0f;
404         SliderModel::GetInstance()->SetMinResponsiveDistance(value);
405     } else {
406         SliderModel::GetInstance()->ResetMinResponsiveDistance();
407     }
408 }
409 
SetShowSteps(const JSCallbackInfo & info)410 void JSSlider::SetShowSteps(const JSCallbackInfo& info)
411 {
412     if (info.Length() < 1) {
413         return;
414     }
415     bool showSteps = false;
416     if (info[0]->IsBoolean()) {
417         showSteps = info[0]->ToBoolean();
418     }
419     std::optional<SliderModel::SliderShowStepOptions> options = std::nullopt;
420     if ((info.Length() >= SLIDER_SHOW_TIPS_MAX_PARAMS) && (info[1]->IsObject())) {
421         auto optionsObject = JSRef<JSObject>::Cast(info[1]);
422         SliderModel::SliderShowStepOptions optionsMap{};
423         JSRef<JSVal> jsOptionsMap = optionsObject->GetProperty(STEPS_STRING);
424         if (jsOptionsMap->IsObject()) {
425             JSSlider::ParseStepOptionsMap(jsOptionsMap, optionsMap);
426         }
427         if (optionsMap.size() > 0) {
428             options = optionsMap;
429         }
430     }
431     SliderModel::GetInstance()->SetShowSteps(showSteps, options);
432 }
433 
SetSliderInteractionMode(const JSCallbackInfo & info)434 void JSSlider::SetSliderInteractionMode(const JSCallbackInfo& info)
435 {
436     if (info.Length() < 1) {
437         SliderModel::GetInstance()->ResetSliderInteractionMode();
438         return;
439     }
440 
441     if (!info[0]->IsNull() && info[0]->IsNumber()) {
442         int32_t num = info[0]->ToNumber<int32_t>();
443         int32_t lowRange = static_cast<int32_t>(SliderModel::SliderInteraction::SLIDE_AND_CLICK);
444         int32_t upRange = static_cast<int32_t>(SliderModel::SliderInteraction::SLIDE_AND_CLICK_UP);
445         if (lowRange <= num && num <= upRange) {
446             auto mode = static_cast<SliderModel::SliderInteraction>(num);
447             SliderModel::GetInstance()->SetSliderInteractionMode(mode);
448         } else {
449             SliderModel::GetInstance()->ResetSliderInteractionMode();
450         }
451     } else {
452         SliderModel::GetInstance()->ResetSliderInteractionMode();
453     }
454 }
455 
SetShowTips(const JSCallbackInfo & info)456 void JSSlider::SetShowTips(const JSCallbackInfo& info)
457 {
458     if (info.Length() < 1) {
459         return;
460     }
461     bool showTips = false;
462     if (info[0]->IsBoolean()) {
463         showTips = info[0]->ToBoolean();
464     }
465 
466     std::optional<std::string> content;
467     RefPtr<ResourceObject> resObj;
468     if (info.Length() == SLIDER_SHOW_TIPS_MAX_PARAMS) {
469         std::string str;
470         if (ParseJsString(info[1], str, resObj)) {
471             content = str;
472         }
473     }
474     if (SystemProperties::ConfigChangePerform()) {
475         SliderModel::GetInstance()->CreateWithStringResourceObj(resObj, showTips);
476     }
477 
478     SliderModel::GetInstance()->SetShowTips(showTips, content);
479 }
480 
SetBlockBorderColor(const JSCallbackInfo & info)481 void JSSlider::SetBlockBorderColor(const JSCallbackInfo& info)
482 {
483     if (info.Length() < 1) {
484         return;
485     }
486 
487     Color colorVal;
488     RefPtr<ResourceObject> resObj;
489     if (!ParseJsColor(info[0], colorVal, resObj)) {
490         SliderModel::GetInstance()->ResetBlockBorderColor();
491     } else {
492         SliderModel::GetInstance()->SetBlockBorderColor(colorVal);
493     }
494     if (SystemProperties::ConfigChangePerform()) {
495         SliderModel::GetInstance()->CreateWithColorResourceObj(resObj, SliderColorType::BLOCK_BORDER_COLOR);
496     }
497 }
498 
SetBlockBorderWidth(const JSCallbackInfo & info)499 void JSSlider::SetBlockBorderWidth(const JSCallbackInfo& info)
500 {
501     if (info.Length() < 1) {
502         return;
503     }
504 
505     CalcDimension blockBorderWidth;
506     if (!ParseJsDimensionVp(info[0], blockBorderWidth)) {
507         SliderModel::GetInstance()->ResetBlockBorderWidth();
508         return;
509     }
510     if (LessNotEqual(blockBorderWidth.Value(), 0.0)) {
511         SliderModel::GetInstance()->ResetBlockBorderWidth();
512         return;
513     }
514     SliderModel::GetInstance()->SetBlockBorderWidth(blockBorderWidth);
515 }
516 
SetStepColor(const JSCallbackInfo & info)517 void JSSlider::SetStepColor(const JSCallbackInfo& info)
518 {
519     if (info.Length() < 1) {
520         return;
521     }
522 
523     Color colorVal;
524     RefPtr<ResourceObject> resObj;
525     if (!ParseJsColor(info[0], colorVal, resObj)) {
526         SliderModel::GetInstance()->ResetStepColor();
527     } else {
528         SliderModel::GetInstance()->SetStepColor(colorVal);
529     }
530     if (SystemProperties::ConfigChangePerform()) {
531         SliderModel::GetInstance()->CreateWithColorResourceObj(resObj, SliderColorType::STEP_COLOR);
532     }
533 }
534 
SetTrackBorderRadius(const JSCallbackInfo & info)535 void JSSlider::SetTrackBorderRadius(const JSCallbackInfo& info)
536 {
537     if (info.Length() < 1) {
538         return;
539     }
540 
541     CalcDimension trackBorderRadius;
542     if (!ParseJsDimensionVpNG(info[0], trackBorderRadius, true)) {
543         SliderModel::GetInstance()->ResetTrackBorderRadius();
544         return;
545     }
546     if (LessNotEqual(trackBorderRadius.Value(), 0.0)) {
547         SliderModel::GetInstance()->ResetTrackBorderRadius();
548         return;
549     }
550     SliderModel::GetInstance()->SetTrackBorderRadius(trackBorderRadius);
551 }
552 
SetSelectedBorderRadius(const JSCallbackInfo & info)553 void JSSlider::SetSelectedBorderRadius(const JSCallbackInfo& info)
554 {
555     if (info.Length() < 1) {
556         return;
557     }
558 
559     CalcDimension selectedBorderRadius;
560     if (!ParseJsDimensionVpNG(info[0], selectedBorderRadius, false)) {
561         SliderModel::GetInstance()->ResetSelectedBorderRadius();
562         return;
563     }
564     if (LessNotEqual(selectedBorderRadius.Value(), 0.0)) {
565         SliderModel::GetInstance()->ResetSelectedBorderRadius();
566         return;
567     }
568     SliderModel::GetInstance()->SetSelectedBorderRadius(selectedBorderRadius);
569 }
570 
SetBlockSize(const JSCallbackInfo & info)571 void JSSlider::SetBlockSize(const JSCallbackInfo& info)
572 {
573     if (info.Length() < 1) {
574         return;
575     }
576     if (!info[0]->IsObject()) {
577         SliderModel::GetInstance()->ResetBlockSize();
578         return;
579     }
580     JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
581 
582     CalcDimension width;
583     JSRef<JSVal> jsWidth = sizeObj->GetProperty("width");
584     if (!ParseJsDimensionVp(jsWidth, width)) {
585         width.SetValue(0.0);
586     }
587     if (LessNotEqual(width.Value(), 0.0)) {
588         width.SetValue(0.0);
589     }
590 
591     CalcDimension height;
592     JSRef<JSVal> jsHeight = sizeObj->GetProperty("height");
593     if (!ParseJsDimensionVp(jsHeight, height)) {
594         height.SetValue(0.0);
595     }
596     if (LessNotEqual(height.Value(), 0.0)) {
597         height.SetValue(0.0);
598     }
599 
600     SliderModel::GetInstance()->SetBlockSize(width, height);
601 }
602 
SetBlockStyle(const JSCallbackInfo & info)603 void JSSlider::SetBlockStyle(const JSCallbackInfo& info)
604 {
605     if (!info[0]->IsObject()) {
606         ResetBlockStyle();
607         return;
608     }
609     auto jsObj = JSRef<JSObject>::Cast(info[0]);
610     auto getType = jsObj->GetProperty("type");
611     if (getType->IsNull() || !getType->IsNumber()) {
612         ResetBlockStyle();
613         return;
614     }
615     auto type = static_cast<SliderModel::BlockStyleType>(getType->ToNumber<int32_t>());
616     if (type == SliderModel::BlockStyleType::IMAGE) {
617         std::string src;
618         RefPtr<ResourceObject> resObj;
619         auto image = jsObj->GetProperty("image");
620         std::string bundleName;
621         std::string moduleName;
622         if (!ParseJsMedia(image, src, resObj)) {
623             ResetBlockStyle();
624             return;
625         } else {
626             GetJsMediaBundleInfo(image, bundleName, moduleName);
627             SliderModel::GetInstance()->SetBlockImage(src, bundleName, moduleName);
628         }
629         if (SystemProperties::ConfigChangePerform()) {
630             SliderModel::GetInstance()->CreateWithMediaResourceObj(resObj, bundleName, moduleName);
631         }
632     } else if (type == SliderModel::BlockStyleType::SHAPE) {
633         auto shape = jsObj->GetProperty("shape");
634         if (!shape->IsObject()) {
635             ResetBlockStyle();
636             return;
637         }
638         JSShapeAbstract* shapeAbstract = JSRef<JSObject>::Cast(shape)->Unwrap<JSShapeAbstract>();
639         if (shapeAbstract == nullptr) {
640             ResetBlockStyle();
641             return;
642         }
643         SliderModel::GetInstance()->SetBlockShape(shapeAbstract->GetBasicShape());
644     }
645     SliderModel::GetInstance()->SetBlockType(type);
646 }
647 
SetStepSize(const JSCallbackInfo & info)648 void JSSlider::SetStepSize(const JSCallbackInfo& info)
649 {
650     if (info.Length() < 1) {
651         return;
652     }
653 
654     CalcDimension stepSize;
655     if (!ParseJsDimensionVp(info[0], stepSize)) {
656         SliderModel::GetInstance()->ResetStepSize();
657         return;
658     }
659     if (LessNotEqual(stepSize.Value(), 0.0)) {
660         auto theme = GetTheme<SliderTheme>();
661         CHECK_NULL_VOID(theme);
662         stepSize = theme->GetMarkerSize();
663     }
664     SliderModel::GetInstance()->SetStepSize(stepSize);
665 }
666 
SetDigitalCrownSensitivity(const JSCallbackInfo & info)667 void JSSlider::SetDigitalCrownSensitivity(const JSCallbackInfo& info)
668 {
669 #ifdef SUPPORT_DIGITAL_CROWN
670     if (info.Length() < 1 || info[0]->IsNull() || !info[0]->IsNumber()) {
671         SliderModel::GetInstance()->ResetDigitalCrownSensitivity();
672         return;
673     }
674 
675     auto sensitivity = info[0]->ToNumber<int32_t>();
676     if (sensitivity < 0 || sensitivity > static_cast<int32_t>(CrownSensitivity::HIGH)) {
677         SliderModel::GetInstance()->ResetDigitalCrownSensitivity();
678     } else {
679         SliderModel::GetInstance()->SetDigitalCrownSensitivity(static_cast<CrownSensitivity>(sensitivity));
680     }
681 #endif
682 }
683 
OnChange(const JSCallbackInfo & info)684 void JSSlider::OnChange(const JSCallbackInfo& info)
685 {
686     if (!info[0]->IsFunction()) {
687         return;
688     }
689     SliderModel::GetInstance()->SetOnChange(
690         JsEventCallback<void(float, int32_t)>(info.GetExecutionContext(), JSRef<JSFunc>::Cast(info[0])));
691     info.ReturnSelf();
692 }
693 
SetEnableHapticFeedback(const JSCallbackInfo & info)694 void JSSlider::SetEnableHapticFeedback(const JSCallbackInfo& info)
695 {
696     bool isEnableHapticFeedback = true;
697     if (info[0]->IsBoolean()) {
698         isEnableHapticFeedback = info[0]->ToBoolean();
699     }
700     SliderModel::GetInstance()->SetEnableHapticFeedback(isEnableHapticFeedback);
701 }
702 
SetPrefix_SuffixWithFrameNode(const JSRef<JSObject> & sliderJsObject)703 RefPtr<NG::UINode> SetPrefix_SuffixWithFrameNode(const JSRef<JSObject>& sliderJsObject)
704 {
705     JSRef<JSVal> builderNodeParam = sliderJsObject->GetProperty("builderNode_");
706     if (builderNodeParam->IsObject()) {
707         auto builderNodeObject = JSRef<JSObject>::Cast(builderNodeParam);
708         JSRef<JSVal> nodePtr = builderNodeObject->GetProperty("nodePtr_");
709         if (!nodePtr.IsEmpty()) {
710             const auto* vm = nodePtr->GetEcmaVM();
711             CHECK_NULL_RETURN(vm, nullptr);
712             auto* node = nodePtr->GetLocalHandle()->ToNativePointer(vm)->Value();
713             auto* myUINode = reinterpret_cast<NG::UINode*>(node);
714             if (!myUINode) {
715                 return nullptr;
716             }
717             auto refPtrUINode = AceType::Claim(myUINode);
718             return refPtrUINode;
719         }
720     }
721     return nullptr;
722 }
723 
SetPrefix(const JSCallbackInfo & args)724 void JSSlider::SetPrefix(const JSCallbackInfo& args)
725 {
726     if (!args[0]->IsObject()) {
727         return;
728     }
729 
730     RefPtr<NG::UINode> refPtrUINode = nullptr;
731     JSRef<JSObject> sliderContentObject;
732     if (args.Length() >= 1 && args[0]->IsObject()) {
733         sliderContentObject = JSRef<JSObject>::Cast(args[0]);
734         refPtrUINode = SetPrefix_SuffixWithFrameNode(sliderContentObject);
735     }
736 
737     NG::SliderPrefixOptions prefixOption;
738     if (args.Length() > 1 && args[1]->IsObject() && !args[1]->IsNull()) {
739         auto prefixOptions = JSRef<JSObject>::Cast(args[1]);
740         if (!prefixOptions->IsEmpty() && !prefixOptions->IsUndefined()) {
741             auto accessibilityTextProperty = prefixOptions->GetProperty("accessibilityText");
742             std::string accessibilityText;
743             if (!accessibilityTextProperty->IsNull() &&
744                 JSSlider::ParseJsString(accessibilityTextProperty, accessibilityText)) {
745                 prefixOption.accessibilityText = accessibilityText;
746             }
747             auto accessibilityDescriptionProperty = prefixOptions->GetProperty("accessibilityDescription");
748             std::string accessibilityDescription;
749             if (!accessibilityDescriptionProperty->IsNull() &&
750                 JSSlider::ParseJsString(accessibilityDescriptionProperty, accessibilityDescription)) {
751                 prefixOption.accessibilityDescription = accessibilityDescription;
752             }
753             auto accessibilityLevelProperty = prefixOptions->GetProperty("accessibilityLevel");
754             std::string accessibilityLevel;
755             if (!accessibilityLevelProperty->IsNull() &&
756                 JSSlider::ParseJsString(accessibilityLevelProperty, accessibilityLevel)) {
757                 prefixOption.accessibilityLevel = accessibilityLevel;
758             }
759             auto accessibilityGroupProperty = prefixOptions->GetProperty("accessibilityGroup");
760             if (!accessibilityGroupProperty->IsNull() && !accessibilityGroupProperty->IsEmpty()) {
761                 prefixOption.accessibilityGroup = accessibilityGroupProperty->ToBoolean();
762             }
763         }
764     }
765 
766     SliderModel::GetInstance()->SetPrefix(refPtrUINode, prefixOption);
767 
768     args.ReturnSelf();
769 }
770 
SetSuffix(const JSCallbackInfo & args)771 void JSSlider::SetSuffix(const JSCallbackInfo& args)
772 {
773     if (!args[0]->IsObject()) {
774         return;
775     }
776 
777     RefPtr<NG::UINode> refPtrUINode = nullptr;
778     JSRef<JSObject> sliderContentObject;
779     if (args.Length() >= 1 && args[0]->IsObject()) {
780         sliderContentObject = JSRef<JSObject>::Cast(args[0]);
781         refPtrUINode = SetPrefix_SuffixWithFrameNode(sliderContentObject);
782     }
783 
784     NG::SliderSuffixOptions suffixOption;
785     if (args.Length() > 1 && args[1]->IsObject() && !args[1]->IsNull()) {
786         JSRef<JSObject> suffixOptions = JSRef<JSObject>::Cast(args[1]);
787         if (!suffixOptions->IsEmpty() && !suffixOptions->IsUndefined()) {
788             auto accessibilityTextProperty = suffixOptions->GetProperty("accessibilityText");
789             std::string accessibilityText;
790             if (!accessibilityTextProperty->IsNull() &&
791                 JSSlider::ParseJsString(accessibilityTextProperty, accessibilityText)) {
792                 suffixOption.accessibilityText = accessibilityText;
793             }
794 
795             auto accessibilityDescriptionProperty = suffixOptions->GetProperty("accessibilityDescription");
796             std::string accessibilityDescription;
797             if (!accessibilityDescriptionProperty->IsNull() &&
798                 JSSlider::ParseJsString(accessibilityDescriptionProperty, accessibilityDescription)) {
799                 suffixOption.accessibilityDescription = accessibilityDescription;
800             }
801 
802             auto accessibilityLevelProperty = suffixOptions->GetProperty("accessibilityLevel");
803             std::string accessibilityLevel;
804             if (!accessibilityLevelProperty->IsNull() &&
805                 JSSlider::ParseJsString(accessibilityLevelProperty, accessibilityLevel)) {
806                 suffixOption.accessibilityLevel = accessibilityLevel;
807             }
808 
809             auto accessibilityGroupProperty = suffixOptions->GetProperty("accessibilityGroup");
810             if (!accessibilityGroupProperty->IsNull() && !accessibilityGroupProperty->IsEmpty()) {
811                 suffixOption.accessibilityGroup = accessibilityGroupProperty->ToBoolean();
812             }
813         }
814     }
815 
816     SliderModel::GetInstance()->SetSuffix(refPtrUINode, suffixOption);
817 
818     args.ReturnSelf();
819 }
820 
ResetBlockStyle()821 void JSSlider::ResetBlockStyle()
822 {
823     SliderModel::GetInstance()->ResetBlockType();
824     SliderModel::GetInstance()->ResetBlockImage();
825     SliderModel::GetInstance()->ResetBlockShape();
826 }
827 
GetIteratorNext(const napi_env env,napi_value iterator,napi_value func,bool * done)828 napi_value JSSlider::GetIteratorNext(const napi_env env, napi_value iterator, napi_value func, bool *done)
829 {
830     napi_value next = nullptr;
831     NAPI_CALL_BASE(env, napi_call_function(env, iterator, func, 0, nullptr, &next), nullptr);
832     CHECK_NULL_RETURN(next, nullptr);
833     napi_value doneValue = nullptr;
834     NAPI_CALL_BASE(env, napi_get_named_property(env, next, DONE_STRING, &doneValue), nullptr);
835     CHECK_NULL_RETURN(doneValue, nullptr);
836     NAPI_CALL_BASE(env, napi_get_value_bool(env, doneValue, done), nullptr);
837     return next;
838 }
839 
ParseStepOptionItemKey(const napi_env env,napi_value item)840 int32_t JSSlider::ParseStepOptionItemKey(const napi_env env, napi_value item)
841 {
842     int32_t result = INT32_MIN;
843     napi_value entry = nullptr;
844     napi_value key = nullptr;
845     napi_valuetype kType = napi_undefined;
846     NAPI_CALL_BASE(env, napi_get_named_property(env, item, VALUE_STRING, &entry), result);
847     CHECK_NULL_RETURN(entry, result);
848     NAPI_CALL_BASE(env, napi_get_element(env, entry, NUM_0, &key), result);
849     CHECK_NULL_RETURN(key, result);
850     NAPI_CALL_BASE(env, napi_typeof(env, key, &kType), result);
851     CHECK_NULL_RETURN(kType, result);
852     if (napi_number == kType) {
853         double step = NUM_0;
854         NAPI_CALL_BASE(env, napi_get_value_double(env, key, &step), result);
855         if ((step >= 0) && (NearZero(std::abs(step - std::floor(step)))) && (step <= INT32_MAX)) {
856             result = static_cast<int32_t>(step);
857         }
858     }
859     return result;
860 }
861 
ParseStepOptionItemValue(const napi_env env,napi_value item,std::string & stepText)862 bool JSSlider::ParseStepOptionItemValue(const napi_env env, napi_value item, std::string& stepText)
863 {
864     bool result = false;
865     napi_value entry = nullptr;
866     napi_value value = nullptr;
867     napi_value textObject = nullptr;
868     napi_valuetype vType = napi_undefined;
869     NAPI_CALL_BASE(env, napi_get_named_property(env, item, VALUE_STRING, &entry), result);
870     CHECK_NULL_RETURN(entry, result);
871     NAPI_CALL_BASE(env, napi_get_element(env, entry, NUM_1, &value), result);
872     CHECK_NULL_RETURN(value, result);
873     NAPI_CALL_BASE(env, napi_typeof(env, value, &vType), result);
874     CHECK_NULL_RETURN(vType, result);
875     if (napi_object == vType) {
876         NAPI_CALL_BASE(env, napi_get_named_property(env, value, TEXT_STRING, &textObject), result);
877         CHECK_NULL_RETURN(textObject, result);
878         panda::Local<panda::JSValueRef> localValue = NapiValueToLocalValue(textObject);
879         JSVal jsValue(localValue);
880         JSRef<JSVal> jsValueRef = JsiRef<JSVal>::Claim(std::move(jsValue));
881         result = ParseJsString(jsValueRef, stepText);
882     }
883     return result;
884 }
885 
ParseStepOptionsMap(JSRef<JSVal> jsStepOptionsMap,StepOptions & stepOptionsMap)886 napi_value JSSlider::ParseStepOptionsMap(JSRef<JSVal> jsStepOptionsMap, StepOptions& stepOptionsMap)
887 {
888     auto engine = EngineHelper::GetCurrentEngine();
889     CHECK_NULL_RETURN(engine, nullptr);
890     NativeEngine* nativeEngine = engine->GetNativeEngine();
891     CHECK_NULL_RETURN(nativeEngine, nullptr);
892     auto env = reinterpret_cast<napi_env>(nativeEngine);
893     panda::Local<JsiValue> localValue = jsStepOptionsMap.Get().GetLocalHandle();
894     JSValueWrapper valueWrapper = localValue;
895     napi_value nativeValue = nativeEngine->ValueToNapiValue(valueWrapper);
896     napi_value entriesFunc = nullptr;
897     napi_value iterator = nullptr;
898     napi_value nextFunc = nullptr;
899     bool done = false;
900     NAPI_CALL_BASE(env, napi_get_named_property(env, nativeValue, ENTRIES_STRING, &entriesFunc), nullptr);
901     CHECK_NULL_RETURN(entriesFunc, nullptr);
902     NAPI_CALL_BASE(env, napi_call_function(env, nativeValue, entriesFunc, NUM_0, nullptr, &iterator), nullptr);
903     CHECK_NULL_RETURN(iterator, nullptr);
904     NAPI_CALL_BASE(env, napi_get_named_property(env, iterator, NEXT_STRING, &nextFunc), nullptr);
905     CHECK_NULL_RETURN(nextFunc, nullptr);
906     napi_value next = JSSlider::GetIteratorNext(env, iterator, nextFunc, &done);
907     while ((nullptr != next) && !done) {
908         auto optionKey = JSSlider::ParseStepOptionItemKey(env, next);
909         std::string optionStr = "";
910         auto praseResult = JSSlider::ParseStepOptionItemValue(env, next, optionStr);
911         next = JSSlider::GetIteratorNext(env, iterator, nextFunc, &done);
912         if ((optionKey < 0) || (!praseResult)) {
913             continue;
914         }
915         stepOptionsMap[static_cast<uint32_t>(optionKey)] = optionStr;
916     }
917     return next;
918 }
919 } // namespace OHOS::Ace::Framework
920