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