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