1 /*
2 * Copyright (c) 2024 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_indicator.h"
17
18 #include "bridge/declarative_frontend/engine/functions/js_event_function.h"
19 #include "bridge/declarative_frontend/engine/jsi/js_ui_index.h"
20 #include "core/components/swiper/swiper_indicator_theme.h"
21 #include "core/components_ng/base/view_stack_processor.h"
22 #include "core/components_ng/pattern/swiper_indicator/indicator_common/indicator_model.h"
23 #include "core/components_ng/pattern/swiper_indicator/indicator_common/indicator_model_ng.h"
24
25 namespace OHOS::Ace {
26 namespace {
27 constexpr int32_t DEFAULT_INDICATOR_COUNT = 2;
28 } // namespace
29 std::unique_ptr<IndicatorModel> IndicatorModel::instance_ = nullptr;
30 std::mutex IndicatorModel::mutex_;
31
GetInstance()32 IndicatorModel* IndicatorModel::GetInstance()
33 {
34 if (!instance_) {
35 std::lock_guard<std::mutex> lock(mutex_);
36 if (!instance_) {
37 instance_.reset(new NG::IndicatorModelNG());
38 }
39 }
40 return instance_.get();
41 }
42
43 } // namespace OHOS::Ace
44 namespace OHOS::Ace::Framework {
45 namespace {
SwiperChangeEventToJSValue(const SwiperChangeEvent & eventInfo)46 JSRef<JSVal> SwiperChangeEventToJSValue(const SwiperChangeEvent& eventInfo)
47 {
48 return JSRef<JSVal>::Make(ToJSValue(eventInfo.GetIndex()));
49 }
50
51 } // namespace
52
Create(const JSCallbackInfo & info)53 void JSIndicator::Create(const JSCallbackInfo& info)
54 {
55 auto indicatorController = IndicatorModel::GetInstance()->Create();
56 if (info[0]->IsObject()) {
57 auto* jsController = JSRef<JSObject>::Cast(info[0])->Unwrap<JSIndicatorController>();
58 if (jsController) {
59 jsController->SetInstanceId(Container::CurrentId());
60 auto indicatorNode = AceType::Claim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
61 jsController->SetController(indicatorController, indicatorNode);
62 }
63 }
64 }
65
JSBind(BindingTarget globalObj)66 void JSIndicator::JSBind(BindingTarget globalObj)
67 {
68 JSClass<JSIndicator>::Declare("IndicatorComponent");
69 MethodOptions opt = MethodOptions::NONE;
70 JSClass<JSIndicator>::StaticMethod("create", &JSIndicator::Create, opt);
71 JSClass<JSIndicator>::StaticMethod("count", &JSIndicator::SetCount, opt);
72 JSClass<JSIndicator>::StaticMethod("loop", &JSIndicator::SetLoop, opt);
73 JSClass<JSIndicator>::StaticMethod("vertical", &JSIndicator::SetVertical, opt);
74 JSClass<JSIndicator>::StaticMethod("style", &JSIndicator::SetStyle, opt);
75 JSClass<JSIndicator>::StaticMethod("initialIndex", &JSIndicator::SetInitialIndex, opt);
76 JSClass<JSIndicator>::StaticMethod("onChange", &JSIndicator::SetOnChange);
77 JSClass<JSIndicator>::InheritAndBind<JSViewAbstract>(globalObj);
78 }
79
SetCount(const JSCallbackInfo & info)80 void JSIndicator::SetCount(const JSCallbackInfo& info)
81 {
82 if (!info[0]->IsNumber()) {
83 IndicatorModel::GetInstance()->SetCount(DEFAULT_INDICATOR_COUNT);
84 return;
85 }
86
87 auto count = std::max(DEFAULT_INDICATOR_COUNT, info[0]->ToNumber<int32_t>());
88 IndicatorModel::GetInstance()->SetCount(count);
89 }
90
SetLoop(const JSCallbackInfo & info)91 void JSIndicator::SetLoop(const JSCallbackInfo& info)
92 {
93 if (!info[0]->IsBoolean()) {
94 IndicatorModel::GetInstance()->SetLoop(true);
95 return;
96 }
97
98 IndicatorModel::GetInstance()->SetLoop(info[0]->ToBoolean());
99 }
100
SetVertical(const JSCallbackInfo & info)101 void JSIndicator::SetVertical(const JSCallbackInfo& info)
102 {
103 if (!info[0]->IsBoolean()) {
104 IndicatorModel::GetInstance()->SetDirection(Axis::HORIZONTAL);
105 return;
106 }
107
108 IndicatorModel::GetInstance()->SetDirection(info[0]->ToBoolean() ? Axis::VERTICAL : Axis::HORIZONTAL);
109 }
110
GetFontContent(const JSRef<JSVal> & font,bool isSelected,SwiperDigitalParameters & digitalParameters)111 void JSIndicator::GetFontContent(const JSRef<JSVal>& font, bool isSelected, SwiperDigitalParameters& digitalParameters)
112 {
113 JSRef<JSVal> size;
114 JSRef<JSVal> weight;
115 if (font->IsObject()) {
116 JSRef<JSObject> obj = JSRef<JSObject>::Cast(font);
117 size = obj->GetProperty("size");
118 weight = obj->GetProperty("weight");
119 }
120
121 auto pipelineContext = PipelineBase::GetCurrentContext();
122 CHECK_NULL_VOID(pipelineContext);
123 auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
124 CHECK_NULL_VOID(swiperIndicatorTheme);
125 // set font size, unit FP
126 CalcDimension fontSize;
127 RefPtr<ResourceObject> resObj;
128 if (!size->IsUndefined() && !size->IsNull() && ParseJsDimensionFpNG(size, fontSize, resObj)) {
129 if (LessOrEqual(fontSize.Value(), 0.0) || LessOrEqual(size->ToNumber<double>(), 0.0) ||
130 fontSize.Unit() == DimensionUnit::PERCENT) {
131 fontSize = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontSize();
132 }
133 } else {
134 fontSize = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontSize();
135 }
136 if (SystemProperties::ConfigChangePerform()) {
137 if (isSelected) {
138 digitalParameters.resourceSelectedFontSizeValueObject = resObj;
139 } else {
140 digitalParameters.resourceFontSizeValueObject = resObj;
141 }
142 }
143 if (isSelected) {
144 digitalParameters.selectedFontSize = fontSize;
145 } else {
146 digitalParameters.fontSize = fontSize;
147 }
148
149 if (!weight->IsNull()) {
150 std::string weightValue;
151 if (weight->IsNumber()) {
152 weightValue = std::to_string(weight->ToNumber<int32_t>());
153 } else {
154 ParseJsString(weight, weightValue);
155 }
156 if (isSelected) {
157 digitalParameters.selectedFontWeight = ConvertStrToFontWeight(weightValue);
158 } else {
159 digitalParameters.fontWeight = ConvertStrToFontWeight(weightValue);
160 }
161 } else {
162 if (isSelected) {
163 digitalParameters.selectedFontWeight = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontWeight();
164 } else {
165 digitalParameters.fontWeight = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontWeight();
166 }
167 }
168 }
169
ParseIndicatorDimension(const JSRef<JSVal> & value)170 std::optional<Dimension> JSIndicator::ParseIndicatorDimension(const JSRef<JSVal>& value)
171 {
172 std::optional<Dimension> indicatorDimension;
173 if (value->IsUndefined()) {
174 return indicatorDimension;
175 }
176 CalcDimension dimPosition;
177 auto parseOk = ParseJsDimensionVpNG(value, dimPosition);
178 indicatorDimension = parseOk && dimPosition.ConvertToPx() >= 0.0f ? dimPosition : 0.0_vp;
179 return indicatorDimension;
180 }
181
GetDotIndicatorInfo(const JSRef<JSObject> & obj)182 SwiperParameters JSIndicator::GetDotIndicatorInfo(const JSRef<JSObject>& obj)
183 {
184 JSRef<JSVal> leftValue = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::LEFT_VALUE));
185 JSRef<JSVal> topValue = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::TOP_VALUE));
186 JSRef<JSVal> rightValue = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::RIGHT_VALUE));
187 JSRef<JSVal> bottomValue = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::BOTTOM_VALUE));
188 JSRef<JSVal> startValue = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::START_VALUE));
189 JSRef<JSVal> endValue = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::END_VALUE));
190 JSRef<JSVal> itemWidthValue = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::ITEM_WIDTH_VALUE));
191 JSRef<JSVal> itemHeightValue = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::ITEM_HEIGHT_VALUE));
192 JSRef<JSVal> selectedItemWidthValue = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::SELECTED_ITEM_WIDTH_VALUE));
193 JSRef<JSVal> selectedItemHeightValue =
194 obj->GetProperty(static_cast<int32_t>(ArkUIIndex::SELECTED_ITEM_HEIGHT_VALUE));
195 auto pipelineContext = PipelineBase::GetCurrentContext();
196 CHECK_NULL_RETURN(pipelineContext, SwiperParameters());
197 auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
198 CHECK_NULL_RETURN(swiperIndicatorTheme, SwiperParameters());
199 SwiperParameters swiperParameters;
200 swiperParameters.dimLeft = ParseIndicatorDimension(leftValue);
201 swiperParameters.dimTop = ParseIndicatorDimension(topValue);
202 swiperParameters.dimRight = ParseIndicatorDimension(rightValue);
203 swiperParameters.dimBottom = ParseIndicatorDimension(bottomValue);
204 CalcDimension dimStart;
205 CalcDimension dimEnd;
206 std::optional<Dimension> indicatorDimension;
207 swiperParameters.dimStart = ParseLengthMetricsToDimension(startValue, dimStart) ? dimStart : indicatorDimension;
208 swiperParameters.dimEnd = ParseLengthMetricsToDimension(endValue, dimEnd) ? dimEnd : indicatorDimension;
209
210 CalcDimension dimPosition;
211 RefPtr<ResourceObject> resItemWidthObj;
212 RefPtr<ResourceObject> resItemHeightObj;
213 RefPtr<ResourceObject> resSelectedItemWidthObj;
214 RefPtr<ResourceObject> resSelectedItemHeightObj;
215 bool parseItemWOk = ParseJsDimensionVpNG(itemWidthValue, dimPosition, resItemWidthObj) &&
216 (dimPosition.Unit() != DimensionUnit::PERCENT);
217 auto defaultSize = swiperIndicatorTheme->GetSize();
218 swiperParameters.itemWidth = parseItemWOk && dimPosition > 0.0_vp ? dimPosition : defaultSize;
219 bool parseItemHOk = ParseJsDimensionVpNG(itemHeightValue, dimPosition, resItemHeightObj) &&
220 (dimPosition.Unit() != DimensionUnit::PERCENT);
221 swiperParameters.itemHeight = parseItemHOk && dimPosition > 0.0_vp ? dimPosition : defaultSize;
222 bool parseSelectedItemWOk = ParseJsDimensionVpNG(selectedItemWidthValue, dimPosition, resSelectedItemWidthObj) &&
223 (dimPosition.Unit() != DimensionUnit::PERCENT);
224 swiperParameters.selectedItemWidth = parseSelectedItemWOk && dimPosition > 0.0_vp ? dimPosition : defaultSize;
225 bool parseSelectedItemHOk = ParseJsDimensionVpNG(selectedItemHeightValue, dimPosition, resSelectedItemHeightObj) &&
226 (dimPosition.Unit() != DimensionUnit::PERCENT);
227 swiperParameters.selectedItemHeight = parseSelectedItemHOk && dimPosition > 0.0_vp ? dimPosition : defaultSize;
228 if (SystemProperties::ConfigChangePerform()) {
229 swiperParameters.resourceItemWidthValueObject = resItemWidthObj;
230 swiperParameters.resourceItemHeightValueObject = resItemHeightObj;
231 swiperParameters.resourceSelectedItemWidthValueObject = resSelectedItemWidthObj;
232 swiperParameters.resourceSelectedItemHeightValueObject = resSelectedItemHeightObj;
233 }
234 IndicatorModel::GetInstance()->SetIsIndicatorCustomSize(
235 parseSelectedItemWOk || parseSelectedItemHOk || parseItemWOk || parseItemHOk);
236 SetDotIndicatorInfo(obj, swiperParameters, swiperIndicatorTheme);
237 return swiperParameters;
238 }
SetDotIndicatorInfo(const JSRef<JSObject> & obj,SwiperParameters & swiperParameters,const RefPtr<SwiperIndicatorTheme> & swiperIndicatorTheme)239 void JSIndicator::SetDotIndicatorInfo(const JSRef<JSObject>& obj, SwiperParameters& swiperParameters,
240 const RefPtr<SwiperIndicatorTheme>& swiperIndicatorTheme)
241 {
242 JSRef<JSVal> maskValue = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::MASK_VALUE));
243 JSRef<JSVal> colorValue = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::COLOR_VALUE));
244 JSRef<JSVal> selectedColorValue = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::SELECTED_COLOR_VALUE));
245 JSRef<JSVal> maxDisplayCountVal = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::MAX_DISPLAY_COUNT_VALUE));
246 JSRef<JSVal> spaceValue = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::SPACE_VALUE));
247 if (maskValue->IsBoolean()) {
248 auto mask = maskValue->ToBoolean();
249 swiperParameters.maskValue = mask;
250 }
251 Color colorVal;
252 RefPtr<ResourceObject> resColorObj;
253 RefPtr<ResourceObject> resSelectedColorObj;
254 auto parseOk = ParseJsColor(colorValue, colorVal, resColorObj);
255 swiperParameters.colorVal = parseOk ? (swiperParameters.parametersByUser.insert("colorVal"), colorVal)
256 : swiperIndicatorTheme->GetColor();
257 parseOk = ParseJsColor(selectedColorValue, colorVal, resSelectedColorObj);
258 swiperParameters.selectedColorVal = parseOk
259 ? (swiperParameters.parametersByUser.insert("selectedColorVal"), colorVal)
260 : swiperIndicatorTheme->GetSelectedColor();
261 if (SystemProperties::ConfigChangePerform()) {
262 swiperParameters.resourceColorValueObject = resColorObj;
263 swiperParameters.resourceSelectedColorValueObject = resSelectedColorObj;
264 }
265 auto defalutSpace = swiperIndicatorTheme->GetIndicatorDotItemSpace();
266 CalcDimension dimSpace;
267 auto parseSpaceOk = ParseLengthMetricsToDimension(spaceValue, dimSpace) &&
268 (dimSpace.Unit() != DimensionUnit::PERCENT);
269 swiperParameters.dimSpace = (parseSpaceOk && !(dimSpace < 0.0_vp)) ? dimSpace : defalutSpace;
270 if (maxDisplayCountVal->IsUndefined()) {
271 return;
272 }
273 uint32_t result = 0;
274 auto setMaxDisplayCountVal = ParseJsInteger(maxDisplayCountVal, result);
275 swiperParameters.maxDisplayCountVal = setMaxDisplayCountVal && result > 0 ? result : 0;
276 }
277
GetDigitIndicatorInfo(const JSRef<JSObject> & obj)278 SwiperDigitalParameters JSIndicator::GetDigitIndicatorInfo(const JSRef<JSObject>& obj)
279 {
280 JSRef<JSVal> dotLeftValue = obj->GetProperty("leftValue");
281 JSRef<JSVal> dotTopValue = obj->GetProperty("topValue");
282 JSRef<JSVal> dotRightValue = obj->GetProperty("rightValue");
283 JSRef<JSVal> dotBottomValue = obj->GetProperty("bottomValue");
284 JSRef<JSVal> fontColorValue = obj->GetProperty("fontColorValue");
285 JSRef<JSVal> selectedFontColorValue = obj->GetProperty("selectedFontColorValue");
286 JSRef<JSVal> digitFontValue = obj->GetProperty("digitFontValue");
287 JSRef<JSVal> selectedDigitFontValue = obj->GetProperty("selectedDigitFontValue");
288 auto pipelineContext = PipelineBase::GetCurrentContext();
289 CHECK_NULL_RETURN(pipelineContext, SwiperDigitalParameters());
290 auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
291 CHECK_NULL_RETURN(swiperIndicatorTheme, SwiperDigitalParameters());
292 SwiperDigitalParameters digitalParameters;
293 digitalParameters.dimLeft = ParseIndicatorDimension(dotLeftValue);
294 digitalParameters.dimTop = ParseIndicatorDimension(dotTopValue);
295 digitalParameters.dimRight = ParseIndicatorDimension(dotRightValue);
296 digitalParameters.dimBottom = ParseIndicatorDimension(dotBottomValue);
297 Color fontColor;
298 RefPtr<ResourceObject> resFontColorObj;
299 RefPtr<ResourceObject> resSelectedFontColorObj;
300 auto parseOk = JSViewAbstract::ParseJsColor(fontColorValue, fontColor, resFontColorObj);
301 digitalParameters.fontColor =
302 parseOk ? (digitalParameters.parametersByUser.insert("fontColor"), fontColor)
303 : swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetTextColor();
304 parseOk = JSViewAbstract::ParseJsColor(selectedFontColorValue, fontColor, resSelectedFontColorObj);
305 digitalParameters.selectedFontColor =
306 parseOk ? (digitalParameters.parametersByUser.insert("selectedFontColor"), fontColor)
307 : swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetTextColor();
308 if (SystemProperties::ConfigChangePerform()) {
309 digitalParameters.resourceFontColorValueObject = resFontColorObj;
310 digitalParameters.resourceSelectedFontColorValueObject = resSelectedFontColorObj;
311 }
312 if (!digitFontValue->IsNull() && digitFontValue->IsObject()) {
313 GetFontContent(digitFontValue, false, digitalParameters);
314 }
315 if (!selectedDigitFontValue->IsNull() && selectedDigitFontValue->IsObject()) {
316 GetFontContent(selectedDigitFontValue, true, digitalParameters);
317 }
318 return digitalParameters;
319 }
320
SetStyle(const JSCallbackInfo & info)321 void JSIndicator::SetStyle(const JSCallbackInfo& info)
322 {
323 if (info[0]->IsObject()) {
324 auto obj = JSRef<JSObject>::Cast(info[0]);
325
326 JSRef<JSVal> typeParam = obj->GetProperty("type");
327 if (typeParam->IsString()) {
328 auto type = typeParam->ToString();
329 if (type == "DigitIndicator") {
330 SwiperDigitalParameters digitalParameters = GetDigitIndicatorInfo(obj);
331 IndicatorModel::GetInstance()->SetDigitIndicatorStyle(digitalParameters);
332 IndicatorModel::GetInstance()->SetIndicatorType(SwiperIndicatorType::DIGIT);
333 } else {
334 SwiperParameters swiperParameters = GetDotIndicatorInfo(obj);
335 IndicatorModel::GetInstance()->SetDotIndicatorStyle(swiperParameters);
336 IndicatorModel::GetInstance()->SetIndicatorType(SwiperIndicatorType::DOT);
337 }
338 } else {
339 SwiperParameters swiperParameters = GetDotIndicatorInfo(obj);
340 IndicatorModel::GetInstance()->SetDotIndicatorStyle(swiperParameters);
341 IndicatorModel::GetInstance()->SetIndicatorType(SwiperIndicatorType::DOT);
342 }
343 } else {
344 SwiperParameters swiperParameters = GetDotIndicatorInfo(JSRef<JSObject>::New());
345 IndicatorModel::GetInstance()->SetDotIndicatorStyle(swiperParameters);
346 IndicatorModel::GetInstance()->SetIndicatorType(SwiperIndicatorType::DOT);
347 }
348 }
349
SetOnChange(const JSCallbackInfo & info)350 void JSIndicator::SetOnChange(const JSCallbackInfo& info)
351 {
352 if (!info[0]->IsFunction()) {
353 return;
354 }
355 auto changeHandler = AceType::MakeRefPtr<JsEventFunction<SwiperChangeEvent, 1>>(
356 JSRef<JSFunc>::Cast(info[0]), SwiperChangeEventToJSValue);
357 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
358 auto onChange = [executionContext = info.GetExecutionContext(), func = std::move(changeHandler), node = targetNode](
359 const BaseEventInfo* info) {
360 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
361 const auto* swiperInfo = TypeInfoHelper::DynamicCast<SwiperChangeEvent>(info);
362 if (!swiperInfo) {
363 return;
364 }
365 PipelineContext::SetCallBackNode(node);
366 func->Execute(*swiperInfo);
367 };
368
369 IndicatorModel::GetInstance()->SetOnChange(std::move(onChange));
370 }
371
SetInitialIndex(const JSCallbackInfo & info)372 void JSIndicator::SetInitialIndex(const JSCallbackInfo& info)
373 {
374 if (!info[0]->IsNumber()) {
375 IndicatorModel::GetInstance()->SetInitialIndex(0);
376 return;
377 }
378
379 auto index = std::max(0, info[0]->ToNumber<int32_t>());
380 IndicatorModel::GetInstance()->SetInitialIndex(index);
381 }
382
JSBind(BindingTarget globalObj)383 void JSIndicatorController::JSBind(BindingTarget globalObj)
384 {
385 JSClass<JSIndicatorController>::Declare("IndicatorComponentController");
386 JSClass<JSIndicatorController>::CustomMethod("showNext", &JSIndicatorController::ShowNext);
387 JSClass<JSIndicatorController>::CustomMethod("showPrevious", &JSIndicatorController::ShowPrevious);
388 JSClass<JSIndicatorController>::CustomMethod("changeIndex", &JSIndicatorController::ChangeIndex);
389
390 JSClass<JSIndicatorController>::Bind(
391 globalObj, JSIndicatorController::Constructor, JSIndicatorController::Destructor);
392 }
393
Constructor(const JSCallbackInfo & args)394 void JSIndicatorController::Constructor(const JSCallbackInfo& args)
395 {
396 auto scroller = Referenced::MakeRefPtr<JSIndicatorController>();
397 scroller->IncRefCount();
398 args.SetReturnValue(Referenced::RawPtr(scroller));
399 }
400
Destructor(JSIndicatorController * scroller)401 void JSIndicatorController::Destructor(JSIndicatorController* scroller)
402 {
403 if (scroller != nullptr) {
404 scroller->DecRefCount();
405 }
406 }
407
ChangeIndex(const JSCallbackInfo & args)408 void JSIndicatorController::ChangeIndex(const JSCallbackInfo& args)
409 {
410 auto controller = controller_.Upgrade();
411 CHECK_NULL_VOID(controller);
412 ContainerScope scope(instanceId_);
413 if (!args[0]->IsNumber()) {
414 return;
415 }
416 bool useAnimation = false;
417 if (args.Length() > 1 && args[1]->IsBoolean()) {
418 useAnimation = args[1]->ToBoolean();
419 }
420 auto index = args[0]->ToNumber<int32_t>();
421 controller->ChangeIndex(index, useAnimation);
422 }
423
424 } // namespace OHOS::Ace::Framework
425