1 /*
2 * Copyright (c) 2022-2023 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_side_bar.h"
17
18 #include "base/geometry/dimension.h"
19 #include "base/image/pixel_map.h"
20 #include "base/log/ace_scoring_log.h"
21 #include "base/log/log.h"
22 #include "bridge/declarative_frontend/engine/js_ref_ptr.h"
23 #include "bridge/declarative_frontend/engine/js_types.h"
24 #include "bridge/declarative_frontend/jsview/js_utils.h"
25 #include "core/components_ng/base/view_stack_processor.h"
26 #include "core/components_ng/pattern/side_bar/side_bar_container_model_ng.h"
27 #include "frameworks/bridge/declarative_frontend/jsview/js_view_common_def.h"
28 #include "frameworks/bridge/declarative_frontend/jsview/models/side_bar_container_model_impl.h"
29
30 namespace OHOS::Ace {
31 std::unique_ptr<SideBarContainerModel> SideBarContainerModel::instance_ = nullptr;
32 std::mutex SideBarContainerModel::mutex_;
33
GetInstance()34 SideBarContainerModel* SideBarContainerModel::GetInstance()
35 {
36 if (!instance_) {
37 std::lock_guard<std::mutex> lock(mutex_);
38 if (!instance_) {
39 #ifdef NG_BUILD
40 instance_.reset(new NG::SideBarContainerModelNG());
41 #else
42 if (Container::IsCurrentUseNewPipeline()) {
43 instance_.reset(new NG::SideBarContainerModelNG());
44 } else {
45 instance_.reset(new Framework::SideBarContainerModelImpl());
46 }
47 #endif
48 }
49 }
50 return instance_.get();
51 }
52 } // namespace OHOS::Ace
53
54 namespace OHOS::Ace::Framework {
55 namespace {
56 constexpr Dimension DEFAULT_CONTROL_BUTTON_WIDTH = 32.0_vp;
57 constexpr Dimension DEFAULT_CONTROL_BUTTON_HEIGHT = 32.0_vp;
58 constexpr Dimension DEFAULT_CONTROL_BUTTON_TOP = 48.0_vp;
59 constexpr Dimension DEFAULT_DIVIDER_STROKE_WIDTH = 1.0_vp;
60 constexpr Dimension DEFAULT_DIVIDER_START_MARGIN = 0.0_vp;
61 constexpr Dimension DEFAULT_DIVIDER_END_MARGIN = 0.0_vp;
62 static Dimension DEFAULT_SIDE_BAR_WIDTH = 200.0_vp;
63 static Dimension DEFAULT_MIN_SIDE_BAR_WIDTH = 200.0_vp;
64 constexpr Dimension DEFAULT_MAX_SIDE_BAR_WIDTH = 280.0_vp;
65 constexpr Color DEFAULT_DIVIDER_COLOR = Color(0x08000000);
66
ParseAndSetWidth(const JSCallbackInfo & info,WidthType widthType)67 void ParseAndSetWidth(const JSCallbackInfo& info, WidthType widthType)
68 {
69 if (info.Length() < 1) {
70 return;
71 }
72
73 CalcDimension value;
74 if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)) {
75 DEFAULT_SIDE_BAR_WIDTH = 240.0_vp;
76 DEFAULT_MIN_SIDE_BAR_WIDTH = 240.0_vp;
77 }
78
79 auto isValid = Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN)
80 ? JSViewAbstract::ParseJsDimensionVpNG(info[0], value)
81 : JSViewAbstract::ParseJsDimensionVp(info[0], value);
82
83 if (!isValid) {
84 switch (widthType) {
85 case WidthType::SIDEBAR_WIDTH:
86 value = DEFAULT_SIDE_BAR_WIDTH;
87 break;
88 case WidthType::MIN_SIDEBAR_WIDTH:
89 value = DEFAULT_MIN_SIDE_BAR_WIDTH;
90 break;
91 case WidthType::MAX_SIDEBAR_WIDTH:
92 value = DEFAULT_MAX_SIDE_BAR_WIDTH;
93 break;
94 default:
95 break;
96 }
97 }
98 SideBarContainerModel::GetInstance()->ParseAndSetWidth(widthType, value);
99 }
100 } // namespace
101
Create(const JSCallbackInfo & info)102 void JSSideBar::Create(const JSCallbackInfo& info)
103 {
104 SideBarContainerModel::GetInstance()->Create();
105 SideBarContainerType style = SideBarContainerType::EMBED;
106 if (!info[0]->IsNull()) {
107 if (info[0]->IsBoolean()) {
108 style = static_cast<SideBarContainerType>(info[0]->ToBoolean());
109 } else if (info[0]->IsNumber()) {
110 style = static_cast<SideBarContainerType>(info[0]->ToNumber<int>());
111 } else {
112 return;
113 }
114 }
115 SideBarContainerModel::GetInstance()->SetSideBarContainerType(style);
116 }
117
SetShowControlButton(bool isShow)118 void JSSideBar::SetShowControlButton(bool isShow)
119 {
120 SideBarContainerModel::GetInstance()->SetShowControlButton(isShow);
121 }
122
JsSideBarPosition(const JSCallbackInfo & info)123 void JSSideBar::JsSideBarPosition(const JSCallbackInfo& info)
124 {
125 if (info.Length() < 1) {
126 return;
127 }
128 SideBarPosition sideBarPosition = SideBarPosition::START;
129 if (info[0]->IsNumber()) {
130 sideBarPosition = static_cast<SideBarPosition>(info[0]->ToNumber<int>());
131 } else {
132 return;
133 }
134 SideBarContainerModel::GetInstance()->SetSideBarPosition(sideBarPosition);
135 }
136
JSBind(BindingTarget globalObj)137 void JSSideBar::JSBind(BindingTarget globalObj)
138 {
139 JSClass<JSSideBar>::Declare("SideBarContainer");
140 MethodOptions opt = MethodOptions::NONE;
141 JSClass<JSSideBar>::StaticMethod("create", &JSSideBar::Create, opt);
142 JSClass<JSSideBar>::StaticMethod("showSideBar", &JSSideBar::JsShowSideBar);
143 JSClass<JSSideBar>::StaticMethod("controlButton", &JSSideBar::JsControlButton);
144 JSClass<JSSideBar>::StaticMethod("showControlButton", &JSSideBar::SetShowControlButton);
145 JSClass<JSSideBar>::StaticMethod("onChange", &JSSideBar::OnChange);
146 JSClass<JSSideBar>::StaticMethod("sideBarWidth", &JSSideBar::JsSideBarWidth);
147 JSClass<JSSideBar>::StaticMethod("minSideBarWidth", &JSSideBar::JsMinSideBarWidth);
148 JSClass<JSSideBar>::StaticMethod("maxSideBarWidth", &JSSideBar::JsMaxSideBarWidth);
149 JSClass<JSSideBar>::StaticMethod("autoHide", &JSSideBar::JsAutoHide);
150 JSClass<JSSideBar>::StaticMethod("sideBarPosition", &JSSideBar::JsSideBarPosition);
151 JSClass<JSSideBar>::StaticMethod("divider", &JSSideBar::JsDivider);
152 JSClass<JSSideBar>::StaticMethod("minContentWidth", &JSSideBar::JsMinContentWidth);
153 JSClass<JSSideBar>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
154 JSClass<JSSideBar>::StaticMethod("width", SetWidth);
155 JSClass<JSSideBar>::StaticMethod("height", SetHeight);
156 JSClass<JSSideBar>::StaticMethod("size", SetSize);
157 JSClass<JSSideBar>::StaticMethod("width", &JSStack::SetWidth);
158 JSClass<JSSideBar>::StaticMethod("height", &JSStack::SetHeight);
159 JSClass<JSSideBar>::StaticMethod("size", &JSStack::SetSize);
160 JSClass<JSSideBar>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
161 JSClass<JSSideBar>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
162 JSClass<JSSideBar>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
163 JSClass<JSSideBar>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
164 JSClass<JSSideBar>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
165 JSClass<JSSideBar>::InheritAndBind<JSContainerBase>(globalObj);
166 }
167
OnChange(const JSCallbackInfo & info)168 void JSSideBar::OnChange(const JSCallbackInfo& info)
169 {
170 if (info.Length() < 1 || !info[0]->IsFunction()) {
171 return;
172 }
173
174 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
175 WeakPtr<NG::FrameNode> targetNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
176 auto onChange = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](bool isShow) {
177 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
178 ACE_SCORING_EVENT("SideBarContainer.onChange");
179 PipelineContext::SetCallBackNode(node);
180 auto newJSVal = JSRef<JSVal>::Make(ToJSValue(isShow));
181 func->ExecuteJS(1, &newJSVal);
182 };
183 SideBarContainerModel::GetInstance()->SetOnChange(std::move(onChange));
184 info.ReturnSelf();
185 }
186
JsSideBarWidth(const JSCallbackInfo & info)187 void JSSideBar::JsSideBarWidth(const JSCallbackInfo& info)
188 {
189 ParseAndSetWidth(info, WidthType::SIDEBAR_WIDTH);
190 }
191
JsMaxSideBarWidth(const JSCallbackInfo & info)192 void JSSideBar::JsMaxSideBarWidth(const JSCallbackInfo& info)
193 {
194 ParseAndSetWidth(info, WidthType::MAX_SIDEBAR_WIDTH);
195 }
196
JsMinSideBarWidth(const JSCallbackInfo & info)197 void JSSideBar::JsMinSideBarWidth(const JSCallbackInfo& info)
198 {
199 ParseAndSetWidth(info, WidthType::MIN_SIDEBAR_WIDTH);
200 }
201
ParseShowSideBarObject(const JSCallbackInfo & args,const JSRef<JSVal> & changeEventVal)202 void ParseShowSideBarObject(const JSCallbackInfo& args, const JSRef<JSVal>& changeEventVal)
203 {
204 CHECK_NULL_VOID(changeEventVal->IsFunction());
205
206 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(changeEventVal));
207 WeakPtr<NG::FrameNode> targetNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
208 auto onChangeEvent = [execCtx = args.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
209 bool isShow) {
210 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
211 ACE_SCORING_EVENT("SideBarContainer.onChangeEvent");
212 PipelineContext::SetCallBackNode(node);
213 auto newJSVal = JSRef<JSVal>::Make(ToJSValue(isShow));
214 func->ExecuteJS(1, &newJSVal);
215 };
216 SideBarContainerModel::GetInstance()->SetOnChangeEvent(std::move(onChangeEvent));
217 }
218
JsShowSideBar(const JSCallbackInfo & info)219 void JSSideBar::JsShowSideBar(const JSCallbackInfo& info)
220 {
221 if (info.Length() < 1 || info.Length() > 2) {
222 return;
223 }
224
225 bool isShow = true;
226 if (info.Length() > 0 && info[0]->IsBoolean()) {
227 isShow = info[0]->ToBoolean();
228 }
229
230 SideBarContainerModel::GetInstance()->SetShowSideBar(isShow);
231 if (info.Length() > 1 && info[1]->IsFunction()) {
232 ParseShowSideBarObject(info, info[1]);
233 }
234 }
235
SetControlButtonIcon(SideBarControlButtonType iconType,JSRef<JSVal> icon)236 void JSSideBar::SetControlButtonIcon(SideBarControlButtonType iconType, JSRef<JSVal> icon)
237 {
238 if (icon->IsUndefined() || icon->IsNull()) {
239 return;
240 }
241 std::string iconPath;
242 auto isStrType = ParseJsMedia(icon, iconPath);
243 RefPtr<PixelMap> pixMap = nullptr;
244 #if defined(PIXEL_MAP_SUPPORTED)
245 if (!isStrType) {
246 pixMap = CreatePixelMapFromNapiValue(icon);
247 }
248 #endif
249 if (isStrType || pixMap != nullptr) {
250 switch (iconType) {
251 case SideBarControlButtonType::SHOWN:
252 SideBarContainerModel::GetInstance()->SetControlButtonShowIconInfo(iconPath, !isStrType, pixMap);
253 break;
254 case SideBarControlButtonType::HIDDEN:
255 SideBarContainerModel::GetInstance()->SetControlButtonHiddenIconInfo(iconPath, !isStrType, pixMap);
256 break;
257 case SideBarControlButtonType::SWITCHING:
258 SideBarContainerModel::GetInstance()->SetControlButtonSwitchingIconInfo(iconPath, !isStrType, pixMap);
259 break;
260 default:
261 break;
262 }
263 }
264 }
265
JsControlButton(const JSCallbackInfo & info)266 void JSSideBar::JsControlButton(const JSCallbackInfo& info)
267 {
268 if (info.Length() < 1) {
269 return;
270 }
271
272 if (!info[0]->IsNull() && info[0]->IsObject()) {
273 JSRef<JSObject> value = JSRef<JSObject>::Cast(info[0]);
274 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TEN)) {
275 ParseControlButtonOG(value);
276 } else {
277 ParseControlButtonNG(value);
278 }
279
280 JSRef<JSVal> icons = value->GetProperty("icons");
281 if (!icons->IsNull() && icons->IsObject()) {
282 JSRef<JSObject> iconsVal = JSRef<JSObject>::Cast(icons);
283 JSRef<JSVal> showIcon = iconsVal->GetProperty("shown");
284 JSRef<JSVal> switchingIcon = iconsVal->GetProperty("switching");
285 JSRef<JSVal> hiddenIcon = iconsVal->GetProperty("hidden");
286 SetControlButtonIcon(SideBarControlButtonType::SHOWN, showIcon);
287 SetControlButtonIcon(SideBarControlButtonType::HIDDEN, hiddenIcon);
288 SetControlButtonIcon(SideBarControlButtonType::SWITCHING, switchingIcon);
289 }
290 }
291 }
292
JsDivider(const JSCallbackInfo & info)293 void JSSideBar::JsDivider(const JSCallbackInfo& info)
294 {
295 if (info.Length() < 1) {
296 return;
297 }
298
299 if (info[0]->IsNull()) {
300 SideBarContainerModel::GetInstance()->SetDividerStrokeWidth(0.0_vp);
301 return;
302 }
303
304 if (info[0]->IsObject()) {
305 JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
306
307 Dimension strokeWidth = DEFAULT_DIVIDER_STROKE_WIDTH;
308 if (!ConvertFromJSValueNG(obj->GetProperty("strokeWidth"), strokeWidth) || (strokeWidth.Value() < 0.0f)) {
309 strokeWidth = DEFAULT_DIVIDER_STROKE_WIDTH;
310 }
311 SideBarContainerModel::GetInstance()->SetDividerStrokeWidth(strokeWidth);
312
313 Color color = DEFAULT_DIVIDER_COLOR;
314 if (!ConvertFromJSValue(obj->GetProperty("color"), color)) {
315 color = DEFAULT_DIVIDER_COLOR;
316 }
317 SideBarContainerModel::GetInstance()->SetDividerColor(color);
318
319 Dimension startMargin = DEFAULT_DIVIDER_START_MARGIN;
320 if (!ConvertFromJSValueNG(obj->GetProperty("startMargin"), startMargin) || (startMargin.Value() < 0.0f)) {
321 startMargin = DEFAULT_DIVIDER_START_MARGIN;
322 }
323 SideBarContainerModel::GetInstance()->SetDividerStartMargin(startMargin);
324
325 Dimension endMargin = DEFAULT_DIVIDER_END_MARGIN;
326 if (!ConvertFromJSValueNG(obj->GetProperty("endMargin"), endMargin) || (endMargin.Value() < 0.0f)) {
327 endMargin = DEFAULT_DIVIDER_END_MARGIN;
328 }
329 SideBarContainerModel::GetInstance()->SetDividerEndMargin(endMargin);
330 }
331 }
332
JsMinContentWidth(const JSCallbackInfo & info)333 void JSSideBar::JsMinContentWidth(const JSCallbackInfo& info)
334 {
335 if (info.Length() < 1) {
336 return;
337 }
338 if (info[0]->IsNull()) {
339 SideBarContainerModel::GetInstance()->SetMinContentWidth(-1.0_vp);
340 return;
341 }
342 CalcDimension minContentWidth;
343 if (!JSViewAbstract::ParseJsDimensionVp(info[0], minContentWidth)) {
344 SideBarContainerModel::GetInstance()->SetMinContentWidth(-1.0_vp);
345 return;
346 }
347 SideBarContainerModel::GetInstance()->SetMinContentWidth(minContentWidth);
348 }
349
JsAutoHide(bool autoHide)350 void JSSideBar::JsAutoHide(bool autoHide)
351 {
352 SideBarContainerModel::GetInstance()->SetAutoHide(autoHide);
353 }
354
ParseControlButtonOG(JSRef<JSObject> value)355 void JSSideBar::ParseControlButtonOG(JSRef<JSObject> value)
356 {
357 JSRef<JSVal> width = value->GetProperty("width");
358 JSRef<JSVal> height = value->GetProperty("height");
359 JSRef<JSVal> left = value->GetProperty("left");
360 JSRef<JSVal> top = value->GetProperty("top");
361
362 if (!width->IsNull() && width->IsNumber()) {
363 auto controlButtonWidth = CalcDimension(width->ToNumber<double>(), DimensionUnit::VP);
364 if (LessNotEqual(controlButtonWidth.Value(), 0.0)) {
365 controlButtonWidth = DEFAULT_CONTROL_BUTTON_WIDTH;
366 }
367 SideBarContainerModel::GetInstance()->SetControlButtonWidth(controlButtonWidth);
368 }
369
370 if (!height->IsNull() && height->IsNumber()) {
371 auto controlButtonHeight = CalcDimension(height->ToNumber<double>(), DimensionUnit::VP);
372 if (LessNotEqual(controlButtonHeight.Value(), 0.0)) {
373 controlButtonHeight = DEFAULT_CONTROL_BUTTON_HEIGHT;
374 }
375 SideBarContainerModel::GetInstance()->SetControlButtonHeight(controlButtonHeight);
376 }
377
378 if (!left->IsNull() && left->IsNumber()) {
379 SideBarContainerModel::GetInstance()->SetControlButtonLeft(
380 Dimension(left->ToNumber<double>(), DimensionUnit::VP));
381 }
382
383 if (!top->IsNull() && top->IsNumber()) {
384 SideBarContainerModel::GetInstance()->SetControlButtonTop(
385 Dimension(top->ToNumber<double>(), DimensionUnit::VP));
386 }
387 }
388
ParseControlButtonNG(JSRef<JSObject> value)389 void JSSideBar::ParseControlButtonNG(JSRef<JSObject> value)
390 {
391 JSRef<JSVal> width = value->GetProperty("width");
392 JSRef<JSVal> height = value->GetProperty("height");
393 JSRef<JSVal> left = value->GetProperty("left");
394 JSRef<JSVal> top = value->GetProperty("top");
395
396 auto controlButtonWidth = DEFAULT_CONTROL_BUTTON_WIDTH;
397 if (width->IsNumber() && GreatOrEqual(width->ToNumber<double>(), 0.0)) {
398 controlButtonWidth = CalcDimension(width->ToNumber<double>(), DimensionUnit::VP);
399 }
400 SideBarContainerModel::GetInstance()->SetControlButtonWidth(controlButtonWidth);
401
402 auto controlButtonHeight = DEFAULT_CONTROL_BUTTON_HEIGHT;
403 if (height->IsNumber() && GreatOrEqual(height->ToNumber<double>(), 0.0)) {
404 controlButtonHeight = CalcDimension(height->ToNumber<double>(), DimensionUnit::VP);
405 }
406 SideBarContainerModel::GetInstance()->SetControlButtonHeight(controlButtonHeight);
407
408 if (left->IsNumber() && GreatOrEqual(left->ToNumber<double>(), 0.0)) {
409 auto controlButtonLeft = CalcDimension(left->ToNumber<double>(), DimensionUnit::VP);
410 SideBarContainerModel::GetInstance()->SetControlButtonLeft(controlButtonLeft);
411 } else {
412 SideBarContainerModel::GetInstance()->ResetControlButtonLeft();
413 }
414
415 auto controlButtonTop = DEFAULT_CONTROL_BUTTON_TOP;
416 if (top->IsNumber() && GreatOrEqual(top->ToNumber<double>(), 0.0)) {
417 controlButtonTop = CalcDimension(top->ToNumber<double>(), DimensionUnit::VP);
418 }
419 SideBarContainerModel::GetInstance()->SetControlButtonTop(controlButtonTop);
420 }
421
422 } // namespace OHOS::Ace::Framework
423