• 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 
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