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