• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 constexpr int32_t PLATFORM_VERSION_TEN = 10;
67 
ParseAndSetWidth(const JSCallbackInfo & info,WidthType widthType)68 void ParseAndSetWidth(const JSCallbackInfo& info, WidthType widthType)
69 {
70     if (info.Length() < 1) {
71         LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
72         return;
73     }
74 
75     CalcDimension value;
76     auto pipeline = PipelineBase::GetCurrentContext();
77     CHECK_NULL_VOID(pipeline);
78     if (pipeline->GetMinPlatformVersion() >= PLATFORM_VERSION_TEN) {
79         DEFAULT_SIDE_BAR_WIDTH = 240.0_vp;
80         DEFAULT_MIN_SIDE_BAR_WIDTH = 240.0_vp;
81     }
82 
83     auto isValid = pipeline->GetMinPlatformVersion() >= PLATFORM_VERSION_TEN
84                        ? JSViewAbstract::ParseJsDimensionVpNG(info[0], value)
85                        : JSViewAbstract::ParseJsDimensionVp(info[0], value);
86 
87     if (!isValid) {
88         switch (widthType) {
89             case WidthType::SIDEBAR_WIDTH:
90                 value = DEFAULT_SIDE_BAR_WIDTH;
91                 break;
92             case WidthType::MIN_SIDEBAR_WIDTH:
93                 value = DEFAULT_MIN_SIDE_BAR_WIDTH;
94                 break;
95             case WidthType::MAX_SIDEBAR_WIDTH:
96                 value = DEFAULT_MAX_SIDE_BAR_WIDTH;
97                 break;
98             default:
99                 break;
100         }
101     }
102     SideBarContainerModel::GetInstance()->ParseAndSetWidth(widthType, value);
103 }
104 } // namespace
105 
Create(const JSCallbackInfo & info)106 void JSSideBar::Create(const JSCallbackInfo& info)
107 {
108     SideBarContainerModel::GetInstance()->Create();
109     SideBarContainerType style = SideBarContainerType::EMBED;
110     if (!info[0]->IsNull()) {
111         if (info[0]->IsBoolean()) {
112             style = static_cast<SideBarContainerType>(info[0]->ToBoolean());
113         } else if (info[0]->IsNumber()) {
114             style = static_cast<SideBarContainerType>(info[0]->ToNumber<int>());
115         } else {
116             LOGE("JSSideBar::CreateForNG The SideBarContainerType arg is wrong");
117             return;
118         }
119     }
120     SideBarContainerModel::GetInstance()->SetSideBarContainerType(style);
121 }
122 
SetShowControlButton(bool isShow)123 void JSSideBar::SetShowControlButton(bool isShow)
124 {
125     SideBarContainerModel::GetInstance()->SetShowControlButton(isShow);
126 }
127 
JsSideBarPosition(const JSCallbackInfo & info)128 void JSSideBar::JsSideBarPosition(const JSCallbackInfo& info)
129 {
130     if (info.Length() < 1) {
131         LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
132         return;
133     }
134     SideBarPosition sideBarPosition = SideBarPosition::START;
135     if (info[0]->IsNumber()) {
136         sideBarPosition = static_cast<SideBarPosition>(info[0]->ToNumber<int>());
137     } else {
138         LOGE("The arg is wrong");
139         return;
140     }
141     SideBarContainerModel::GetInstance()->SetSideBarPosition(sideBarPosition);
142 }
143 
JSBind(BindingTarget globalObj)144 void JSSideBar::JSBind(BindingTarget globalObj)
145 {
146     JSClass<JSSideBar>::Declare("SideBarContainer");
147     MethodOptions opt = MethodOptions::NONE;
148     JSClass<JSSideBar>::StaticMethod("create", &JSSideBar::Create, opt);
149     JSClass<JSSideBar>::StaticMethod("pop", &JSSideBar::Pop);
150     JSClass<JSSideBar>::StaticMethod("showSideBar", &JSSideBar::JsShowSideBar);
151     JSClass<JSSideBar>::StaticMethod("controlButton", &JSSideBar::JsControlButton);
152     JSClass<JSSideBar>::StaticMethod("showControlButton", &JSSideBar::SetShowControlButton);
153     JSClass<JSSideBar>::StaticMethod("onChange", &JSSideBar::OnChange);
154     JSClass<JSSideBar>::StaticMethod("sideBarWidth", &JSSideBar::JsSideBarWidth);
155     JSClass<JSSideBar>::StaticMethod("minSideBarWidth", &JSSideBar::JsMinSideBarWidth);
156     JSClass<JSSideBar>::StaticMethod("maxSideBarWidth", &JSSideBar::JsMaxSideBarWidth);
157     JSClass<JSSideBar>::StaticMethod("autoHide", &JSSideBar::JsAutoHide);
158     JSClass<JSSideBar>::StaticMethod("sideBarPosition", &JSSideBar::JsSideBarPosition);
159     JSClass<JSSideBar>::StaticMethod("divider", &JSSideBar::JsDivider);
160     JSClass<JSSideBar>::StaticMethod("minContentWidth", &JSSideBar::JsMinContentWidth);
161     JSClass<JSSideBar>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
162     JSClass<JSSideBar>::StaticMethod("width", SetWidth);
163     JSClass<JSSideBar>::StaticMethod("height", SetHeight);
164     JSClass<JSSideBar>::StaticMethod("size", SetSize);
165     JSClass<JSSideBar>::StaticMethod("width", &JSStack::SetWidth);
166     JSClass<JSSideBar>::StaticMethod("height", &JSStack::SetHeight);
167     JSClass<JSSideBar>::StaticMethod("size", &JSStack::SetSize);
168     JSClass<JSSideBar>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
169     JSClass<JSSideBar>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
170     JSClass<JSSideBar>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
171     JSClass<JSSideBar>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
172     JSClass<JSSideBar>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
173     JSClass<JSSideBar>::InheritAndBind<JSContainerBase>(globalObj);
174 }
175 
OnChange(const JSCallbackInfo & info)176 void JSSideBar::OnChange(const JSCallbackInfo& info)
177 {
178     if (info.Length() < 1 || !info[0]->IsFunction()) {
179         LOGE("JSSideBar::OnChange info param is wrong.");
180         return;
181     }
182 
183     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
184     auto onChange = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](bool isShow) {
185         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
186         ACE_SCORING_EVENT("SideBarContainer.onChange");
187         auto newJSVal = JSRef<JSVal>::Make(ToJSValue(isShow));
188         func->ExecuteJS(1, &newJSVal);
189     };
190     SideBarContainerModel::GetInstance()->SetOnChange(std::move(onChange));
191     info.ReturnSelf();
192 }
193 
JsSideBarWidth(const JSCallbackInfo & info)194 void JSSideBar::JsSideBarWidth(const JSCallbackInfo& info)
195 {
196     ParseAndSetWidth(info, WidthType::SIDEBAR_WIDTH);
197 }
198 
JsMaxSideBarWidth(const JSCallbackInfo & info)199 void JSSideBar::JsMaxSideBarWidth(const JSCallbackInfo& info)
200 {
201     ParseAndSetWidth(info, WidthType::MAX_SIDEBAR_WIDTH);
202 }
203 
JsMinSideBarWidth(const JSCallbackInfo & info)204 void JSSideBar::JsMinSideBarWidth(const JSCallbackInfo& info)
205 {
206     ParseAndSetWidth(info, WidthType::MIN_SIDEBAR_WIDTH);
207 }
208 
ParseShowSideBarObject(const JSCallbackInfo & args,const JSRef<JSVal> & changeEventVal)209 void ParseShowSideBarObject(const JSCallbackInfo& args, const JSRef<JSVal>& changeEventVal)
210 {
211     CHECK_NULL_VOID(changeEventVal->IsFunction());
212 
213     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(changeEventVal));
214     auto onChangeEvent = [execCtx = args.GetExecutionContext(), func = std::move(jsFunc)](bool isShow) {
215         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
216         ACE_SCORING_EVENT("SideBarContainer.onChangeEvent");
217         auto newJSVal = JSRef<JSVal>::Make(ToJSValue(isShow));
218         func->ExecuteJS(1, &newJSVal);
219     };
220     SideBarContainerModel::GetInstance()->SetOnChangeEvent(std::move(onChangeEvent));
221 }
222 
JsShowSideBar(const JSCallbackInfo & info)223 void JSSideBar::JsShowSideBar(const JSCallbackInfo& info)
224 {
225     if (info.Length() < 1 || info.Length() > 2) {
226         LOGE("The arg is wrong, it is supposed to have 1 or 2 arguments");
227         return;
228     }
229 
230     bool isShow = true;
231     if (info.Length() > 0 && info[0]->IsBoolean()) {
232         isShow = info[0]->ToBoolean();
233     }
234 
235     SideBarContainerModel::GetInstance()->SetShowSideBar(isShow);
236     if (info.Length() > 1 && info[1]->IsFunction()) {
237         ParseShowSideBarObject(info, info[1]);
238     }
239 }
240 
SetControlButtonIcon(SideBarControlButtonType iconType,JSRef<JSVal> icon)241 void JSSideBar::SetControlButtonIcon(SideBarControlButtonType iconType, JSRef<JSVal> icon)
242 {
243     if (icon->IsUndefined() || icon->IsNull()) {
244         LOGE("SetControlButtonIcon icon parse failed, icon is null.");
245         return;
246     }
247     std::string iconPath;
248     auto isStrType = ParseJsMedia(icon, iconPath);
249     RefPtr<PixelMap> pixMap = nullptr;
250 #if defined(PIXEL_MAP_SUPPORTED)
251     if (!isStrType) {
252         pixMap = CreatePixelMapFromNapiValue(icon);
253     }
254 #endif
255     if (isStrType || pixMap != nullptr) {
256         switch (iconType) {
257             case SideBarControlButtonType::SHOWN:
258                 SideBarContainerModel::GetInstance()->SetControlButtonShowIconInfo(iconPath, !isStrType, pixMap);
259                 break;
260             case SideBarControlButtonType::HIDDEN:
261                 SideBarContainerModel::GetInstance()->SetControlButtonHiddenIconInfo(iconPath, !isStrType, pixMap);
262                 break;
263             case SideBarControlButtonType::SWITCHING:
264                 SideBarContainerModel::GetInstance()->SetControlButtonSwitchingIconInfo(iconPath, !isStrType, pixMap);
265                 break;
266             default:
267                 break;
268         }
269     }
270 }
271 
JsControlButton(const JSCallbackInfo & info)272 void JSSideBar::JsControlButton(const JSCallbackInfo& info)
273 {
274     if (info.Length() < 1) {
275         LOGE("JSSideBar::JsControlButtonForNG The arg is wrong, it is supposed to have at least 1 arguments");
276         return;
277     }
278 
279     if (!info[0]->IsNull() && info[0]->IsObject()) {
280         JSRef<JSObject> value = JSRef<JSObject>::Cast(info[0]);
281         auto pipeline = PipelineBase::GetCurrentContext();
282         CHECK_NULL_VOID(pipeline);
283         if (pipeline->GetMinPlatformVersion() < PLATFORM_VERSION_TEN) {
284             ParseControlButtonOG(value);
285         } else {
286             ParseControlButtonNG(value);
287         }
288 
289         JSRef<JSVal> icons = value->GetProperty("icons");
290         if (!icons->IsNull() && icons->IsObject()) {
291             JSRef<JSObject> iconsVal = JSRef<JSObject>::Cast(icons);
292             JSRef<JSVal> showIcon = iconsVal->GetProperty("shown");
293             JSRef<JSVal> switchingIcon = iconsVal->GetProperty("switching");
294             JSRef<JSVal> hiddenIcon = iconsVal->GetProperty("hidden");
295             SetControlButtonIcon(SideBarControlButtonType::SHOWN, showIcon);
296             SetControlButtonIcon(SideBarControlButtonType::HIDDEN, hiddenIcon);
297             SetControlButtonIcon(SideBarControlButtonType::SWITCHING, switchingIcon);
298         }
299     }
300 }
301 
JsDivider(const JSCallbackInfo & info)302 void JSSideBar::JsDivider(const JSCallbackInfo& info)
303 {
304     if (info.Length() < 1) {
305         LOGE("Invalid params");
306         return;
307     }
308 
309     if (info[0]->IsNull()) {
310         SideBarContainerModel::GetInstance()->SetDividerStrokeWidth(0.0_vp);
311         return;
312     }
313 
314     if (info[0]->IsObject()) {
315         JSRef<JSObject> obj = JSRef<JSObject>::Cast(info[0]);
316 
317         Dimension strokeWidth = DEFAULT_DIVIDER_STROKE_WIDTH;
318         if (!ConvertFromJSValueNG(obj->GetProperty("strokeWidth"), strokeWidth) || (strokeWidth.Value() < 0.0f)) {
319             strokeWidth = DEFAULT_DIVIDER_STROKE_WIDTH;
320         }
321         SideBarContainerModel::GetInstance()->SetDividerStrokeWidth(strokeWidth);
322 
323         Color color = DEFAULT_DIVIDER_COLOR;
324         if (!ConvertFromJSValue(obj->GetProperty("color"), color)) {
325             color = DEFAULT_DIVIDER_COLOR;
326         }
327         SideBarContainerModel::GetInstance()->SetDividerColor(color);
328 
329         Dimension startMargin = DEFAULT_DIVIDER_START_MARGIN;
330         if (!ConvertFromJSValueNG(obj->GetProperty("startMargin"), startMargin) || (startMargin.Value() < 0.0f)) {
331             startMargin = DEFAULT_DIVIDER_START_MARGIN;
332         }
333         SideBarContainerModel::GetInstance()->SetDividerStartMargin(startMargin);
334 
335         Dimension endMargin = DEFAULT_DIVIDER_END_MARGIN;
336         if (!ConvertFromJSValueNG(obj->GetProperty("endMargin"), endMargin) || (endMargin.Value() < 0.0f)) {
337             endMargin = DEFAULT_DIVIDER_END_MARGIN;
338         }
339         SideBarContainerModel::GetInstance()->SetDividerEndMargin(endMargin);
340     }
341 }
342 
JsMinContentWidth(const JSCallbackInfo & info)343 void JSSideBar::JsMinContentWidth(const JSCallbackInfo& info)
344 {
345     if (info.Length() < 1) {
346         LOGW("JsMinContentWidth::Invalid params");
347         return;
348     }
349     if (info[0]->IsNull()) {
350         SideBarContainerModel::GetInstance()->SetMinContentWidth(-1.0_vp);
351         LOGW("JsMinContentWidth::info[0]->IsNull()");
352         return;
353     }
354     CalcDimension minContentWidth;
355     if (!JSViewAbstract::ParseJsDimensionVp(info[0], minContentWidth)) {
356         SideBarContainerModel::GetInstance()->SetMinContentWidth(-1.0_vp);
357         LOGW("JsMinContentWidth::ParseJsDimensionVp Fail!!!");
358         return;
359     }
360     SideBarContainerModel::GetInstance()->SetMinContentWidth(minContentWidth);
361 }
362 
JsAutoHide(bool autoHide)363 void JSSideBar::JsAutoHide(bool autoHide)
364 {
365     SideBarContainerModel::GetInstance()->SetAutoHide(autoHide);
366 }
367 
Pop()368 void JSSideBar::Pop()
369 {
370     SideBarContainerModel::GetInstance()->Pop();
371 }
372 
373 
ParseControlButtonOG(JSRef<JSObject> value)374 void JSSideBar::ParseControlButtonOG(JSRef<JSObject> value)
375 {
376     JSRef<JSVal> width = value->GetProperty("width");
377     JSRef<JSVal> height = value->GetProperty("height");
378     JSRef<JSVal> left = value->GetProperty("left");
379     JSRef<JSVal> top = value->GetProperty("top");
380 
381     if (!width->IsNull() && width->IsNumber()) {
382         auto controlButtonWidth = CalcDimension(width->ToNumber<double>(), DimensionUnit::VP);
383         if (LessNotEqual(controlButtonWidth.Value(), 0.0)) {
384             controlButtonWidth = DEFAULT_CONTROL_BUTTON_WIDTH;
385         }
386         SideBarContainerModel::GetInstance()->SetControlButtonWidth(controlButtonWidth);
387     }
388 
389     if (!height->IsNull() && height->IsNumber()) {
390         auto controlButtonHeight = CalcDimension(height->ToNumber<double>(), DimensionUnit::VP);
391         if (LessNotEqual(controlButtonHeight.Value(), 0.0)) {
392             controlButtonHeight = DEFAULT_CONTROL_BUTTON_HEIGHT;
393         }
394         SideBarContainerModel::GetInstance()->SetControlButtonHeight(controlButtonHeight);
395     }
396 
397     if (!left->IsNull() && left->IsNumber()) {
398         SideBarContainerModel::GetInstance()->SetControlButtonLeft(
399             Dimension(left->ToNumber<double>(), DimensionUnit::VP));
400     }
401 
402     if (!top->IsNull() && top->IsNumber()) {
403         SideBarContainerModel::GetInstance()->SetControlButtonTop(
404             Dimension(top->ToNumber<double>(), DimensionUnit::VP));
405     }
406 }
407 
ParseControlButtonNG(JSRef<JSObject> value)408 void JSSideBar::ParseControlButtonNG(JSRef<JSObject> value)
409 {
410     JSRef<JSVal> width = value->GetProperty("width");
411     JSRef<JSVal> height = value->GetProperty("height");
412     JSRef<JSVal> left = value->GetProperty("left");
413     JSRef<JSVal> top = value->GetProperty("top");
414 
415     auto controlButtonWidth = DEFAULT_CONTROL_BUTTON_WIDTH;
416     if (width->IsNumber() && GreatOrEqual(width->ToNumber<double>(), 0.0)) {
417         controlButtonWidth = CalcDimension(width->ToNumber<double>(), DimensionUnit::VP);
418     }
419     SideBarContainerModel::GetInstance()->SetControlButtonWidth(controlButtonWidth);
420 
421     auto controlButtonHeight = DEFAULT_CONTROL_BUTTON_HEIGHT;
422     if (height->IsNumber() && GreatOrEqual(height->ToNumber<double>(), 0.0)) {
423         controlButtonHeight = CalcDimension(height->ToNumber<double>(), DimensionUnit::VP);
424     }
425     SideBarContainerModel::GetInstance()->SetControlButtonHeight(controlButtonHeight);
426 
427     if (left->IsNumber() && GreatOrEqual(left->ToNumber<double>(), 0.0)) {
428         auto controlButtonLeft = CalcDimension(left->ToNumber<double>(), DimensionUnit::VP);
429         SideBarContainerModel::GetInstance()->SetControlButtonLeft(controlButtonLeft);
430     } else {
431         SideBarContainerModel::GetInstance()->ResetControlButtonLeft();
432     }
433 
434     auto controlButtonTop = DEFAULT_CONTROL_BUTTON_TOP;
435     if (top->IsNumber() && GreatOrEqual(top->ToNumber<double>(), 0.0)) {
436         controlButtonTop = CalcDimension(top->ToNumber<double>(), DimensionUnit::VP);
437     }
438     SideBarContainerModel::GetInstance()->SetControlButtonTop(controlButtonTop);
439 }
440 
441 } // namespace OHOS::Ace::Framework
442