• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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_swiper.h"
17 
18 #include <algorithm>
19 #include <iterator>
20 
21 #include "base/log/ace_scoring_log.h"
22 #include "bridge/common/utils/utils.h"
23 #include "bridge/declarative_frontend/engine/functions/js_click_function.h"
24 #include "bridge/declarative_frontend/jsview/models/swiper_model_impl.h"
25 #include "bridge/declarative_frontend/view_stack_processor.h"
26 #include "bridge/js_frontend/engine/jsi/js_value.h"
27 #include "core/components/common/layout/constants.h"
28 #include "core/components/common/properties/scroll_bar.h"
29 #include "core/components/swiper/swiper_component.h"
30 #include "core/components_ng/pattern/swiper/swiper_model_ng.h"
31 
32 namespace OHOS::Ace {
33 
34 std::unique_ptr<SwiperModel> SwiperModel::instance_ = nullptr;
35 
GetInstance()36 SwiperModel* SwiperModel::GetInstance()
37 {
38     if (!instance_) {
39 #ifdef NG_BUILD
40         instance_.reset(new NG::SwiperModelNG());
41 #else
42         if (Container::IsCurrentUseNewPipeline()) {
43             instance_.reset(new NG::SwiperModelNG());
44         } else {
45             instance_.reset(new Framework::SwiperModelImpl());
46         }
47 #endif
48     }
49     return instance_.get();
50 }
51 
52 } // namespace OHOS::Ace
53 namespace OHOS::Ace::Framework {
54 namespace {
55 
56 const std::vector<EdgeEffect> EDGE_EFFECT = { EdgeEffect::SPRING, EdgeEffect::FADE, EdgeEffect::NONE };
57 const std::vector<SwiperDisplayMode> DISPLAY_MODE = { SwiperDisplayMode::STRETCH, SwiperDisplayMode::AUTO_LINEAR };
58 
SwiperChangeEventToJSValue(const SwiperChangeEvent & eventInfo)59 JSRef<JSVal> SwiperChangeEventToJSValue(const SwiperChangeEvent& eventInfo)
60 {
61     return JSRef<JSVal>::Make(ToJSValue(eventInfo.GetIndex()));
62 }
63 
64 } // namespace
65 
Create(const JSCallbackInfo & info)66 void JSSwiper::Create(const JSCallbackInfo& info)
67 {
68     auto controller = SwiperModel::GetInstance()->Create();
69 
70     if (info.Length() > 0 && info[0]->IsObject()) {
71         auto* jsController = JSRef<JSObject>::Cast(info[0])->Unwrap<JSSwiperController>();
72         if (jsController) {
73             jsController->SetController(controller);
74         }
75     }
76 }
77 
JsRemoteMessage(const JSCallbackInfo & info)78 void JSSwiper::JsRemoteMessage(const JSCallbackInfo& info)
79 {
80     RemoteCallback remoteCallback;
81     JSInteractableView::JsRemoteMessage(info, remoteCallback);
82 
83     SwiperModel::GetInstance()->SetRemoteMessageEventId(std::move(remoteCallback));
84 }
85 
JSBind(BindingTarget globalObj)86 void JSSwiper::JSBind(BindingTarget globalObj)
87 {
88     JSClass<JSSwiper>::Declare("Swiper");
89     MethodOptions opt = MethodOptions::NONE;
90     JSClass<JSSwiper>::StaticMethod("create", &JSSwiper::Create, opt);
91     JSClass<JSSwiper>::StaticMethod("autoPlay", &JSSwiper::SetAutoPlay, opt);
92     JSClass<JSSwiper>::StaticMethod("duration", &JSSwiper::SetDuration, opt);
93     JSClass<JSSwiper>::StaticMethod("index", &JSSwiper::SetIndex, opt);
94     JSClass<JSSwiper>::StaticMethod("interval", &JSSwiper::SetInterval, opt);
95     JSClass<JSSwiper>::StaticMethod("loop", &JSSwiper::SetLoop, opt);
96     JSClass<JSSwiper>::StaticMethod("vertical", &JSSwiper::SetVertical, opt);
97     JSClass<JSSwiper>::StaticMethod("indicator", &JSSwiper::SetIndicator, opt);
98     JSClass<JSSwiper>::StaticMethod("displayMode", &JSSwiper::SetDisplayMode);
99     JSClass<JSSwiper>::StaticMethod("effectMode", &JSSwiper::SetEffectMode);
100     JSClass<JSSwiper>::StaticMethod("displayCount", &JSSwiper::SetDisplayCount);
101     JSClass<JSSwiper>::StaticMethod("itemSpace", &JSSwiper::SetItemSpace);
102     JSClass<JSSwiper>::StaticMethod("cachedCount", &JSSwiper::SetCachedCount);
103     JSClass<JSSwiper>::StaticMethod("curve", &JSSwiper::SetCurve);
104     JSClass<JSSwiper>::StaticMethod("onChange", &JSSwiper::SetOnChange);
105     JSClass<JSSwiper>::StaticMethod("onAnimationStart", &JSSwiper::SetOnAnimationStart);
106     JSClass<JSSwiper>::StaticMethod("onAnimationEnd", &JSSwiper::SetOnAnimationEnd);
107     JSClass<JSSwiper>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
108     JSClass<JSSwiper>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
109     JSClass<JSSwiper>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
110     JSClass<JSSwiper>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
111     JSClass<JSSwiper>::StaticMethod("remoteMessage", &JSSwiper::JsRemoteMessage);
112     JSClass<JSSwiper>::StaticMethod("onClick", &JSSwiper::SetOnClick);
113     JSClass<JSSwiper>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
114     JSClass<JSSwiper>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
115     JSClass<JSSwiper>::StaticMethod("indicatorStyle", &JSSwiper::SetIndicatorStyle);
116     JSClass<JSSwiper>::StaticMethod("enabled", &JSSwiper::SetEnabled);
117     JSClass<JSSwiper>::StaticMethod("disableSwipe", &JSSwiper::SetDisableSwipe);
118     JSClass<JSSwiper>::StaticMethod("height", &JSSwiper::SetHeight);
119     JSClass<JSSwiper>::StaticMethod("width", &JSSwiper::SetWidth);
120     JSClass<JSSwiper>::StaticMethod("size", &JSSwiper::SetSize);
121     JSClass<JSSwiper>::Inherit<JSContainerBase>();
122     JSClass<JSSwiper>::Inherit<JSViewAbstract>();
123     JSClass<JSSwiper>::Bind<>(globalObj);
124 }
125 
SetAutoPlay(bool autoPlay)126 void JSSwiper::SetAutoPlay(bool autoPlay)
127 {
128     SwiperModel::GetInstance()->SetAutoPlay(autoPlay);
129 }
130 
SetEnabled(const JSCallbackInfo & info)131 void JSSwiper::SetEnabled(const JSCallbackInfo& info)
132 {
133     JSViewAbstract::JsEnabled(info);
134     if (info.Length() < 1) {
135         LOGE("The info is wrong, it is supposed to have at least 1 arguments");
136         return;
137     }
138 
139     if (!info[0]->IsBoolean()) {
140         LOGE("info is not bool.");
141         return;
142     }
143 
144     SwiperModel::GetInstance()->SetEnabled(info[0]->IsBoolean());
145 }
146 
SetDisableSwipe(bool disableSwipe)147 void JSSwiper::SetDisableSwipe(bool disableSwipe)
148 {
149     SwiperModel::GetInstance()->SetDisableSwipe(disableSwipe);
150 }
151 
SetEffectMode(const JSCallbackInfo & info)152 void JSSwiper::SetEffectMode(const JSCallbackInfo& info)
153 {
154     if (info.Length() < 1) {
155         LOGE("The info is wrong, it is supposed to have atleast 1 arguments");
156         return;
157     }
158 
159     if (!info[0]->IsNumber()) {
160         LOGE("info is not a  number ");
161         return;
162     }
163 
164     auto edgeEffect = info[0]->ToNumber<int32_t>();
165     if (edgeEffect < 0 || edgeEffect >= static_cast<int32_t>(EDGE_EFFECT.size())) {
166         LOGE("Edge effect: %{public}d illegal value", edgeEffect);
167         return;
168     }
169 
170     SwiperModel::GetInstance()->SetEdgeEffect(EDGE_EFFECT[edgeEffect]);
171 }
172 
SetDisplayCount(const JSCallbackInfo & info)173 void JSSwiper::SetDisplayCount(const JSCallbackInfo& info)
174 {
175     if (info.Length() < 1) {
176         LOGE("The info is wrong, it is supposed to have atleast 1 arguments");
177         return;
178     }
179 
180     if (info[0]->IsString() && info[0]->ToString() == "auto") {
181         SwiperModel::GetInstance()->SetDisplayMode(SwiperDisplayMode::AUTO_LINEAR);
182     } else if (info[0]->IsNumber()) {
183         SwiperModel::GetInstance()->SetDisplayCount(info[0]->ToNumber<int32_t>());
184     }
185 }
186 
SetDuration(int32_t duration)187 void JSSwiper::SetDuration(int32_t duration)
188 {
189     if (duration < 0) {
190         LOGE("duration is not valid: %{public}d", duration);
191         return;
192     }
193 
194     SwiperModel::GetInstance()->SetDuration(duration);
195 }
196 
SetIndex(int32_t index)197 void JSSwiper::SetIndex(int32_t index)
198 {
199     if (index < 0) {
200         LOGE("index is not valid: %{public}d", index);
201         return;
202     }
203 
204     SwiperModel::GetInstance()->SetIndex(index);
205 }
206 
SetInterval(int32_t interval)207 void JSSwiper::SetInterval(int32_t interval)
208 {
209     if (interval < 0) {
210         LOGE("interval is not valid: %{public}d", interval);
211         return;
212     }
213 
214     SwiperModel::GetInstance()->SetAutoPlayInterval(interval);
215 }
216 
SetLoop(bool loop)217 void JSSwiper::SetLoop(bool loop)
218 {
219     SwiperModel::GetInstance()->SetLoop(loop);
220 }
221 
SetVertical(bool isVertical)222 void JSSwiper::SetVertical(bool isVertical)
223 {
224     SwiperModel::GetInstance()->SetDirection(isVertical ? Axis::VERTICAL : Axis::HORIZONTAL);
225 }
226 
SetIndicator(bool showIndicator)227 void JSSwiper::SetIndicator(bool showIndicator)
228 {
229     SwiperModel::GetInstance()->SetShowIndicator(showIndicator);
230 }
231 
SetIndicatorStyle(const JSCallbackInfo & info)232 void JSSwiper::SetIndicatorStyle(const JSCallbackInfo& info)
233 {
234     SwiperParameters swiperParameters;
235     if (info[0]->IsObject()) {
236         JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
237         JSRef<JSVal> leftValue = obj->GetProperty("left");
238         JSRef<JSVal> topValue = obj->GetProperty("top");
239         JSRef<JSVal> rightValue = obj->GetProperty("right");
240         JSRef<JSVal> bottomValue = obj->GetProperty("bottom");
241         JSRef<JSVal> sizeValue = obj->GetProperty("size");
242         JSRef<JSVal> maskValue = obj->GetProperty("mask");
243         JSRef<JSVal> colorValue = obj->GetProperty("color");
244         JSRef<JSVal> selectedColorValue = obj->GetProperty("selectedColor");
245 
246         Dimension dimLeft;
247         if (ParseJsDimensionPx(leftValue, dimLeft)) {
248             swiperParameters.dimLeft = dimLeft;
249         }
250         Dimension dimTop;
251         if (ParseJsDimensionPx(topValue, dimTop)) {
252             swiperParameters.dimTop = dimTop;
253         }
254         Dimension dimRight;
255         if (ParseJsDimensionPx(rightValue, dimRight)) {
256             swiperParameters.dimRight = dimRight;
257         }
258         Dimension dimBottom;
259         if (ParseJsDimensionPx(bottomValue, dimBottom)) {
260             swiperParameters.dimBottom = dimBottom;
261         }
262         Dimension dimSize;
263         if (ParseJsDimensionPx(sizeValue, dimSize)) {
264             swiperParameters.dimSize = dimSize;
265         }
266         if (maskValue->IsBoolean()) {
267             auto mask = maskValue->ToBoolean();
268             swiperParameters.maskValue = mask;
269         }
270         Color colorVal;
271         if (ParseJsColor(colorValue, colorVal)) {
272             swiperParameters.colorVal = colorVal;
273         }
274         Color selectedColorVal;
275         if (ParseJsColor(selectedColorValue, selectedColorVal)) {
276             swiperParameters.selectedColorVal = selectedColorVal;
277         }
278     }
279 
280     SwiperModel::GetInstance()->SetIndicatorStyle(swiperParameters);
281 
282     info.ReturnSelf();
283 }
284 
SetItemSpace(const JSCallbackInfo & info)285 void JSSwiper::SetItemSpace(const JSCallbackInfo& info)
286 {
287     if (info.Length() < 1) {
288         LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
289         return;
290     }
291 
292     Dimension value;
293     if (!ParseJsDimensionVp(info[0], value)) {
294         return;
295     }
296 
297     if (LessNotEqual(value.Value(), 0.0)) {
298         value.SetValue(0.0);
299     }
300 
301     SwiperModel::GetInstance()->SetItemSpace(value);
302 }
303 
SetDisplayMode(int32_t index)304 void JSSwiper::SetDisplayMode(int32_t index)
305 {
306     if (index < 0 || index >= static_cast<int32_t>(DISPLAY_MODE.size())) {
307         LOGE("display mode is not valid: %{public}d", index);
308         return;
309     }
310 
311     SwiperModel::GetInstance()->SetDisplayMode(DISPLAY_MODE[index]);
312 }
313 
SetCachedCount(int32_t cachedCount)314 void JSSwiper::SetCachedCount(int32_t cachedCount)
315 {
316     SwiperModel::GetInstance()->SetCachedCount(cachedCount);
317 }
318 
SetCurve(const std::string & curveStr)319 void JSSwiper::SetCurve(const std::string& curveStr)
320 {
321     RefPtr<Curve> curve = CreateCurve(curveStr);
322 
323     SwiperModel::GetInstance()->SetCurve(curve);
324 }
325 
SetOnChange(const JSCallbackInfo & info)326 void JSSwiper::SetOnChange(const JSCallbackInfo& info)
327 {
328     if (!info[0]->IsFunction()) {
329         return;
330     }
331 
332     auto changeHandler = AceType::MakeRefPtr<JsEventFunction<SwiperChangeEvent, 1>>(
333         JSRef<JSFunc>::Cast(info[0]), SwiperChangeEventToJSValue);
334     auto onChange = [executionContext = info.GetExecutionContext(), func = std::move(changeHandler)](
335                         const BaseEventInfo* info) {
336         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
337         const auto* swiperInfo = TypeInfoHelper::DynamicCast<SwiperChangeEvent>(info);
338         if (!swiperInfo) {
339             LOGE("HandleChangeEvent swiperInfo == nullptr");
340             return;
341         }
342         ACE_SCORING_EVENT("Swiper.OnChange");
343         func->Execute(*swiperInfo);
344     };
345 
346     SwiperModel::GetInstance()->SetOnChange(std::move(onChange));
347 }
348 
SetOnAnimationStart(const JSCallbackInfo & info)349 void JSSwiper::SetOnAnimationStart(const JSCallbackInfo& info)
350 {
351     if (!info[0]->IsFunction()) {
352         return;
353     }
354 
355     auto animationStartHandler = AceType::MakeRefPtr<JsEventFunction<SwiperChangeEvent, 1>>(
356         JSRef<JSFunc>::Cast(info[0]), SwiperChangeEventToJSValue);
357     auto onAnimationStart = [executionContext = info.GetExecutionContext(), func = std::move(animationStartHandler)](
358                         const BaseEventInfo* info) {
359         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
360         const auto* swiperInfo = TypeInfoHelper::DynamicCast<SwiperChangeEvent>(info);
361         if (!swiperInfo) {
362             LOGE("onAnimationStart swiperInfo is nullptr");
363             return;
364         }
365         ACE_SCORING_EVENT("Swiper.onAnimationStart");
366         func->Execute(*swiperInfo);
367     };
368 
369     SwiperModel::GetInstance()->SetOnAnimationStart(std::move(onAnimationStart));
370 }
371 
SetOnAnimationEnd(const JSCallbackInfo & info)372 void JSSwiper::SetOnAnimationEnd(const JSCallbackInfo& info)
373 {
374     if (!info[0]->IsFunction()) {
375         return;
376     }
377 
378     auto animationEndHandler = AceType::MakeRefPtr<JsEventFunction<SwiperChangeEvent, 1>>(
379         JSRef<JSFunc>::Cast(info[0]), SwiperChangeEventToJSValue);
380     auto onAnimationEnd = [executionContext = info.GetExecutionContext(), func = std::move(animationEndHandler)](
381                         const BaseEventInfo* info) {
382         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
383         const auto* swiperInfo = TypeInfoHelper::DynamicCast<SwiperChangeEvent>(info);
384         if (!swiperInfo) {
385             LOGE("onAnimationEnd swiperInfo is nullptr");
386             return;
387         }
388         ACE_SCORING_EVENT("Swiper.onAnimationEnd");
389         func->Execute(*swiperInfo);
390     };
391 
392     SwiperModel::GetInstance()->SetOnAnimationEnd(std::move(onAnimationEnd));
393 }
394 
SetOnClick(const JSCallbackInfo & info)395 void JSSwiper::SetOnClick(const JSCallbackInfo& info)
396 {
397     if (Container::IsCurrentUseNewPipeline()) {
398         JSInteractableView::JsOnClick(info);
399         return;
400     }
401 
402     if (!info[0]->IsFunction()) {
403         LOGW("JSSwiper::SetOnClick the info is not click function");
404         return;
405     }
406 
407     RefPtr<JsClickFunction> jsOnClickFunc = AceType::MakeRefPtr<JsClickFunction>(JSRef<JSFunc>::Cast(info[0]));
408     auto onClick = [execCtx = info.GetExecutionContext(), func = std::move(jsOnClickFunc)](
409                        const BaseEventInfo* info, const RefPtr<V2::InspectorFunctionImpl>& impl) {
410         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
411         const auto* clickInfo = TypeInfoHelper::DynamicCast<ClickInfo>(info);
412         auto newInfo = *clickInfo;
413         if (impl) {
414             impl->UpdateEventInfo(newInfo);
415         }
416         ACE_SCORING_EVENT("onClick");
417         func->Execute(newInfo);
418     };
419 
420     SwiperModel::GetInstance()->SetOnClick(onClick);
421 }
422 
SetWidth(const JSCallbackInfo & info)423 void JSSwiper::SetWidth(const JSCallbackInfo& info)
424 {
425     if (info.Length() < 1) {
426         LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
427         return;
428     }
429 
430     SetWidth(info[0]);
431 }
432 
SetWidth(const JSRef<JSVal> & jsValue)433 void JSSwiper::SetWidth(const JSRef<JSVal>& jsValue)
434 {
435     if (Container::IsCurrentUseNewPipeline()) {
436         JSViewAbstract::JsWidth(jsValue);
437         return;
438     }
439 
440     JSViewAbstract::JsWidth(jsValue);
441     SwiperModel::GetInstance()->SetMainSwiperSizeWidth();
442 }
443 
SetHeight(const JSRef<JSVal> & jsValue)444 void JSSwiper::SetHeight(const JSRef<JSVal>& jsValue)
445 {
446     if (Container::IsCurrentUseNewPipeline()) {
447         JSViewAbstract::JsHeight(jsValue);
448         return;
449     }
450 
451     JSViewAbstract::JsHeight(jsValue);
452     SwiperModel::GetInstance()->SetMainSwiperSizeHeight();
453 }
454 
SetHeight(const JSCallbackInfo & info)455 void JSSwiper::SetHeight(const JSCallbackInfo& info)
456 {
457     if (info.Length() < 1) {
458         LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
459         return;
460     }
461 
462     SetHeight(info[0]);
463 }
464 
SetSize(const JSCallbackInfo & info)465 void JSSwiper::SetSize(const JSCallbackInfo& info)
466 {
467     if (info.Length() < 1) {
468         LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
469         return;
470     }
471 
472     if (!info[0]->IsObject()) {
473         LOGE("arg is not Object or String.");
474         return;
475     }
476 
477     JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
478     SetWidth(sizeObj->GetProperty("width"));
479     SetHeight(sizeObj->GetProperty("height"));
480 }
481 
JSBind(BindingTarget globalObj)482 void JSSwiperController::JSBind(BindingTarget globalObj)
483 {
484     JSClass<JSSwiperController>::Declare("SwiperController");
485     JSClass<JSSwiperController>::CustomMethod("swipeTo", &JSSwiperController::SwipeTo);
486     JSClass<JSSwiperController>::CustomMethod("showNext", &JSSwiperController::ShowNext);
487     JSClass<JSSwiperController>::CustomMethod("showPrevious", &JSSwiperController::ShowPrevious);
488     JSClass<JSSwiperController>::CustomMethod("finishAnimation", &JSSwiperController::FinishAnimation);
489     JSClass<JSSwiperController>::Bind(globalObj, JSSwiperController::Constructor, JSSwiperController::Destructor);
490 }
491 
Constructor(const JSCallbackInfo & args)492 void JSSwiperController::Constructor(const JSCallbackInfo& args)
493 {
494     auto scroller = Referenced::MakeRefPtr<JSSwiperController>();
495     scroller->IncRefCount();
496     args.SetReturnValue(Referenced::RawPtr(scroller));
497 }
498 
Destructor(JSSwiperController * scroller)499 void JSSwiperController::Destructor(JSSwiperController* scroller)
500 {
501     if (scroller != nullptr) {
502         scroller->DecRefCount();
503     }
504 }
505 
FinishAnimation(const JSCallbackInfo & args)506 void JSSwiperController::FinishAnimation(const JSCallbackInfo& args)
507 {
508     if (!controller_) {
509         return;
510     }
511 
512     if (args.Length() > 0 && args[0]->IsFunction()) {
513         RefPtr<JsFunction> jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(args[0]));
514         auto onFinish = [execCtx = args.GetExecutionContext(), func = std::move(jsFunc)]() {
515             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
516             ACE_SCORING_EVENT("Swiper.finishAnimation");
517             func->Execute();
518         };
519 
520         controller_->SetFinishCallback(onFinish);
521         controller_->FinishAnimation();
522         return;
523     }
524 
525     controller_->FinishAnimation();
526 }
527 
528 } // namespace OHOS::Ace::Framework
529