/* * Copyright (c) 2021-2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "frameworks/bridge/declarative_frontend/jsview/js_swiper.h" #include #include #include "base/log/ace_scoring_log.h" #include "bridge/common/utils/utils.h" #include "bridge/declarative_frontend/engine/functions/js_click_function.h" #include "bridge/declarative_frontend/jsview/models/swiper_model_impl.h" #include "bridge/declarative_frontend/view_stack_processor.h" #include "bridge/js_frontend/engine/jsi/js_value.h" #include "core/components/common/layout/constants.h" #include "core/components/common/properties/scroll_bar.h" #include "core/components/swiper/swiper_component.h" #include "core/components_ng/pattern/swiper/swiper_model_ng.h" namespace OHOS::Ace { std::unique_ptr SwiperModel::instance_ = nullptr; SwiperModel* SwiperModel::GetInstance() { if (!instance_) { #ifdef NG_BUILD instance_.reset(new NG::SwiperModelNG()); #else if (Container::IsCurrentUseNewPipeline()) { instance_.reset(new NG::SwiperModelNG()); } else { instance_.reset(new Framework::SwiperModelImpl()); } #endif } return instance_.get(); } } // namespace OHOS::Ace namespace OHOS::Ace::Framework { namespace { const std::vector EDGE_EFFECT = { EdgeEffect::SPRING, EdgeEffect::FADE, EdgeEffect::NONE }; const std::vector DISPLAY_MODE = { SwiperDisplayMode::STRETCH, SwiperDisplayMode::AUTO_LINEAR }; JSRef SwiperChangeEventToJSValue(const SwiperChangeEvent& eventInfo) { return JSRef::Make(ToJSValue(eventInfo.GetIndex())); } } // namespace void JSSwiper::Create(const JSCallbackInfo& info) { auto controller = SwiperModel::GetInstance()->Create(); if (info.Length() > 0 && info[0]->IsObject()) { auto* jsController = JSRef::Cast(info[0])->Unwrap(); if (jsController) { jsController->SetController(controller); } } } void JSSwiper::JsRemoteMessage(const JSCallbackInfo& info) { RemoteCallback remoteCallback; JSInteractableView::JsRemoteMessage(info, remoteCallback); SwiperModel::GetInstance()->SetRemoteMessageEventId(std::move(remoteCallback)); } void JSSwiper::JSBind(BindingTarget globalObj) { JSClass::Declare("Swiper"); MethodOptions opt = MethodOptions::NONE; JSClass::StaticMethod("create", &JSSwiper::Create, opt); JSClass::StaticMethod("autoPlay", &JSSwiper::SetAutoPlay, opt); JSClass::StaticMethod("duration", &JSSwiper::SetDuration, opt); JSClass::StaticMethod("index", &JSSwiper::SetIndex, opt); JSClass::StaticMethod("interval", &JSSwiper::SetInterval, opt); JSClass::StaticMethod("loop", &JSSwiper::SetLoop, opt); JSClass::StaticMethod("vertical", &JSSwiper::SetVertical, opt); JSClass::StaticMethod("indicator", &JSSwiper::SetIndicator, opt); JSClass::StaticMethod("displayMode", &JSSwiper::SetDisplayMode); JSClass::StaticMethod("effectMode", &JSSwiper::SetEffectMode); JSClass::StaticMethod("displayCount", &JSSwiper::SetDisplayCount); JSClass::StaticMethod("itemSpace", &JSSwiper::SetItemSpace); JSClass::StaticMethod("cachedCount", &JSSwiper::SetCachedCount); JSClass::StaticMethod("curve", &JSSwiper::SetCurve); JSClass::StaticMethod("onChange", &JSSwiper::SetOnChange); JSClass::StaticMethod("onAnimationStart", &JSSwiper::SetOnAnimationStart); JSClass::StaticMethod("onAnimationEnd", &JSSwiper::SetOnAnimationEnd); JSClass::StaticMethod("onTouch", &JSInteractableView::JsOnTouch); JSClass::StaticMethod("onHover", &JSInteractableView::JsOnHover); JSClass::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey); JSClass::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete); JSClass::StaticMethod("remoteMessage", &JSSwiper::JsRemoteMessage); JSClass::StaticMethod("onClick", &JSSwiper::SetOnClick); JSClass::StaticMethod("onAppear", &JSInteractableView::JsOnAppear); JSClass::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear); JSClass::StaticMethod("indicatorStyle", &JSSwiper::SetIndicatorStyle); JSClass::StaticMethod("enabled", &JSSwiper::SetEnabled); JSClass::StaticMethod("disableSwipe", &JSSwiper::SetDisableSwipe); JSClass::StaticMethod("height", &JSSwiper::SetHeight); JSClass::StaticMethod("width", &JSSwiper::SetWidth); JSClass::StaticMethod("size", &JSSwiper::SetSize); JSClass::Inherit(); JSClass::Inherit(); JSClass::Bind<>(globalObj); } void JSSwiper::SetAutoPlay(bool autoPlay) { SwiperModel::GetInstance()->SetAutoPlay(autoPlay); } void JSSwiper::SetEnabled(const JSCallbackInfo& info) { JSViewAbstract::JsEnabled(info); if (info.Length() < 1) { LOGE("The info is wrong, it is supposed to have at least 1 arguments"); return; } if (!info[0]->IsBoolean()) { LOGE("info is not bool."); return; } SwiperModel::GetInstance()->SetEnabled(info[0]->IsBoolean()); } void JSSwiper::SetDisableSwipe(bool disableSwipe) { SwiperModel::GetInstance()->SetDisableSwipe(disableSwipe); } void JSSwiper::SetEffectMode(const JSCallbackInfo& info) { if (info.Length() < 1) { LOGE("The info is wrong, it is supposed to have atleast 1 arguments"); return; } if (!info[0]->IsNumber()) { LOGE("info is not a number "); return; } auto edgeEffect = info[0]->ToNumber(); if (edgeEffect < 0 || edgeEffect >= static_cast(EDGE_EFFECT.size())) { LOGE("Edge effect: %{public}d illegal value", edgeEffect); return; } SwiperModel::GetInstance()->SetEdgeEffect(EDGE_EFFECT[edgeEffect]); } void JSSwiper::SetDisplayCount(const JSCallbackInfo& info) { if (info.Length() < 1) { LOGE("The info is wrong, it is supposed to have atleast 1 arguments"); return; } if (info[0]->IsString() && info[0]->ToString() == "auto") { SwiperModel::GetInstance()->SetDisplayMode(SwiperDisplayMode::AUTO_LINEAR); } else if (info[0]->IsNumber()) { SwiperModel::GetInstance()->SetDisplayCount(info[0]->ToNumber()); } } void JSSwiper::SetDuration(int32_t duration) { if (duration < 0) { LOGE("duration is not valid: %{public}d", duration); return; } SwiperModel::GetInstance()->SetDuration(duration); } void JSSwiper::SetIndex(int32_t index) { if (index < 0) { LOGE("index is not valid: %{public}d", index); return; } SwiperModel::GetInstance()->SetIndex(index); } void JSSwiper::SetInterval(int32_t interval) { if (interval < 0) { LOGE("interval is not valid: %{public}d", interval); return; } SwiperModel::GetInstance()->SetAutoPlayInterval(interval); } void JSSwiper::SetLoop(bool loop) { SwiperModel::GetInstance()->SetLoop(loop); } void JSSwiper::SetVertical(bool isVertical) { SwiperModel::GetInstance()->SetDirection(isVertical ? Axis::VERTICAL : Axis::HORIZONTAL); } void JSSwiper::SetIndicator(bool showIndicator) { SwiperModel::GetInstance()->SetShowIndicator(showIndicator); } void JSSwiper::SetIndicatorStyle(const JSCallbackInfo& info) { SwiperParameters swiperParameters; if (info[0]->IsObject()) { JSRef obj = JSRef::Cast(info[0]); JSRef leftValue = obj->GetProperty("left"); JSRef topValue = obj->GetProperty("top"); JSRef rightValue = obj->GetProperty("right"); JSRef bottomValue = obj->GetProperty("bottom"); JSRef sizeValue = obj->GetProperty("size"); JSRef maskValue = obj->GetProperty("mask"); JSRef colorValue = obj->GetProperty("color"); JSRef selectedColorValue = obj->GetProperty("selectedColor"); Dimension dimLeft; if (ParseJsDimensionPx(leftValue, dimLeft)) { swiperParameters.dimLeft = dimLeft; } Dimension dimTop; if (ParseJsDimensionPx(topValue, dimTop)) { swiperParameters.dimTop = dimTop; } Dimension dimRight; if (ParseJsDimensionPx(rightValue, dimRight)) { swiperParameters.dimRight = dimRight; } Dimension dimBottom; if (ParseJsDimensionPx(bottomValue, dimBottom)) { swiperParameters.dimBottom = dimBottom; } Dimension dimSize; if (ParseJsDimensionPx(sizeValue, dimSize)) { swiperParameters.dimSize = dimSize; } if (maskValue->IsBoolean()) { auto mask = maskValue->ToBoolean(); swiperParameters.maskValue = mask; } Color colorVal; if (ParseJsColor(colorValue, colorVal)) { swiperParameters.colorVal = colorVal; } Color selectedColorVal; if (ParseJsColor(selectedColorValue, selectedColorVal)) { swiperParameters.selectedColorVal = selectedColorVal; } } SwiperModel::GetInstance()->SetIndicatorStyle(swiperParameters); info.ReturnSelf(); } void JSSwiper::SetItemSpace(const JSCallbackInfo& info) { if (info.Length() < 1) { LOGE("The arg is wrong, it is supposed to have atleast 1 arguments"); return; } Dimension value; if (!ParseJsDimensionVp(info[0], value)) { return; } if (LessNotEqual(value.Value(), 0.0)) { value.SetValue(0.0); } SwiperModel::GetInstance()->SetItemSpace(value); } void JSSwiper::SetDisplayMode(int32_t index) { if (index < 0 || index >= static_cast(DISPLAY_MODE.size())) { LOGE("display mode is not valid: %{public}d", index); return; } SwiperModel::GetInstance()->SetDisplayMode(DISPLAY_MODE[index]); } void JSSwiper::SetCachedCount(int32_t cachedCount) { SwiperModel::GetInstance()->SetCachedCount(cachedCount); } void JSSwiper::SetCurve(const std::string& curveStr) { RefPtr curve = CreateCurve(curveStr); SwiperModel::GetInstance()->SetCurve(curve); } void JSSwiper::SetOnChange(const JSCallbackInfo& info) { if (!info[0]->IsFunction()) { return; } auto changeHandler = AceType::MakeRefPtr>( JSRef::Cast(info[0]), SwiperChangeEventToJSValue); auto onChange = [executionContext = info.GetExecutionContext(), func = std::move(changeHandler)]( const BaseEventInfo* info) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext); const auto* swiperInfo = TypeInfoHelper::DynamicCast(info); if (!swiperInfo) { LOGE("HandleChangeEvent swiperInfo == nullptr"); return; } ACE_SCORING_EVENT("Swiper.OnChange"); func->Execute(*swiperInfo); }; SwiperModel::GetInstance()->SetOnChange(std::move(onChange)); } void JSSwiper::SetOnAnimationStart(const JSCallbackInfo& info) { if (!info[0]->IsFunction()) { return; } auto animationStartHandler = AceType::MakeRefPtr>( JSRef::Cast(info[0]), SwiperChangeEventToJSValue); auto onAnimationStart = [executionContext = info.GetExecutionContext(), func = std::move(animationStartHandler)]( const BaseEventInfo* info) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext); const auto* swiperInfo = TypeInfoHelper::DynamicCast(info); if (!swiperInfo) { LOGE("onAnimationStart swiperInfo is nullptr"); return; } ACE_SCORING_EVENT("Swiper.onAnimationStart"); func->Execute(*swiperInfo); }; SwiperModel::GetInstance()->SetOnAnimationStart(std::move(onAnimationStart)); } void JSSwiper::SetOnAnimationEnd(const JSCallbackInfo& info) { if (!info[0]->IsFunction()) { return; } auto animationEndHandler = AceType::MakeRefPtr>( JSRef::Cast(info[0]), SwiperChangeEventToJSValue); auto onAnimationEnd = [executionContext = info.GetExecutionContext(), func = std::move(animationEndHandler)]( const BaseEventInfo* info) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext); const auto* swiperInfo = TypeInfoHelper::DynamicCast(info); if (!swiperInfo) { LOGE("onAnimationEnd swiperInfo is nullptr"); return; } ACE_SCORING_EVENT("Swiper.onAnimationEnd"); func->Execute(*swiperInfo); }; SwiperModel::GetInstance()->SetOnAnimationEnd(std::move(onAnimationEnd)); } void JSSwiper::SetOnClick(const JSCallbackInfo& info) { if (Container::IsCurrentUseNewPipeline()) { JSInteractableView::JsOnClick(info); return; } if (!info[0]->IsFunction()) { LOGW("JSSwiper::SetOnClick the info is not click function"); return; } RefPtr jsOnClickFunc = AceType::MakeRefPtr(JSRef::Cast(info[0])); auto onClick = [execCtx = info.GetExecutionContext(), func = std::move(jsOnClickFunc)]( const BaseEventInfo* info, const RefPtr& impl) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); const auto* clickInfo = TypeInfoHelper::DynamicCast(info); auto newInfo = *clickInfo; if (impl) { impl->UpdateEventInfo(newInfo); } ACE_SCORING_EVENT("onClick"); func->Execute(newInfo); }; SwiperModel::GetInstance()->SetOnClick(onClick); } void JSSwiper::SetWidth(const JSCallbackInfo& info) { if (info.Length() < 1) { LOGE("The arg is wrong, it is supposed to have atleast 1 arguments"); return; } SetWidth(info[0]); } void JSSwiper::SetWidth(const JSRef& jsValue) { if (Container::IsCurrentUseNewPipeline()) { JSViewAbstract::JsWidth(jsValue); return; } JSViewAbstract::JsWidth(jsValue); SwiperModel::GetInstance()->SetMainSwiperSizeWidth(); } void JSSwiper::SetHeight(const JSRef& jsValue) { if (Container::IsCurrentUseNewPipeline()) { JSViewAbstract::JsHeight(jsValue); return; } JSViewAbstract::JsHeight(jsValue); SwiperModel::GetInstance()->SetMainSwiperSizeHeight(); } void JSSwiper::SetHeight(const JSCallbackInfo& info) { if (info.Length() < 1) { LOGE("The arg is wrong, it is supposed to have atleast 1 arguments"); return; } SetHeight(info[0]); } void JSSwiper::SetSize(const JSCallbackInfo& info) { if (info.Length() < 1) { LOGE("The arg is wrong, it is supposed to have atleast 1 arguments"); return; } if (!info[0]->IsObject()) { LOGE("arg is not Object or String."); return; } JSRef sizeObj = JSRef::Cast(info[0]); SetWidth(sizeObj->GetProperty("width")); SetHeight(sizeObj->GetProperty("height")); } void JSSwiperController::JSBind(BindingTarget globalObj) { JSClass::Declare("SwiperController"); JSClass::CustomMethod("swipeTo", &JSSwiperController::SwipeTo); JSClass::CustomMethod("showNext", &JSSwiperController::ShowNext); JSClass::CustomMethod("showPrevious", &JSSwiperController::ShowPrevious); JSClass::CustomMethod("finishAnimation", &JSSwiperController::FinishAnimation); JSClass::Bind(globalObj, JSSwiperController::Constructor, JSSwiperController::Destructor); } void JSSwiperController::Constructor(const JSCallbackInfo& args) { auto scroller = Referenced::MakeRefPtr(); scroller->IncRefCount(); args.SetReturnValue(Referenced::RawPtr(scroller)); } void JSSwiperController::Destructor(JSSwiperController* scroller) { if (scroller != nullptr) { scroller->DecRefCount(); } } void JSSwiperController::FinishAnimation(const JSCallbackInfo& args) { if (!controller_) { return; } if (args.Length() > 0 && args[0]->IsFunction()) { RefPtr jsFunc = AceType::MakeRefPtr(JSRef(), JSRef::Cast(args[0])); auto onFinish = [execCtx = args.GetExecutionContext(), func = std::move(jsFunc)]() { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); ACE_SCORING_EVENT("Swiper.finishAnimation"); func->Execute(); }; controller_->SetFinishCallback(onFinish); controller_->FinishAnimation(); return; } controller_->FinishAnimation(); } } // namespace OHOS::Ace::Framework