/* * Copyright (c) 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_navdestination.h" #include "base/log/ace_scoring_log.h" #include "base/memory/ace_type.h" #include "base/utils/utils.h" #include "base/system_bar/system_bar_style.h" #include "bridge/declarative_frontend/engine/functions/js_function.h" #include "bridge/declarative_frontend/engine/js_converter.h" #include "bridge/declarative_frontend/engine/js_execution_scope_defines.h" #include "bridge/declarative_frontend/engine/js_ref_ptr.h" #include "bridge/declarative_frontend/engine/js_types.h" #include "bridge/declarative_frontend/jsview/js_navdestination_context.h" #include "bridge/declarative_frontend/jsview/js_navigation.h" #include "bridge/declarative_frontend/jsview/js_navigation_utils.h" #include "bridge/declarative_frontend/jsview/js_navdestination_scrollable_processor.h" #include "bridge/declarative_frontend/jsview/js_utils.h" #include "core/components_ng/base/view_stack_model.h" #include "core/components_ng/base/view_stack_processor.h" #include "core/components_ng/manager/navigation/navigation_manager.h" #include "core/components_ng/pattern/navigation/navigation_options.h" #include "core/components_ng/pattern/navrouter/navdestination_model_ng.h" namespace OHOS::Ace { std::unique_ptr NavDestinationModel::instance_ = nullptr; std::mutex NavDestinationModel::mutex_; NavDestinationModel* NavDestinationModel::GetInstance() { if (!instance_) { std::lock_guard lock(mutex_); instance_.reset(new NG::NavDestinationModelNG()); } return instance_.get(); } } // namespace OHOS::Ace namespace OHOS::Ace::Framework { namespace { constexpr int32_t PARAMATER_LENGTH_ONE = 1; constexpr int32_t PARAMATER_LENGTH_TWO = 2; constexpr int32_t JS_ENUM_TRANSITIONTYPE_NONE = 1; constexpr int32_t JS_ENUM_TRANSITIONTYPE_TITLE = 2; constexpr int32_t JS_ENUM_TRANSITIONTYPE_CONTENT = 3; constexpr int32_t JS_ENUM_TRANSITIONTYPE_FADE = 4; constexpr int32_t JS_ENUM_TRANSITIONTYPE_EXPLODE = 5; constexpr int32_t JS_ENUM_TRANSITIONTYPE_SLIDE_RIGHT = 6; constexpr int32_t JS_ENUM_TRANSITIONTYPE_SLIDE_BOTTOM = 7; constexpr int32_t LAYOUT_SAFE_AREA_TYPE_LIMIT = 2; constexpr int32_t LAYOUT_SAFE_AREA_EDGE_LIMIT = 6; constexpr char MORE_BUTTON_OPTIONS_PROPERTY[] = "moreButtonOptions"; // sources in js_window_utils.h enum class ApiOrientation : uint32_t { BEGIN = 0, UNSPECIFIED = BEGIN, PORTRAIT = 1, LANDSCAPE = 2, PORTRAIT_INVERTED = 3, LANDSCAPE_INVERTED = 4, AUTO_ROTATION = 5, AUTO_ROTATION_PORTRAIT = 6, AUTO_ROTATION_LANDSCAPE = 7, AUTO_ROTATION_RESTRICTED = 8, AUTO_ROTATION_PORTRAIT_RESTRICTED = 9, AUTO_ROTATION_LANDSCAPE_RESTRICTED = 10, LOCKED = 11, AUTO_ROTATION_UNSPECIFIED = 12, USER_ROTATION_PORTRAIT = 13, USER_ROTATION_LANDSCAPE = 14, USER_ROTATION_PORTRAIT_INVERTED = 15, USER_ROTATION_LANDSCAPE_INVERTED = 16, FOLLOW_DESKTOP = 17, END = FOLLOW_DESKTOP, }; const std::map JS_TO_NATIVE_ORIENTATION_MAP { {ApiOrientation::UNSPECIFIED, Orientation::UNSPECIFIED }, {ApiOrientation::PORTRAIT, Orientation::VERTICAL }, {ApiOrientation::LANDSCAPE, Orientation::HORIZONTAL }, {ApiOrientation::PORTRAIT_INVERTED, Orientation::REVERSE_VERTICAL }, {ApiOrientation::LANDSCAPE_INVERTED, Orientation::REVERSE_HORIZONTAL }, {ApiOrientation::AUTO_ROTATION, Orientation::SENSOR }, {ApiOrientation::AUTO_ROTATION_PORTRAIT, Orientation::SENSOR_VERTICAL }, {ApiOrientation::AUTO_ROTATION_LANDSCAPE, Orientation::SENSOR_HORIZONTAL }, {ApiOrientation::AUTO_ROTATION_RESTRICTED, Orientation::AUTO_ROTATION_RESTRICTED }, {ApiOrientation::AUTO_ROTATION_PORTRAIT_RESTRICTED, Orientation::AUTO_ROTATION_PORTRAIT_RESTRICTED }, {ApiOrientation::AUTO_ROTATION_LANDSCAPE_RESTRICTED, Orientation::AUTO_ROTATION_LANDSCAPE_RESTRICTED }, {ApiOrientation::LOCKED, Orientation::LOCKED }, {ApiOrientation::AUTO_ROTATION_UNSPECIFIED, Orientation::AUTO_ROTATION_UNSPECIFIED }, {ApiOrientation::USER_ROTATION_PORTRAIT, Orientation::USER_ROTATION_PORTRAIT }, {ApiOrientation::USER_ROTATION_LANDSCAPE, Orientation::USER_ROTATION_LANDSCAPE }, {ApiOrientation::USER_ROTATION_PORTRAIT_INVERTED, Orientation::USER_ROTATION_PORTRAIT_INVERTED }, {ApiOrientation::USER_ROTATION_LANDSCAPE_INVERTED, Orientation::USER_ROTATION_LANDSCAPE_INVERTED }, {ApiOrientation::FOLLOW_DESKTOP, Orientation::FOLLOW_DESKTOP }, }; NG::NavigationSystemTransitionType ParseTransitionType(int32_t value) { switch (value) { case JS_ENUM_TRANSITIONTYPE_NONE: return NG::NavigationSystemTransitionType::NONE; case JS_ENUM_TRANSITIONTYPE_TITLE: return NG::NavigationSystemTransitionType::TITLE; case JS_ENUM_TRANSITIONTYPE_CONTENT: return NG::NavigationSystemTransitionType::CONTENT; case JS_ENUM_TRANSITIONTYPE_FADE: return NG::NavigationSystemTransitionType::FADE; case JS_ENUM_TRANSITIONTYPE_EXPLODE: return NG::NavigationSystemTransitionType::EXPLODE; case JS_ENUM_TRANSITIONTYPE_SLIDE_RIGHT: return NG::NavigationSystemTransitionType::SLIDE_RIGHT; case JS_ENUM_TRANSITIONTYPE_SLIDE_BOTTOM: return NG::NavigationSystemTransitionType::SLIDE_BOTTOM; default: return NG::NavigationSystemTransitionType::DEFAULT; } } bool ParseCommonTitle(const JSRef& jsObj) { JSRef subtitle = jsObj->GetProperty("sub"); JSRef title = jsObj->GetProperty("main"); std::string mainTitle; std::string subTitle; RefPtr subResObj; RefPtr mainResObj; bool hasSub = JSViewAbstract::ParseJsString(subtitle, subTitle, subResObj); bool hasMain = JSViewAbstract::ParseJsString(title, mainTitle, mainResObj); if (hasSub || hasMain) { if (SystemProperties::ConfigChangePerform() && (mainResObj || subResObj)) { return NG::NavDestinationModelNG::GetInstance()->ParseCommonTitle( hasSub, hasMain, subResObj, mainResObj); } else { return NG::NavDestinationModelNG::GetInstance()->ParseCommonTitle( hasSub, hasMain, subTitle, mainTitle); } } return false; } void ParseCommonAndCustomTitle(const JSRef& jsObj) { // NavigationCommonTitle if (ParseCommonTitle(jsObj)) { return; } // CustomBuilder | NavigationCustomTitle CalcDimension titleHeight; if (!jsObj->HasProperty("height")) { NavDestinationModel::GetInstance()->SetTitleHeight(titleHeight, false); return; } JSRef height = jsObj->GetProperty("height"); RefPtr heightResObj; bool isValid = JSContainerBase::ParseJsDimensionVpNG(height, titleHeight, heightResObj); if (height->IsString()) { std::string heightValue; JSViewAbstract::ParseJsString(height, heightValue); if (heightValue == NG::TITLE_MAIN_WITH_SUB) { NavDestinationModel::GetInstance()->SetTitleHeight(NG::DOUBLE_LINE_TITLEBAR_HEIGHT); return; } if (heightValue == NG::TITLE_MAIN) { NavDestinationModel::GetInstance()->SetTitleHeight(NG::SINGLE_LINE_TITLEBAR_HEIGHT); return; } } if (!isValid || titleHeight.Value() < 0) { NavDestinationModel::GetInstance()->SetTitleHeight(Dimension(), true); return; } if (SystemProperties::ConfigChangePerform() && heightResObj) { NavDestinationModel::GetInstance()->SetTitleHeight(titleHeight, heightResObj); return; } NavDestinationModel::GetInstance()->SetTitleHeight(titleHeight); } void ParseBackButtonText(const JSCallbackInfo& info, RefPtr& pixMap, const NG::ImageOption& imageOption, const std::function)>& iconSymbol, std::string src, const std::vector& nameList, RefPtr& backButtonIconResObj) { std::string backButtonAccessibilityText; RefPtr backButtonTextResObj; JSViewAbstract::ParseJsString(info[1], backButtonAccessibilityText, backButtonTextResObj); if (SystemProperties::ConfigChangePerform()) { if (backButtonIconResObj && backButtonTextResObj) { NavDestinationModel::GetInstance()->SetBackButtonIconSrcAndTextRes( iconSymbol, backButtonIconResObj, imageOption, pixMap, nameList, true, backButtonTextResObj); return; } if (backButtonTextResObj) { NavDestinationModel::GetInstance()->SetBackButtonIconTextRes( iconSymbol, src, imageOption, pixMap, nameList, true, backButtonTextResObj); return; } if (backButtonIconResObj) { NavDestinationModel::GetInstance()->SetBackButtonIcon( iconSymbol, backButtonIconResObj, imageOption, pixMap, nameList, true, backButtonAccessibilityText); return; } } NavDestinationModel::GetInstance()->SetBackButtonIcon( iconSymbol, src, imageOption, pixMap, nameList, true, backButtonAccessibilityText); } } // namespace void JSNavDestination::Create() { NavDestinationModel::GetInstance()->Create(); NavDestinationModel::GetInstance()->SetScrollableProcessor( []() { return AceType::MakeRefPtr(); }); } void JSNavDestination::Create(const JSCallbackInfo& info) { if (info.Length() <= 0) { NavDestinationModel::GetInstance()->Create(); NavDestinationModel::GetInstance()->SetScrollableProcessor( []() { return AceType::MakeRefPtr(); }); return; } std::string moduleName; std::string pagePath; if (info.Length() == 1) { // input format: builder/pathInfo if (info[0]->IsFunction()) { // first parameter = builder auto builderFunctionJS = info[0]; auto builderFunc = [context = info.GetExecutionContext(), builder = std::move(builderFunctionJS)]() { JAVASCRIPT_EXECUTION_SCOPE(context) JSRef::Cast(builder)->Call(JSRef()); }; auto ctx = AceType::MakeRefPtr(); auto navPathInfo = AceType::MakeRefPtr(); ctx->SetNavPathInfo(navPathInfo); NavDestinationModel::GetInstance()->Create(std::move(builderFunc), std::move(ctx)); NavDestinationModel::GetInstance()->SetScrollableProcessor( []() { return AceType::MakeRefPtr(); }); return; } else if (info[0]->IsObject()) { // first parameter = pathInfo{'moduleName': stringA, 'pagePath': stringB} auto infoObj = JSRef::Cast(info[0]); if (!infoObj->GetProperty(NG::NAVIGATION_MODULE_NAME)->IsString() || !infoObj->GetProperty(NG::NAVIGATION_PAGE_PATH)->IsString()) { TAG_LOGE(AceLogTag::ACE_NAVIGATION, "navDestination current pageInfo is invalid"); return; } moduleName = infoObj->GetProperty(NG::NAVIGATION_MODULE_NAME)->ToString(); pagePath = infoObj->GetProperty(NG::NAVIGATION_PAGE_PATH)->ToString(); NavDestinationModel::GetInstance()->Create(); NavDestinationModel::GetInstance()->SetScrollableProcessor( []() { return AceType::MakeRefPtr(); }); NavDestinationModel::GetInstance()->SetNavDestinationPathInfo(moduleName, pagePath); return; } TAG_LOGE(AceLogTag::ACE_NAVIGATION, "current input info is neither buildFunction or navDestination usefulInfo"); return; } else if (info.Length() == 2) { // parameter = builder(maybe empty) + pathInfo if (!info[0]->IsFunction() || !info[1]->IsObject()) { TAG_LOGE(AceLogTag::ACE_NAVIGATION, "buider or pageInfo is invalid"); return; } auto builderFunctionJS = info[0]; auto builderFunc = [context = info.GetExecutionContext(), builder = std::move(builderFunctionJS)]() { JAVASCRIPT_EXECUTION_SCOPE(context) JSRef::Cast(builder)->Call(JSRef()); }; auto ctx = AceType::MakeRefPtr(); auto navPathInfo = AceType::MakeRefPtr(); ctx->SetNavPathInfo(navPathInfo); auto infoObj = JSRef::Cast(info[1]); if (!infoObj->GetProperty(NG::NAVIGATION_MODULE_NAME)->IsString() || !infoObj->GetProperty(NG::NAVIGATION_PAGE_PATH)->IsString()) { TAG_LOGE(AceLogTag::ACE_NAVIGATION, "navDestination current pageInfo is invalid"); return; } moduleName = infoObj->GetProperty(NG::NAVIGATION_MODULE_NAME)->ToString(); pagePath = infoObj->GetProperty(NG::NAVIGATION_PAGE_PATH)->ToString(); NavDestinationModel::GetInstance()->Create(std::move(builderFunc), std::move(ctx)); NavDestinationModel::GetInstance()->SetScrollableProcessor( []() { return AceType::MakeRefPtr(); }); NavDestinationModel::GetInstance()->SetNavDestinationPathInfo(moduleName, pagePath); } } void JSNavDestination::SetHideTitleBar(const JSCallbackInfo& info) { bool isHide = false; if (info.Length() > 0 && info[0]->IsBoolean()) { isHide = info[0]->ToBoolean(); } bool isAnimated = false; if (info.Length() > 1 && info[1]->IsBoolean()) { isAnimated = info[1]->ToBoolean(); } NavDestinationModel::GetInstance()->SetHideTitleBar(isHide, isAnimated); } void JSNavDestination::SetHideBackButton(const JSCallbackInfo& info) { bool isHide = false; if (info.Length() > 0 && info[0]->IsBoolean()) { isHide = info[0]->ToBoolean(); } NavDestinationModel::GetInstance()->SetHideBackButton(isHide); } void JSNavDestination::SetTitle(const JSCallbackInfo& info) { // Resource and string type. std::string title; RefPtr mainResObj; NavDestinationModel::GetInstance()->ResetResObj( NavDestinationPatternType::TITLE_BAR, "navDestination.title.commonMainTitle"); NavDestinationModel::GetInstance()->ResetResObj( NavDestinationPatternType::TITLE_BAR, "navDestination.title.commonSubTitle"); NavDestinationModel::GetInstance()->ResetResObj( NavDestinationPatternType::TITLE_BAR, "navDestination.title.customtitle"); if (JSViewAbstract::ParseJsString(info[0], title, mainResObj)) { if (SystemProperties::ConfigChangePerform() && mainResObj) { NavDestinationModel::GetInstance()->ParseCommonTitle(false, true, nullptr, mainResObj); } else { NavDestinationModel::GetInstance()->ParseCommonTitle(false, true, "", title); } } else if (info[0]->IsObject()) { JSRef jsObj = JSRef::Cast(info[0]); ParseCommonAndCustomTitle(jsObj); JSRef builderObject = jsObj->GetProperty("builder"); if (builderObject->IsFunction()) { ViewStackModel::GetInstance()->NewScope(); JsFunction jsBuilderFunc(info.This(), JSRef::Cast(builderObject)); ACE_SCORING_EVENT("Navdestination.title.builder"); jsBuilderFunc.Execute(); auto customNode = ViewStackModel::GetInstance()->Finish(); NavDestinationModel::GetInstance()->SetCustomTitle(customNode); } } else { NavDestinationModel::GetInstance()->ParseCommonTitle(false, false, "", ""); } NG::NavigationTitlebarOptions options; NavDestinationModel::GetInstance()->ResetResObj( NavDestinationPatternType::TITLE_BAR, "navDestination.navigationTitlebarOptions"); JSNavigationUtils::ParseTitleBarOptions(info, false, options); NavDestinationModel::GetInstance()->SetTitlebarOptions(std::move(options)); } void JSNavDestination::SetBackButtonIcon(const JSCallbackInfo& info) { // srcType、pixmap、string if (info.Length() < 1) { return; } NavDestinationModel::GetInstance()->ResetResObj( NavDestinationPatternType::TITLE_BAR, "navDestination.backButtonIcon.icon"); NavDestinationModel::GetInstance()->ResetResObj( NavDestinationPatternType::TITLE_BAR, "navDestination.backButtonIcon.accessibilityText"); std::string src; RefPtr backButtonIconResObj; auto noPixMap = ParseJsMedia(info[0], src, backButtonIconResObj); RefPtr pixMap = nullptr; auto isValidImage = false; #if defined(PIXEL_MAP_SUPPORTED) if (!noPixMap) { pixMap = CreatePixelMapFromNapiValue(info[0]); } #endif if (noPixMap || pixMap != nullptr) { isValidImage = true; } std::vector nameList; NG::ImageOption imageOption; std::string bundleName; std::string moduleName; GetJsMediaBundleInfo(info[0], bundleName, moduleName); nameList.emplace_back(bundleName); nameList.emplace_back(moduleName); imageOption.noPixMap = noPixMap; imageOption.isValidImage = isValidImage; std::function)> iconSymbol = nullptr; auto isSymbol = info[0]->IsObject() && src.empty() && pixMap == nullptr; if (isSymbol) { SetSymbolOptionApply(info, iconSymbol, info[0]); } std::string backButtonAccessibilityText; bool configChange = SystemProperties::ConfigChangePerform(); if (info.Length() > 1) { if (!info[1]->IsNull() && !info[1]->IsUndefined()) { ParseBackButtonText(info, pixMap, imageOption, iconSymbol, src, nameList, backButtonIconResObj); return; } } if (configChange && backButtonIconResObj) { NavDestinationModel::GetInstance()->SetBackButtonIcon( iconSymbol, backButtonIconResObj, imageOption, pixMap, nameList); } else { NavDestinationModel::GetInstance()->SetBackButtonIcon(iconSymbol, src, imageOption, pixMap, nameList); } } void JSNavDestination::SetOnShown(const JSCallbackInfo& info) { if (!info[0]->IsFunction()) { return; } auto onShownCallback = AceType::MakeRefPtr(JSRef(), JSRef::Cast(info[0])); WeakPtr targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode()); auto onShown = [execCtx = info.GetExecutionContext(), func = std::move(onShownCallback), node = targetNode]() { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); ACE_SCORING_EVENT("NavDestination.onShown"); PipelineContext::SetCallBackNode(node); JSRef params[1]; params[0] = JSRef::Make(ToJSValue("undefined")); func->ExecuteJS(1, params); }; NavDestinationModel::GetInstance()->SetOnShown(std::move(onShown)); info.ReturnSelf(); } void JSNavDestination::SetOnHidden(const JSCallbackInfo& info) { if (!info[0]->IsFunction()) { return; } auto onHiddenCallback = AceType::MakeRefPtr(JSRef(), JSRef::Cast(info[0])); WeakPtr targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode()); auto onHidden = [execCtx = info.GetExecutionContext(), func = std::move(onHiddenCallback), node = targetNode]() { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); ACE_SCORING_EVENT("NavDestination.onHidden"); PipelineContext::SetCallBackNode(node); func->ExecuteJS(); }; NavDestinationModel::GetInstance()->SetOnHidden(std::move(onHidden)); info.ReturnSelf(); } void JSNavDestination::SetOnBackPressed(const JSCallbackInfo& info) { if (!info[0]->IsFunction()) { return; } auto onBackPressedCallback = AceType::MakeRefPtr(JSRef(), JSRef::Cast(info[0])); auto onBackPressed = [execCtx = info.GetExecutionContext(), func = std::move(onBackPressedCallback)]() -> bool { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, false); ACE_SCORING_EVENT("NavDestination.onBackPressed"); return (func->ExecuteJS())->ToBoolean(); }; NavDestinationModel::GetInstance()->SetOnBackPressed(std::move(onBackPressed)); info.ReturnSelf(); } void JSNavDestination::SetOnReady(const JSCallbackInfo& info) { if (!info[0]->IsFunction()) { return; } auto onReadyCallback = AceType::MakeRefPtr(JSRef(), JSRef::Cast(info[0])); auto onReady = [execCtx = info.GetExecutionContext(), func = std::move(onReadyCallback)]( RefPtr context) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); auto jsContext = JSClass::NewInstance(); auto jsNavDestinationContext = Referenced::Claim(jsContext->Unwrap()); CHECK_NULL_VOID(jsNavDestinationContext); jsNavDestinationContext->SetNavDestinationContext(context); ACE_SCORING_EVENT("NavDestination.onReady"); JSRef params[1]; params[0] = jsContext; func->ExecuteJS(1, params); }; NavDestinationModel::GetInstance()->SetOnReady(std::move(onReady)); info.ReturnSelf(); } void JSNavDestination::SetMode(const JSCallbackInfo& info) { if (!info[0]->IsNumber()) { // set default back ground color NavDestinationModel::GetInstance()->SetNavDestinationMode(NG::NavDestinationMode::STANDARD); return; } auto mode = info[0]->ToNumber(); NavDestinationModel::GetInstance()->SetNavDestinationMode(static_cast(mode)); } void JSNavDestination::SetMenus(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } NavDestinationModel::GetInstance()->ResetResObj( NavDestinationPatternType::NAV_DESTINATION, "navDestination.menuItems"); NavDestinationModel::GetInstance()->ResetResObj( NavDestinationPatternType::NAV_DESTINATION, "navDestination.navigationMenuOptions"); NG::NavigationMenuOptions options; if (info.Length() > 1 && info[1]->IsObject()) { auto optObj = JSRef::Cast(info[1]); auto moreButtonProperty = optObj->GetProperty(MORE_BUTTON_OPTIONS_PROPERTY); JSNavigationUtils::ParseMenuOptions(moreButtonProperty, options); } if (info[0]->IsUndefined() || info[0]->IsArray()) { std::vector menuItems; if (info[0]->IsUndefined()) { menuItems = {}; } else { auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode()); JSNavigationUtils::ParseBarItems(targetNode, info, JSRef::Cast(info[0]), menuItems); } NavDestinationModel::GetInstance()->SetMenuItems(std::move(menuItems)); NavDestinationModel::GetInstance()->SetMenuOptions(std::move(options)); return; } else if (info[0]->IsObject()) { auto builderObject = JSRef::Cast(info[0])->GetProperty("builder"); if (builderObject->IsFunction()) { ViewStackModel::GetInstance()->NewScope(); JsFunction jsBuilderFunc(info.This(), JSRef::Cast(builderObject)); ACE_SCORING_EVENT("NavDestiNation.menu.builder"); jsBuilderFunc.Execute(); auto customNode = ViewStackModel::GetInstance()->Finish(); NavDestinationModel::GetInstance()->SetCustomMenu(customNode); NavDestinationModel::GetInstance()->SetMenuOptions(std::move(options)); } } } void JSNavDestination::SetBackgroundColor(const JSCallbackInfo& info) { Color backgroundColor; RefPtr backgroundColorResObj; bool isValid = ParseJsColor(info[0], backgroundColor, backgroundColorResObj); NavDestinationModel::GetInstance()->SetBackgroundColor(backgroundColor, isValid, backgroundColorResObj); } void JSNavDestination::SetWillAppear(const JSCallbackInfo& info) { if (!info[0]->IsFunction()) { return; } auto willAppear = AceType::MakeRefPtr(JSRef(), JSRef::Cast(info[0])); auto onWillAppear = [execCtx = info.GetExecutionContext(), func = std::move(willAppear)]() { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); ACE_SCORING_EVENT("NavDestination.WillAppear"); func->ExecuteJS(); }; NavDestinationModel::GetInstance()->SetOnWillAppear(std::move(onWillAppear)); info.ReturnSelf(); } void JSNavDestination::SetWillHide(const JSCallbackInfo& info) { if (!info[0]->IsFunction()) { return; } auto willHideCallback = AceType::MakeRefPtr(JSRef(), JSRef::Cast(info[0])); auto onWillHide = [execCtx = info.GetExecutionContext(), func = std::move(willHideCallback)]() { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); ACE_SCORING_EVENT("NavDestination.WillHide"); func->ExecuteJS(); }; NavDestinationModel::GetInstance()->SetOnWillHide(std::move(onWillHide)); info.ReturnSelf(); } void JSNavDestination::SetWillShow(const JSCallbackInfo& info) { if (!info[0]->IsFunction()) { return; } auto willShowCallback = AceType::MakeRefPtr(JSRef(), JSRef::Cast(info[0])); auto onWillShow = [execCtx = info.GetExecutionContext(), func = std::move(willShowCallback)]() { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); ACE_SCORING_EVENT("NavDestination.WillShow"); func->ExecuteJS(); }; NavDestinationModel::GetInstance()->SetOnWillShow(std::move(onWillShow)); info.ReturnSelf(); } void JSNavDestination::SetWillDisAppear(const JSCallbackInfo& info) { if (!info[0]->IsFunction()) { return; } auto WillDisAppear = AceType::MakeRefPtr(JSRef(), JSRef::Cast(info[0])); auto onWillDisAppear = [execCtx = info.GetExecutionContext(), func = std::move(WillDisAppear)]() { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); ACE_SCORING_EVENT("NavDestination.WillDisAppear"); func->ExecuteJS(); }; NavDestinationModel::GetInstance()->SetOnWillDisAppear(std::move(onWillDisAppear)); info.ReturnSelf(); } void JSNavDestination::SetIgnoreLayoutSafeArea(const JSCallbackInfo& info) { NG::IgnoreLayoutSafeAreaOpts opts { .type = NG::LAYOUT_SAFE_AREA_TYPE_SYSTEM, .rawEdges = NG::LAYOUT_SAFE_AREA_EDGE_ALL }; if (info.Length() >= PARAMATER_LENGTH_ONE && info[0]->IsArray()) { auto paramArray = JSRef::Cast(info[0]); uint32_t layoutSafeAreaType = NG::LAYOUT_SAFE_AREA_TYPE_NONE; for (size_t i = 0; i < paramArray->Length(); ++i) { if (!paramArray->GetValueAt(i)->IsNumber() || paramArray->GetValueAt(i)->ToNumber() > LAYOUT_SAFE_AREA_TYPE_LIMIT) { layoutSafeAreaType = NG::SAFE_AREA_TYPE_SYSTEM; break; } layoutSafeAreaType |= NG::IgnoreLayoutSafeAreaOpts::TypeToMask(paramArray->GetValueAt(i)->ToNumber()); } opts.type = layoutSafeAreaType; } if (info.Length() >= PARAMATER_LENGTH_TWO && info[1]->IsArray()) { auto paramArray = JSRef::Cast(info[1]); uint32_t layoutSafeAreaEdge = NG::LAYOUT_SAFE_AREA_EDGE_NONE; for (size_t i = 0; i < paramArray->Length(); ++i) { if (!paramArray->GetValueAt(i)->IsNumber() || paramArray->GetValueAt(i)->ToNumber() > LAYOUT_SAFE_AREA_EDGE_LIMIT) { layoutSafeAreaEdge = NG::LAYOUT_SAFE_AREA_EDGE_ALL; break; } layoutSafeAreaEdge |= NG::IgnoreLayoutSafeAreaOpts::EdgeToMask(paramArray->GetValueAt(i)->ToNumber()); } opts.rawEdges = layoutSafeAreaEdge; } NavDestinationModel::GetInstance()->SetIgnoreLayoutSafeArea(opts); } void JSNavDestination::SetRecoverable(const JSCallbackInfo& info) { if (!info[0]->IsBoolean()) { // the default value of navDestination's recoverable is true NavDestinationModel::GetInstance()->SetRecoverable(true); return; } auto recoverable = info[0]->ToBoolean(); NavDestinationModel::GetInstance()->SetRecoverable(recoverable); } void JSNavDestination::SetToolBarConfiguration(const JSCallbackInfo& info) { bool hideText = false; JSNavigationUtils::ParseHideToolBarText(info, hideText); NavDestinationModel::GetInstance()->SetHideItemText(hideText); NavDestinationModel::GetInstance()->ResetResObj( NavDestinationPatternType::NAV_DESTINATION, "navDestination.toolbarConfiguration"); if (info[0]->IsUndefined() || info[0]->IsArray()) { std::vector toolBarItems; if (info[0]->IsArray()) { auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode()); JSNavigationUtils::ParseToolbarItemsConfiguration( targetNode, info, JSRef::Cast(info[0]), toolBarItems); } NG::MoreButtonOptions toolbarMoreButtonOptions; if (info.Length() > 1 && info[1]->IsObject()) { auto optObj = JSRef::Cast(info[1]); auto moreButtonProperty = optObj->GetProperty(MORE_BUTTON_OPTIONS_PROPERTY); JSNavigationUtils::ParseToolBarMoreButtonOptions(moreButtonProperty, toolbarMoreButtonOptions); } if (SystemProperties::ConfigChangePerform()) { NavDestinationModel::GetInstance()->SetToolbarConfiguration( std::move(toolBarItems), std::move(toolbarMoreButtonOptions)); } else { NavDestinationModel::GetInstance()->SetToolbarMorebuttonOptions(std::move(toolbarMoreButtonOptions)); NavDestinationModel::GetInstance()->SetToolbarConfiguration(std::move(toolBarItems)); } } else if (info[0]->IsObject()) { auto builderFuncParam = JSRef::Cast(info[0])->GetProperty("builder"); if (builderFuncParam->IsFunction()) { ViewStackModel::GetInstance()->NewScope(); JsFunction jsBuilderFunc(builderFuncParam); jsBuilderFunc.Execute(); auto customNode = ViewStackModel::GetInstance()->Finish(); NavDestinationModel::GetInstance()->SetCustomToolBar(customNode); } } NG::NavigationToolbarOptions options; NavDestinationModel::GetInstance()->ResetResObj( NavDestinationPatternType::NAV_DESTINATION, "navigation.navigationToolbarOptions"); JSNavigationUtils::ParseToolbarOptions(info, options); NavDestinationModel::GetInstance()->SetToolBarOptions(std::move(options)); } void JSNavDestination::SetHideToolBar(const JSCallbackInfo& info) { bool isHide = false; if (info.Length() > 0 && info[0]->IsBoolean()) { isHide = info[0]->ToBoolean(); } bool isAnimated = false; if (info.Length() > 1 && info[1]->IsBoolean()) { isAnimated = info[1]->ToBoolean(); } NavDestinationModel::GetInstance()->SetHideToolBar(isHide, isAnimated); } void JSNavDestination::BindToScrollable(const JSCallbackInfo& info) { auto bindFunc = [&info](const RefPtr& processor) { auto jsProcessor = AceType::DynamicCast(processor); CHECK_NULL_VOID(jsProcessor); jsProcessor->BindToScrollable(info); }; NavDestinationModel::GetInstance()->UpdateBindingWithScrollable(std::move(bindFunc)); } void JSNavDestination::BindToNestedScrollable(const JSCallbackInfo& info) { auto bindFunc = [&info](const RefPtr& processor) { auto jsProcessor = AceType::DynamicCast(processor); CHECK_NULL_VOID(jsProcessor); jsProcessor->BindToNestedScrollable(info); }; NavDestinationModel::GetInstance()->UpdateBindingWithScrollable(std::move(bindFunc)); } void JSNavDestination::SetCustomTransition(const JSCallbackInfo& info) { if (info.Length() != 1 || !info[0]->IsFunction()) { NavDestinationModel::GetInstance()->SetCustomTransition(nullptr); return; } auto jsTransitionDelegate = AceType::MakeRefPtr(JSRef::Cast(info[0])); auto transitionDelegate = [execCtx = info.GetExecutionContext(), delegate = std::move(jsTransitionDelegate)]( NG::NavigationOperation operation, bool isEnter) -> std::optional> { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, std::nullopt); JSRef params[2]; params[0] = JSRef::Make(ToJSValue(static_cast(operation))); params[1] = JSRef::Make(ToJSValue(isEnter)); auto ret = delegate->ExecuteJS(2, params); if (!ret->IsArray()) { TAG_LOGI(AceLogTag::ACE_NAVIGATION, "NavDestination custom transition invalid!"); return std::nullopt; } std::vector allTransitions; auto allTransitionObj = JSRef::Cast(ret); for (size_t index = 0; index < allTransitionObj->Length(); ++index) { auto transitionValue = allTransitionObj->GetValueAt(index); if (!transitionValue->IsObject()) { continue; } auto navDestinationTransition = JSNavigationUtils::ParseNavDestinationTransition( JSRef::Cast(transitionValue), execCtx); if (navDestinationTransition.has_value()) { allTransitions.emplace_back(navDestinationTransition.value()); } } return allTransitions; }; NavDestinationModel::GetInstance()->SetCustomTransition(std::move(transitionDelegate)); } void JSNavDestination::JSBind(BindingTarget globalObj) { JSNavDestinationContext::JSBind(globalObj); JSClass::Declare("NavDestination"); JSClass::StaticMethod("create", &JSNavDestination::Create); JSClass::StaticMethod("title", &JSNavDestination::SetTitle); JSClass::StaticMethod("hideTitleBar", &JSNavDestination::SetHideTitleBar); JSClass::StaticMethod("hideBackButton", &JSNavDestination::SetHideBackButton); JSClass::StaticMethod("backButtonIcon", &JSNavDestination::SetBackButtonIcon); JSClass::StaticMethod("backgroundColor", &JSNavDestination::SetBackgroundColor); JSClass::StaticMethod("onShown", &JSNavDestination::SetOnShown); JSClass::StaticMethod("onHidden", &JSNavDestination::SetOnHidden); JSClass::StaticMethod("onBackPressed", &JSNavDestination::SetOnBackPressed); JSClass::StaticMethod("onReady", &JSNavDestination::SetOnReady); JSClass::StaticMethod("onAttach", &JSInteractableView::JsOnAttach); JSClass::StaticMethod("onAppear", &JSInteractableView::JsOnAppear); JSClass::StaticMethod("onDetach", &JSInteractableView::JsOnDetach); JSClass::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear); JSClass::StaticMethod("onTouch", &JSInteractableView::JsOnTouch); JSClass::StaticMethod("id", &JSViewAbstract::JsId); JSClass::StaticMethod("mode", &JSNavDestination::SetMode); JSClass::StaticMethod("menus", &JSNavDestination::SetMenus); JSClass::StaticMethod("onWillAppear", &JSNavDestination::SetWillAppear); JSClass::StaticMethod("onWillShow", &JSNavDestination::SetWillShow); JSClass::StaticMethod("onWillHide", &JSNavDestination::SetWillHide); JSClass::StaticMethod("onWillDisappear", &JSNavDestination::SetWillDisAppear); JSClass::StaticMethod("onActive", &JSNavDestination::SetOnActive); JSClass::StaticMethod("onInactive", &JSNavDestination::SetOnInactive); JSClass::StaticMethod("onResult", &JSNavDestination::SetResultCallback); JSClass::StaticMethod("ignoreLayoutSafeArea", &JSNavDestination::SetIgnoreLayoutSafeArea); JSClass::StaticMethod("systemBarStyle", &JSNavDestination::SetSystemBarStyle); JSClass::StaticMethod("recoverable", &JSNavDestination::SetRecoverable); JSClass::StaticMethod("toolbarConfiguration", &JSNavDestination::SetToolBarConfiguration); JSClass::StaticMethod("hideToolBar", &JSNavDestination::SetHideToolBar); JSClass::StaticMethod("systemTransition", &JSNavDestination::SetSystemTransition); JSClass::StaticMethod("bindToScrollable", &JSNavDestination::BindToScrollable); JSClass::StaticMethod("bindToNestedScrollable", &JSNavDestination::BindToNestedScrollable); JSClass::StaticMethod("customTransition", &JSNavDestination::SetCustomTransition); JSClass::StaticMethod("onNewParam", &JSNavDestination::SetOnNewParam); JSClass::StaticMethod("preferredOrientation", &JSNavDestination::SetPreferredOrientation); JSClass::StaticMethod("enableStatusBar", &JSNavDestination::EnableStatusBar); JSClass::StaticMethod("enableNavigationIndicator", &JSNavDestination::EnableNavigationIndicator); JSClass::InheritAndBind(globalObj); } void JSNavDestination::SetSystemBarStyle(const JSCallbackInfo& info) { RefPtr style = nullptr; if (info.Length() == 1 && info[0]->IsObject()) { auto styleObj = JsConverter::ConvertJsValToNapiValue(info[0]); auto env = GetCurrentEnv(); if (env) { style = SystemBarStyle::CreateStyleFromJsObj(env, styleObj); } } NavDestinationModel::GetInstance()->SetSystemBarStyle(style); } void JSNavDestination::SetSystemTransition(const JSCallbackInfo& info) { if (!info[0]->IsNumber()) { NavDestinationModel::GetInstance()->SetSystemTransitionType(NG::NavigationSystemTransitionType::DEFAULT); return; } auto value = info[0]->ToNumber(); NG::NavigationSystemTransitionType type = ParseTransitionType(value); NavDestinationModel::GetInstance()->SetSystemTransitionType(type); } void JSNavDestination::SetResultCallback(const JSCallbackInfo& info) { if (info.Length() < 1) { return; } if (!info[0]->IsFunction()) { return; } auto func = JSRef::Cast(info[0]); if (func->IsEmpty()) { return; } auto setPopCallback = [func](const RefPtr& info) { auto pathInfo = AceType::DynamicCast(info); CHECK_NULL_VOID(pathInfo); pathInfo->SetNavDestinationPopCallback(func); }; NavDestinationModel::GetInstance()->SetOnPop(setPopCallback); } void JSNavDestination::SetOnActive(const JSCallbackInfo& info) { if (info.Length() <= 0) { return; } if (!info[0]->IsFunction()) { return; } auto onActive = AceType::MakeRefPtr(JSRef(), JSRef::Cast(info[0])); auto onActiveCallback = [exeCtx = info.GetExecutionContext(), func = std::move(onActive)](int32_t reason) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(exeCtx); ACE_SCORING_EVENT("NavDestination.OnActive"); JSRef params[1]; params[0] = JSRef::Make(ToJSValue(reason)); func->ExecuteJS(1, params); }; NavDestinationModel::GetInstance()->SetOnActive(std::move(onActiveCallback)); info.ReturnSelf(); } void JSNavDestination::SetOnInactive(const JSCallbackInfo& info) { if (info.Length() <= 0) { return; } if (!info[0]->IsFunction()) { return; } auto onInactive = AceType::MakeRefPtr(JSRef(), JSRef::Cast(info[0])); auto onInactiveCallback = [execCtx = info.GetExecutionContext(), func = std::move(onInactive)](int32_t reason) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); ACE_SCORING_EVENT("NavDestination.OnInactive"); JSRef params[1]; params[0] = JSRef::Make(ToJSValue(reason)); func->ExecuteJS(1, params); }; NavDestinationModel::GetInstance()->SetOnInactive(std::move(onInactiveCallback)); info.ReturnSelf(); } void JSNavDestination::SetOnNewParam(const JSCallbackInfo& info) { if (info.Length() <= 0 || !info[0]->IsFunction()) { return; } auto onNewParam = AceType::MakeRefPtr(JSRef::Cast(info[0])); auto onNewParamCallback = [execCtx = info.GetExecutionContext(), func = std::move(onNewParam)](napi_value param) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); ACE_SCORING_EVENT("NavDestination.onNewParam"); JSRef params[1]; params[0] = JsConverter::ConvertNapiValueToJsVal(param); func->ExecuteJS(1, params); }; NavDestinationModel::GetInstance()->SetOnNewParam(std::move(onNewParamCallback)); info.ReturnSelf(); } void JSNavDestination::SetPreferredOrientation(const JSCallbackInfo& info) { std::optional orientation; if (info.Length() > 0 && info[0]->IsNumber()) { auto ori = info[0]->ToNumber(); if (ori >= static_cast(ApiOrientation::BEGIN) && ori <= static_cast(ApiOrientation::END)) { orientation = JS_TO_NATIVE_ORIENTATION_MAP.at(static_cast(ori)); } } NavDestinationModel::GetInstance()->SetPreferredOrientation(orientation); } void JSNavDestination::EnableStatusBar(const JSCallbackInfo& info) { std::optional> statusBar; if (info.Length() > 0 && info[0]->IsBoolean()) { bool enable = info[0]->ToBoolean(); bool animated = false; if (info.Length() > 1 && info[1]->IsBoolean()) { animated = info[1]->ToBoolean(); } statusBar = std::make_pair(enable, animated); } NavDestinationModel::GetInstance()->SetEnableStatusBar(statusBar); } void JSNavDestination::EnableNavigationIndicator(const JSCallbackInfo& info) { std::optional navigationIndicator; if (info.Length() > 0 && info[0]->IsBoolean()) { navigationIndicator = info[0]->ToBoolean(); } NavDestinationModel::GetInstance()->SetEnableNavigationIndicator(navigationIndicator); } } // namespace OHOS::Ace::Framework