• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_navigation_utils.h"
17 
18 #include "frameworks/base/log/ace_scoring_log.h"
19 #include "bridge/declarative_frontend/jsview/js_utils.h"
20 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
21 
22 namespace OHOS::Ace::Framework {
23 
24 namespace {
25 // navigation title bar options
26 constexpr char BACKGROUND_COLOR_PROPERTY[] = "backgroundColor";
27 constexpr char BACKGROUND_BLUR_STYLE_PROPERTY[] = "backgroundBlurStyle";
28 constexpr char BAR_STYLE_PROPERTY[] = "barStyle";
29 constexpr char PADDING_START_PROPERTY[] = "paddingStart";
30 constexpr char PADDING_END_PROPERTY[] = "paddingEnd";
31 constexpr char MAIN_TITLE_MODIFIER[] = "mainTitleModifier";
32 constexpr char SUB_TITLE_MODIFIER[] = "subTitleModifier";
33 
ParseSymbolAndIcon(const JSCallbackInfo & info,NG::BarItem & toolBarItem,const JSRef<JSObject> & itemObject)34 void ParseSymbolAndIcon(const JSCallbackInfo& info, NG::BarItem& toolBarItem,
35     const JSRef<JSObject>& itemObject)
36 {
37     std::string icon;
38     std::string activeIcon;
39     auto itemSymbolIconObject = itemObject->GetProperty("symbolIcon");
40     if (itemSymbolIconObject->IsObject()) {
41         std::function<void(WeakPtr<NG::FrameNode>)> iconSymbol = nullptr;
42         JSViewAbstract::SetSymbolOptionApply(info, iconSymbol, itemSymbolIconObject);
43         toolBarItem.iconSymbol = iconSymbol;
44     }
45     auto itemIconObject = itemObject->GetProperty("icon");
46     if (JSViewAbstract::ParseJsMedia(itemIconObject, icon)) {
47         toolBarItem.icon = icon;
48     }
49 
50     auto itemActiveSymbolIconObject = itemObject->GetProperty("activeSymbolIcon");
51     if (itemActiveSymbolIconObject->IsObject()) {
52         std::function<void(WeakPtr<NG::FrameNode>)> activeSymbol = nullptr;
53         JSViewAbstract::SetSymbolOptionApply(info, activeSymbol, itemActiveSymbolIconObject);
54         toolBarItem.activeIconSymbol = activeSymbol;
55     }
56     auto itemActiveIconObject = itemObject->GetProperty("activeIcon");
57     if (JSViewAbstract::ParseJsMedia(itemActiveIconObject, activeIcon)) {
58         toolBarItem.activeIcon = activeIcon;
59     }
60 }
61 
ParseBackgroundOptions(const JSRef<JSVal> & obj,NG::NavigationBackgroundOptions & options)62 void ParseBackgroundOptions(const JSRef<JSVal>& obj, NG::NavigationBackgroundOptions& options)
63 {
64     options.color.reset();
65     options.blurStyle.reset();
66     if (!obj->IsObject()) {
67         return;
68     }
69     auto optObj = JSRef<JSObject>::Cast(obj);
70     auto colorProperty = optObj->GetProperty(BACKGROUND_COLOR_PROPERTY);
71     Color color;
72     if (JSViewAbstract::ParseJsColor(colorProperty, color)) {
73         options.color = color;
74     }
75     auto blurProperty = optObj->GetProperty(BACKGROUND_BLUR_STYLE_PROPERTY);
76     if (blurProperty->IsNumber()) {
77         auto blurStyle = blurProperty->ToNumber<int32_t>();
78         if (blurStyle >= static_cast<int>(BlurStyle::NO_MATERIAL) &&
79             blurStyle <= static_cast<int>(BlurStyle::COMPONENT_ULTRA_THICK)) {
80             options.blurStyle = static_cast<BlurStyle>(blurStyle);
81         }
82     }
83 }
84 
ParseBarOptions(const JSRef<JSVal> & obj,NG::NavigationBarOptions & options)85 void ParseBarOptions(const JSRef<JSVal>& obj, NG::NavigationBarOptions& options)
86 {
87     options.paddingStart.reset();
88     options.paddingEnd.reset();
89     options.barStyle.reset();
90     if (!obj->IsObject()) {
91         return;
92     }
93     auto optObj = JSRef<JSObject>::Cast(obj);
94     auto barStyleProperty = optObj->GetProperty(BAR_STYLE_PROPERTY);
95     if (barStyleProperty->IsNumber()) {
96         auto barStyle = barStyleProperty->ToNumber<int32_t>();
97         if (barStyle >= static_cast<int32_t>(NG::BarStyle::STANDARD) &&
98             barStyle <= static_cast<int32_t>(NG::BarStyle::SAFE_AREA_PADDING)) {
99             options.barStyle = static_cast<NG::BarStyle>(barStyle);
100         } else {
101             options.barStyle = NG::BarStyle::STANDARD;
102         }
103     }
104     CalcDimension paddingStart;
105     if (JSViewAbstract::ParseLengthMetricsToDimension(optObj->GetProperty(PADDING_START_PROPERTY), paddingStart)) {
106         options.paddingStart = paddingStart;
107     }
108     CalcDimension paddingEnd;
109     if (JSViewAbstract::ParseLengthMetricsToDimension(optObj->GetProperty(PADDING_END_PROPERTY), paddingEnd)) {
110         options.paddingEnd = paddingEnd;
111     }
112 }
113 
ParseTextOptions(const JSCallbackInfo & info,const JSRef<JSVal> & obj,NG::NavigationTextOptions & options)114 void ParseTextOptions(const JSCallbackInfo& info, const JSRef<JSVal>& obj, NG::NavigationTextOptions& options)
115 {
116     options.Reset();
117     if (!obj->IsObject()) {
118         return;
119     }
120     auto optObj = JSRef<JSObject>::Cast(obj);
121     auto mainTitleModifierProperty = optObj->GetProperty(MAIN_TITLE_MODIFIER);
122     auto subTitleModifierProperty = optObj->GetProperty(SUB_TITLE_MODIFIER);
123     JSViewAbstract::SetTextStyleApply(info, options.mainTitleApplyFunc, mainTitleModifierProperty);
124     JSViewAbstract::SetTextStyleApply(info, options.subTitleApplyFunc, subTitleModifierProperty);
125 }
126 
ParseToolBarItemAction(const WeakPtr<NG::FrameNode> & targetNode,const JSCallbackInfo & info,const JSRef<JSObject> & itemObject,NG::BarItem & toolBarItem)127 void ParseToolBarItemAction(const WeakPtr<NG::FrameNode>& targetNode,
128     const JSCallbackInfo& info, const JSRef<JSObject>& itemObject, NG::BarItem& toolBarItem)
129 {
130     auto itemActionValue = itemObject->GetProperty("action");
131     if (!itemActionValue->IsFunction()) {
132         return;
133     }
134 
135     RefPtr<JsFunction> onClickFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(itemActionValue));
136     auto onItemClick = [execCtx = info.GetExecutionContext(), func = std::move(onClickFunc),
137                             node = targetNode]() {
138         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
139         if (func) {
140             PipelineContext::SetCallBackNode(node);
141             func->ExecuteJS();
142         }
143     };
144     toolBarItem.action = onItemClick;
145 }
146 }
147 
ParseToolbarItemsConfiguration(const WeakPtr<NG::FrameNode> & targetNode,const JSCallbackInfo & info,const JSRef<JSArray> & jsArray,std::vector<NG::BarItem> & items)148 void JSNavigationUtils::ParseToolbarItemsConfiguration(const WeakPtr<NG::FrameNode>& targetNode,
149     const JSCallbackInfo& info, const JSRef<JSArray>& jsArray, std::vector<NG::BarItem>& items)
150 {
151     auto length = jsArray->Length();
152     for (size_t i = 0; i < length; i++) {
153         auto item = jsArray->GetValueAt(i);
154         if (!item->IsObject()) {
155             continue;
156         }
157 
158         NG::BarItem toolBarItem;
159         std::string text;
160         auto itemObject = JSRef<JSObject>::Cast(item);
161         auto itemValueObject = itemObject->GetProperty("value");
162         if (JSViewAbstract::ParseJsString(itemValueObject, text)) {
163             toolBarItem.text = text;
164         }
165 
166         ParseToolBarItemAction(targetNode, info, itemObject, toolBarItem);
167 
168         auto itemStatusValue = itemObject->GetProperty("status");
169         if (itemStatusValue->IsNumber()) {
170             toolBarItem.status = static_cast<NG::NavToolbarItemStatus>(itemStatusValue->ToNumber<int32_t>());
171         }
172         ParseSymbolAndIcon(info, toolBarItem, itemObject);
173         items.push_back(toolBarItem);
174     }
175 }
176 
ParseTitleBarOptions(const JSCallbackInfo & info,bool needSetDefaultValue,NG::NavigationTitlebarOptions & options)177 void JSNavigationUtils::ParseTitleBarOptions(
178     const JSCallbackInfo& info, bool needSetDefaultValue, NG::NavigationTitlebarOptions& options)
179 {
180     if (needSetDefaultValue) {
181         if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
182             auto pipelineContext = PipelineBase::GetCurrentContext();
183             CHECK_NULL_VOID(pipelineContext);
184             auto theme = pipelineContext->GetTheme<NavigationBarTheme>();
185             CHECK_NULL_VOID(theme);
186             auto blurStyle = static_cast<BlurStyle>(theme->GetTitlebarBackgroundBlurStyle());
187             if (blurStyle != BlurStyle::NO_MATERIAL) {
188                 options.bgOptions.blurStyle = blurStyle;
189                 options.bgOptions.color = Color::TRANSPARENT;
190             }
191         }
192     }
193 
194     if (info.Length() > 1) {
195         if (!info[1]->IsObject()) {
196             return;
197         }
198         ParseBackgroundOptions(info[1], options.bgOptions);
199         ParseBarOptions(info[1], options.brOptions);
200         ParseTextOptions(info, info[1], options.textOptions);
201         JSRef<JSObject> jsObjOption = JSRef<JSObject>::Cast(info[1]);
202         auto enableHoverModeProperty = jsObjOption->GetProperty("enableHoverMode");
203         if (enableHoverModeProperty->IsBoolean()) {
204             options.enableHoverMode = enableHoverModeProperty->ToBoolean();
205         }
206     }
207 }
208 
ParseToolbarOptions(const JSCallbackInfo & info,NG::NavigationToolbarOptions & options)209 void JSNavigationUtils::ParseToolbarOptions(const JSCallbackInfo& info, NG::NavigationToolbarOptions& options)
210 {
211     if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
212         auto pipelineContext = PipelineBase::GetCurrentContext();
213         CHECK_NULL_VOID(pipelineContext);
214         auto theme = pipelineContext->GetTheme<NavigationBarTheme>();
215         CHECK_NULL_VOID(theme);
216         auto blurStyle = static_cast<BlurStyle>(theme->GetToolbarBackgroundBlurStyle());
217         if (blurStyle != BlurStyle::NO_MATERIAL) {
218             options.bgOptions.blurStyle = blurStyle;
219             options.bgOptions.color = Color::TRANSPARENT;
220         }
221     }
222     if (info.Length() > 1) {
223         ParseBackgroundOptions(info[1], options.bgOptions);
224         ParseBarOptions(info[1], options.brOptions);
225     }
226 }
227 
ParseBarItems(const WeakPtr<NG::FrameNode> & targetNode,const JSCallbackInfo & info,const JSRef<JSArray> & jsArray,std::vector<NG::BarItem> & items)228 void JSNavigationUtils::ParseBarItems(const WeakPtr<NG::FrameNode>& targetNode,
229     const JSCallbackInfo& info, const JSRef<JSArray>& jsArray, std::vector<NG::BarItem>& items)
230 {
231     auto length = jsArray->Length();
232     for (size_t i = 0; i < length; i++) {
233         auto item = jsArray->GetValueAt(i);
234         if (!item->IsObject()) {
235             continue;
236         }
237         auto itemObject = JSRef<JSObject>::Cast(item);
238         NG::BarItem toolBarItem;
239         std::string value;
240         auto itemValueObject = itemObject->GetProperty("value");
241         if (JSViewAbstract::ParseJsString(itemValueObject, value)) {
242             toolBarItem.text = value;
243         }
244 
245         auto itemSymbolIconObject = itemObject->GetProperty("symbolIcon");
246         if (itemSymbolIconObject->IsObject()) {
247             std::function<void(WeakPtr<NG::FrameNode>)> iconSymbol = nullptr;
248             JSViewAbstract::SetSymbolOptionApply(info, iconSymbol, itemSymbolIconObject);
249             toolBarItem.iconSymbol = iconSymbol;
250         }
251         std::string icon;
252         auto itemIconObject = itemObject->GetProperty("icon");
253         if (JSViewAbstract::ParseJsMedia(itemIconObject, icon)) {
254             toolBarItem.icon = icon;
255         }
256 
257         auto itemEnabledObject = itemObject->GetProperty("isEnabled");
258         if (itemEnabledObject->IsBoolean()) {
259             toolBarItem.isEnabled = itemEnabledObject->ToBoolean();
260         }
261 
262         ParseToolBarItemAction(targetNode, info, itemObject, toolBarItem);
263         items.push_back(toolBarItem);
264     }
265 }
266 
ParseNavDestinationTransition(const JSRef<JSObject> & jsTransition,const JsiExecutionContext & execCtx)267 std::optional<NG::NavDestinationTransition> JSNavigationUtils::ParseNavDestinationTransition(
268     const JSRef<JSObject>& jsTransition, const JsiExecutionContext& execCtx)
269 {
270     if (jsTransition->IsEmpty() || jsTransition->IsUndefined()) {
271         return std::nullopt;
272     }
273     NG::NavDestinationTransition navDestinationTransition;
274     JSRef<JSVal> event = jsTransition->GetProperty("event");
275     if (!event->IsFunction()) {
276         // property `event` of navDestinationTransition is required option, so return nullopt if it's invalid.
277         return std::nullopt;
278     } else {
279         auto eventFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(event));
280         auto transitionEvent = [execCtx, event = std::move(eventFunc)]() {
281             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
282             ACE_SCORING_EVENT("navDestination custom transition event");
283             event->ExecuteJS();
284         };
285         navDestinationTransition.event = std::move(transitionEvent);
286     }
287     JSRef<JSVal> jsOnTransitionEnd = jsTransition->GetProperty("onTransitionEnd");
288     if (jsOnTransitionEnd->IsFunction()) {
289         auto transitionEndFunc =
290             AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(jsOnTransitionEnd));
291         auto onTransitionEnd = [execCtx, transitionEnd = std::move(transitionEndFunc)]() {
292             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
293             ACE_SCORING_EVENT("navDestination custom transition finish");
294             transitionEnd->ExecuteJS();
295         };
296         navDestinationTransition.onTransitionEnd = std::move(onTransitionEnd);
297     }
298     JSRef<JSVal> duration = jsTransition->GetProperty("duration");
299     // default duration: 1000.
300     navDestinationTransition.duration = duration->IsNumber() ? duration->ToNumber<int32_t>() : 1000;
301     JSRef<JSVal> delay = jsTransition->GetProperty("delay");
302     // default delay: 0.
303     navDestinationTransition.delay = delay->IsNumber() ? delay->ToNumber<int32_t>() : 0;
304     JSRef<JSVal> curveArgs = jsTransition->GetProperty("curve");
305     if (curveArgs->IsString()) {
306         navDestinationTransition.curve = CreateCurve(curveArgs->ToString(), false);
307     } else if (curveArgs->IsObject()) {
308         JSRef<JSVal> curveString = JSRef<JSObject>::Cast(curveArgs)->GetProperty("__curveString");
309         if (curveString->IsString()) {
310             navDestinationTransition.curve = CreateCurve(curveString->ToString(), false);
311         }
312     } else {
313         // default curve: easeInOut
314         navDestinationTransition.curve = Curves::EASE_IN_OUT;
315     }
316     return navDestinationTransition;
317 }
318 } // namespace OHOS::Ace::Framework
319