1 /*
2 * Copyright (c) 2021-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_sliding_panel.h"
17
18 #include <algorithm>
19 #include <cstdint>
20 #include <iterator>
21
22 #include "base/log/ace_scoring_log.h"
23 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
24 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
25 #include "bridge/declarative_frontend/jsview/models/sliding_panel_model_impl.h"
26 #include "core/components_ng/base/view_abstract_model_ng.h"
27 #include "core/components_ng/pattern/panel/sliding_panel_model.h"
28 #include "core/components_ng/pattern/panel/sliding_panel_model_ng.h"
29
30 namespace OHOS::Ace {
31
32 std::unique_ptr<SlidingPanelModel> SlidingPanelModel::instance_ = nullptr;
33 std::mutex SlidingPanelModel::mutex_;
34
GetInstance()35 SlidingPanelModel* SlidingPanelModel::GetInstance()
36 {
37 if (!instance_) {
38 std::lock_guard<std::mutex> lock(mutex_);
39 if (!instance_) {
40 #ifdef NG_BUILD
41 instance_.reset(new NG::SlidingPanelModelNG());
42 #else
43 if (Container::IsCurrentUseNewPipeline()) {
44 instance_.reset(new NG::SlidingPanelModelNG());
45 } else {
46 instance_.reset(new Framework::SlidingPanelModelImpl());
47 }
48 #endif
49 }
50 }
51 return instance_.get();
52 }
53
54 } // namespace OHOS::Ace
55 namespace OHOS::Ace::Framework {
56 namespace {
57
58 const std::vector<PanelMode> PANEL_MODES = { PanelMode::MINI, PanelMode::HALF, PanelMode::FULL, PanelMode::AUTO };
59 const std::vector<PanelType> PANEL_TYPES = { PanelType::MINI_BAR, PanelType::FOLDABLE_BAR, PanelType::TEMP_DISPLAY,
60 PanelType::CUSTOM };
61 const std::vector<VisibleType> PANEL_VISIBLE_TYPES = { VisibleType::GONE, VisibleType::VISIBLE,
62 VisibleType::INVISIBLE };
63
64 const static bool DEFAULT_HASDRAGBAR = true;
65 const static bool DEFAULT_SHOWCLOSEICON = false;
66 const static PanelMode DEFAULT_PANELMODE = PanelMode::HALF;
67 const static PanelType DEFAULT_PANELTYPE = PanelType::FOLDABLE_BAR;
68 const std::string DEFAULT_BACKGROUND_MASK = "#08182431";
69 } // namespace
70
Create(const JSCallbackInfo & info)71 void JSSlidingPanel::Create(const JSCallbackInfo& info)
72 {
73 if (info.Length() > 0 && info[0]->IsBoolean()) {
74 bool isShow = true;
75 isShow = info[0]->ToBoolean();
76 SlidingPanelModel::GetInstance()->Create(isShow);
77 return;
78 }
79 }
80
JSBind(BindingTarget globalObj)81 void JSSlidingPanel::JSBind(BindingTarget globalObj)
82 {
83 JSClass<JSSlidingPanel>::Declare("Panel");
84 MethodOptions opt = MethodOptions::NONE;
85 JSClass<JSSlidingPanel>::StaticMethod("create", &JSSlidingPanel::Create, opt);
86 JSClass<JSSlidingPanel>::StaticMethod("pop", &JSSlidingPanel::Pop, opt);
87 JSClass<JSSlidingPanel>::StaticMethod("dragBar", &JSSlidingPanel::SetHasDragBar, opt);
88 JSClass<JSSlidingPanel>::StaticMethod("show", &JSSlidingPanel::SetShow, opt);
89 JSClass<JSSlidingPanel>::StaticMethod("showCloseIcon", &JSSlidingPanel::SetShowCloseIcon, opt);
90 JSClass<JSSlidingPanel>::StaticMethod("mode", &JSSlidingPanel::SetPanelMode, opt);
91 JSClass<JSSlidingPanel>::StaticMethod("type", &JSSlidingPanel::SetPanelType, opt);
92 JSClass<JSSlidingPanel>::StaticMethod("customHeight", &JSSlidingPanel::SetCustomHeight, opt);
93 JSClass<JSSlidingPanel>::StaticMethod("backgroundMask", &JSSlidingPanel::SetBackgroundMask, opt);
94 JSClass<JSSlidingPanel>::StaticMethod("fullHeight", &JSSlidingPanel::SetFullHeight, opt);
95 JSClass<JSSlidingPanel>::StaticMethod("halfHeight", &JSSlidingPanel::SetHalfHeight, opt);
96 JSClass<JSSlidingPanel>::StaticMethod("miniHeight", &JSSlidingPanel::SetMiniHeight, opt);
97 JSClass<JSSlidingPanel>::StaticMethod("backgroundColor", JsBackgroundColor);
98 JSClass<JSSlidingPanel>::StaticMethod("border", JsPanelBorder);
99 JSClass<JSSlidingPanel>::StaticMethod("borderWidth", JsPanelBorderWidth);
100 JSClass<JSSlidingPanel>::StaticMethod("borderColor", JsPanelBorderColor);
101 JSClass<JSSlidingPanel>::StaticMethod("borderStyle", JsPanelBorderStyle);
102 JSClass<JSSlidingPanel>::StaticMethod("borderRadius", JsPanelBorderRadius);
103
104 JSClass<JSSlidingPanel>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
105 JSClass<JSSlidingPanel>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
106 JSClass<JSSlidingPanel>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
107 JSClass<JSSlidingPanel>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
108 JSClass<JSSlidingPanel>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
109 JSClass<JSSlidingPanel>::StaticMethod("onChange", &JSSlidingPanel::SetOnSizeChange);
110 JSClass<JSSlidingPanel>::StaticMethod("onHeightChange", &JSSlidingPanel::SetOnHeightChange);
111 JSClass<JSSlidingPanel>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
112 JSClass<JSSlidingPanel>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
113
114 JSClass<JSSlidingPanel>::InheritAndBind<JSContainerBase>(globalObj);
115 }
116
SetBackgroundMask(const JSCallbackInfo & info)117 void JSSlidingPanel::SetBackgroundMask(const JSCallbackInfo& info)
118 {
119 Color color;
120 if (info.Length() < 1) {
121 color = Color::FromString(DEFAULT_BACKGROUND_MASK);
122 } else if (!ParseJsColor(info[0], color)) {
123 color = Color::FromString(DEFAULT_BACKGROUND_MASK);
124 }
125
126 SlidingPanelModel::GetInstance()->SetBackgroundMask(color);
127 }
128
ParsePanelRadius(const JSRef<JSVal> & args,BorderRadius & borderRadius)129 void JSSlidingPanel::ParsePanelRadius(const JSRef<JSVal>& args, BorderRadius& borderRadius)
130 {
131 if (!args->IsObject() && !args->IsNumber() && !args->IsString()) {
132 return;
133 }
134
135 CalcDimension radius;
136 if (ParseJsDimensionVp(args, radius)) {
137 borderRadius.radiusTopLeft = radius;
138 borderRadius.radiusTopRight = radius;
139 borderRadius.radiusBottomLeft = radius;
140 borderRadius.radiusBottomRight = radius;
141 return;
142 }
143 if (args->IsObject()) {
144 JSRef<JSObject> object = JSRef<JSObject>::Cast(args);
145 auto valueTopLeft = object->GetProperty("topLeft");
146 if (!valueTopLeft->IsUndefined()) {
147 ParseJsDimensionVp(valueTopLeft, borderRadius.radiusTopLeft);
148 }
149 auto valueTopRight = object->GetProperty("topRight");
150 if (!valueTopRight->IsUndefined()) {
151 ParseJsDimensionVp(valueTopRight, borderRadius.radiusTopRight);
152 }
153 auto valueBottomLeft = object->GetProperty("bottomLeft");
154 if (!valueBottomLeft->IsUndefined()) {
155 ParseJsDimensionVp(valueBottomLeft, borderRadius.radiusBottomLeft);
156 }
157 auto valueBottomRight = object->GetProperty("bottomRight");
158 if (!valueBottomRight->IsUndefined()) {
159 ParseJsDimensionVp(valueBottomRight, borderRadius.radiusBottomRight);
160 }
161 return;
162 }
163 }
164
JsPanelBorderRadius(const JSCallbackInfo & info)165 void JSSlidingPanel::JsPanelBorderRadius(const JSCallbackInfo& info)
166 {
167 BorderRadius borderRadius;
168 ParsePanelRadius(info[0], borderRadius);
169
170 ViewAbstractModel::GetInstance()->SetBorderRadius(borderRadius.radiusTopLeft, borderRadius.radiusTopRight,
171 borderRadius.radiusBottomLeft, borderRadius.radiusBottomRight);
172 }
173
JsBackgroundColor(const JSCallbackInfo & info)174 void JSSlidingPanel::JsBackgroundColor(const JSCallbackInfo& info)
175 {
176 if (info.Length() < 1) {
177 return;
178 }
179 Color backgroundColor;
180 if (!ParseJsColor(info[0], backgroundColor)) {
181 return;
182 }
183
184 SlidingPanelModel::GetInstance()->SetBackgroundColor(backgroundColor);
185 }
186
JsPanelBorderColor(const JSCallbackInfo & info)187 void JSSlidingPanel::JsPanelBorderColor(const JSCallbackInfo& info)
188 {
189 if (info.Length() < 1) {
190 return;
191 }
192 Color borderColor;
193 if (!ParseJsColor(info[0], borderColor)) {
194 return;
195 }
196
197 SlidingPanelModel::GetInstance()->SetBorderColor(borderColor);
198 }
199
JsPanelBorderWidth(const JSCallbackInfo & info)200 void JSSlidingPanel::JsPanelBorderWidth(const JSCallbackInfo& info)
201 {
202 if (info.Length() < 1) {
203 return;
204 }
205 CalcDimension borderWidth;
206 if (!ParseJsDimensionVp(info[0], borderWidth)) {
207 return;
208 }
209 SlidingPanelModel::GetInstance()->SetBorderWidth(borderWidth);
210 }
211
JsPanelBorderStyle(int32_t style)212 void JSSlidingPanel::JsPanelBorderStyle(int32_t style)
213 {
214 BorderStyle borderStyle = BorderStyle::SOLID;
215 if (style > 0 && style < 4) {
216 borderStyle = static_cast<BorderStyle>(style);
217 }
218 SlidingPanelModel::GetInstance()->SetBorderStyle(borderStyle);
219 }
220
JsPanelBorder(const JSCallbackInfo & info)221 void JSSlidingPanel::JsPanelBorder(const JSCallbackInfo& info)
222 {
223 if (info.Length() < 1) {
224 return;
225 }
226 if (!info[0]->IsObject()) {
227 return;
228 }
229
230 auto argsPtrItem = JSRef<JSObject>::Cast(info[0]);
231 CalcDimension width = CalcDimension(0.0, DimensionUnit::VP);
232 ParseJsDimensionVp(argsPtrItem->GetProperty("width"), width);
233 SlidingPanelModel::GetInstance()->SetBorderWidth(width);
234
235 BorderRadius borderRadius;
236 ParsePanelRadius(argsPtrItem->GetProperty("radius"), borderRadius);
237 ViewAbstractModel::GetInstance()->SetBorderRadius(borderRadius.radiusTopLeft, borderRadius.radiusTopRight,
238 borderRadius.radiusBottomLeft, borderRadius.radiusBottomRight);
239
240 auto styleJsValue = argsPtrItem->GetProperty("style");
241 auto borderStyle = BorderStyle::SOLID;
242 if (!styleJsValue->IsUndefined() && styleJsValue->IsNumber()) {
243 auto styleValue = styleJsValue->ToNumber<uint32_t>();
244 if (styleValue > 0 && styleValue < 4) {
245 borderStyle = static_cast<BorderStyle>(styleValue);
246 }
247 }
248 SlidingPanelModel::GetInstance()->SetBorderStyle(borderStyle);
249
250 Color borderColor;
251 ParseJsColor(argsPtrItem->GetProperty("color"), borderColor);
252 SlidingPanelModel::GetInstance()->SetBorderColor(borderColor);
253 }
254
SetOnSizeChange(const JSCallbackInfo & args)255 void JSSlidingPanel::SetOnSizeChange(const JSCallbackInfo& args)
256 {
257 if (!args[0]->IsFunction()) {
258 return;
259 }
260
261 auto onSizeChangeNG = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
262 const BaseEventInfo* info) {
263 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
264 auto eventInfo = TypeInfoHelper::DynamicCast<SlidingPanelSizeChangeEvent>(info);
265 if (!eventInfo) {
266 return;
267 }
268 auto params = ConvertToJSValues(eventInfo->GetWidth(), eventInfo->GetHeight(), eventInfo->GetMode());
269 ACE_SCORING_EVENT("SlidingPanel.OnSizeChange");
270 func->Call(JSRef<JSObject>(), params.size(), params.data());
271 };
272 SlidingPanelModel::GetInstance()->SetOnSizeChange(onSizeChangeNG);
273
274 args.ReturnSelf();
275 }
276
SetOnHeightChange(const JSCallbackInfo & args)277 void JSSlidingPanel::SetOnHeightChange(const JSCallbackInfo& args)
278 {
279 if (args.Length() < 1) {
280 return;
281 }
282 if (!args[0]->IsFunction()) {
283 return;
284 }
285
286 auto onHeightChangeCallback = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(args[0]));
287 WeakPtr<NG::FrameNode> targetNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
288 auto onHeightChange = [execCtx = args.GetExecutionContext(), func = std::move(onHeightChangeCallback),
289 node = targetNode](int32_t height) {
290 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
291 ACE_SCORING_EVENT("OnHeightChange");
292 PipelineContext::SetCallBackNode(node);
293 JSRef<JSVal> param = JSRef<JSVal>::Make(ToJSValue(height));
294 func->ExecuteJS(1, ¶m);
295 };
296
297 SlidingPanelModel::GetInstance()->SetOnHeightChange(std::move(onHeightChange));
298
299 args.ReturnSelf();
300 }
301
SetHasDragBar(const JSCallbackInfo & info)302 void JSSlidingPanel::SetHasDragBar(const JSCallbackInfo& info)
303 {
304 if (info.Length() < 1) {
305 return;
306 }
307 auto hasDragBar = DEFAULT_HASDRAGBAR;
308 if (info[0]->IsBoolean()) {
309 hasDragBar = info[0]->ToBoolean();
310 }
311 SlidingPanelModel::GetInstance()->SetHasDragBar(hasDragBar);
312 }
313
SetShowCloseIcon(const JSCallbackInfo & info)314 void JSSlidingPanel::SetShowCloseIcon(const JSCallbackInfo& info)
315 {
316 if (info.Length() < 1) {
317 return;
318 }
319 auto showCloseIcon = DEFAULT_SHOWCLOSEICON;
320 if (info[0]->IsBoolean()) {
321 showCloseIcon = info[0]->ToBoolean();
322 }
323 SlidingPanelModel::GetInstance()->SetShowCloseIcon(showCloseIcon);
324 }
325
SetShow(const JSCallbackInfo & info)326 void JSSlidingPanel::SetShow(const JSCallbackInfo& info)
327 {
328 if (Container::GreatOrEqualAPIVersion(PlatformVersion::VERSION_TEN) &&
329 (info[0]->IsUndefined() || info[0]->IsNull())) {
330 SlidingPanelModel::GetInstance()->SetIsShow(true);
331 } else {
332 SlidingPanelModel::GetInstance()->SetIsShow(info[0]->ToBoolean());
333 }
334 }
335
ParseModeObject(const JSCallbackInfo & info,const JSRef<JSVal> & changeEventVal)336 void ParseModeObject(const JSCallbackInfo& info, const JSRef<JSVal>& changeEventVal)
337 {
338 CHECK_NULL_VOID(changeEventVal->IsFunction());
339
340 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(changeEventVal));
341 WeakPtr<NG::FrameNode> targetNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
342 auto onMode = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
343 const BaseEventInfo* baseEventInfo) {
344 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
345 ACE_SCORING_EVENT("SlidingPanel.ModeChangeEvent");
346 auto eventInfo = TypeInfoHelper::DynamicCast<SlidingPanelSizeChangeEvent>(baseEventInfo);
347 if (!eventInfo) {
348 return;
349 }
350 PipelineContext::SetCallBackNode(node);
351 auto newJSVal = JSRef<JSVal>::Make(ToJSValue(static_cast<int32_t>(eventInfo->GetMode())));
352 func->ExecuteJS(1, &newJSVal);
353 };
354 SlidingPanelModel::GetInstance()->SetModeChangeEvent(std::move(onMode));
355 }
356
SetPanelMode(const JSCallbackInfo & info)357 void JSSlidingPanel::SetPanelMode(const JSCallbackInfo& info)
358 {
359 if (info.Length() < 1 || info.Length() > 2) {
360 return;
361 }
362
363 int32_t mode = static_cast<int32_t>(DEFAULT_PANELMODE);
364 if (info.Length() > 0 && info[0]->IsNumber()) {
365 const auto modeNumber = info[0]->ToNumber<int32_t>();
366 if (modeNumber >= 0 && modeNumber < static_cast<int32_t>(PANEL_MODES.size())) {
367 mode = modeNumber;
368 }
369 }
370
371 if (info.Length() > 1 && info[1]->IsFunction()) {
372 ParseModeObject(info, info[1]);
373 }
374
375 SlidingPanelModel::GetInstance()->SetPanelMode(PANEL_MODES[mode]);
376 }
377
SetPanelType(const JSCallbackInfo & info)378 void JSSlidingPanel::SetPanelType(const JSCallbackInfo& info)
379 {
380 if (info.Length() < 1) {
381 return;
382 }
383 auto type = static_cast<int32_t>(DEFAULT_PANELTYPE);
384 if (info[0]->IsNumber()) {
385 const auto typeNumber = info[0]->ToNumber<int32_t>();
386 if (typeNumber >= 0 && typeNumber < static_cast<int32_t>(PANEL_TYPES.size())) {
387 type = typeNumber;
388 }
389 }
390 SlidingPanelModel::GetInstance()->SetPanelType(PANEL_TYPES[type]);
391 }
392
SetCustomHeight(const JSCallbackInfo & info)393 void JSSlidingPanel::SetCustomHeight(const JSCallbackInfo& info)
394 {
395 if (info.Length() < 1) {
396 return;
397 }
398 CalcDimension customHeight;
399 if (info[0]->IsString() && info[0]->ToString().find("wrapContent") != std::string::npos) {
400 customHeight = CalcDimension(info[0]->ToString());
401 } else if (!ParseJsDimensionVp(info[0], customHeight)) {
402 customHeight = Dimension(0.0);
403 }
404
405 SlidingPanelModel::GetInstance()->SetCustomHeight(customHeight);
406 }
407
SetMiniHeight(const JSCallbackInfo & info)408 void JSSlidingPanel::SetMiniHeight(const JSCallbackInfo& info)
409 {
410 if (info.Length() < 1) {
411 return;
412 }
413 CalcDimension miniHeight;
414 if (!ParseJsDimensionVp(info[0], miniHeight)) {
415 return;
416 }
417
418 SlidingPanelModel::GetInstance()->SetMiniHeight(miniHeight);
419 }
420
SetHalfHeight(const JSCallbackInfo & info)421 void JSSlidingPanel::SetHalfHeight(const JSCallbackInfo& info)
422 {
423 if (info.Length() < 1) {
424 return;
425 }
426 CalcDimension halfHeight;
427 if (!ParseJsDimensionVp(info[0], halfHeight)) {
428 return;
429 }
430 SlidingPanelModel::GetInstance()->SetHalfHeight(halfHeight);
431 }
432
SetFullHeight(const JSCallbackInfo & info)433 void JSSlidingPanel::SetFullHeight(const JSCallbackInfo& info)
434 {
435 if (info.Length() < 1) {
436 return;
437 }
438 CalcDimension fullHeight;
439 if (!ParseJsDimensionVp(info[0], fullHeight)) {
440 return;
441 }
442 SlidingPanelModel::GetInstance()->SetFullHeight(fullHeight);
443 }
444
Pop()445 void JSSlidingPanel::Pop()
446 {
447 SlidingPanelModel::GetInstance()->Pop();
448 }
449
450 } // namespace OHOS::Ace::Framework
451