1 /*
2 * Copyright (c) 2021-2022 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/action_sheet/js_action_sheet.h"
17
18 #include <string>
19 #include <vector>
20
21 #include "base/log/ace_scoring_log.h"
22 #include "bridge/common/utils/engine_helper.h"
23 #include "bridge/declarative_frontend/engine/functions/js_function.h"
24 #include "bridge/declarative_frontend/jsview/models/action_sheet_model_impl.h"
25 #include "core/common/container.h"
26 #include "core/components_ng/base/view_stack_processor.h"
27 #include "core/components_ng/pattern/action_sheet/action_sheet_model_ng.h"
28
29 namespace OHOS::Ace {
30 std::unique_ptr<ActionSheetModel> ActionSheetModel::instance_ = nullptr;
31 std::mutex ActionSheetModel::mutex_;
32
GetInstance()33 ActionSheetModel* ActionSheetModel::GetInstance()
34 {
35 if (!instance_) {
36 std::lock_guard<std::mutex> lock(mutex_);
37 if (!instance_) {
38 #ifdef NG_BUILD
39 instance_.reset(new NG::ActionSheetModelNG());
40 #else
41 if (Container::IsCurrentUseNewPipeline()) {
42 instance_.reset(new NG::ActionSheetModelNG());
43 } else {
44 instance_.reset(new Framework::ActionSheetModelImpl());
45 }
46 #endif
47 }
48 }
49 return instance_.get();
50 }
51 } // namespace OHOS::Ace
52
53 namespace OHOS::Ace::Framework {
54 namespace {
55 const DimensionOffset ACTION_SHEET_OFFSET_DEFAULT = DimensionOffset(0.0_vp, -40.0_vp);
56 const DimensionOffset ACTION_SHEET_OFFSET_DEFAULT_TOP = DimensionOffset(0.0_vp, 40.0_vp);
57 const std::vector<DialogAlignment> DIALOG_ALIGNMENT = { DialogAlignment::TOP, DialogAlignment::CENTER,
58 DialogAlignment::BOTTOM, DialogAlignment::DEFAULT, DialogAlignment::TOP_START, DialogAlignment::TOP_END,
59 DialogAlignment::CENTER_START, DialogAlignment::CENTER_END, DialogAlignment::BOTTOM_START,
60 DialogAlignment::BOTTOM_END };
61 } // namespace
62
SetParseStyle(ButtonInfo & buttonInfo,const int32_t styleValue)63 static void SetParseStyle(ButtonInfo& buttonInfo, const int32_t styleValue)
64 {
65 if (styleValue >= static_cast<int32_t>(DialogButtonStyle::DEFAULT) &&
66 styleValue <= static_cast<int32_t>(DialogButtonStyle::HIGHTLIGHT)) {
67 buttonInfo.dlgButtonStyle = static_cast<DialogButtonStyle>(styleValue);
68 }
69 }
70
ParseSheetInfo(const JSCallbackInfo & args,JSRef<JSVal> val)71 ActionSheetInfo ParseSheetInfo(const JSCallbackInfo& args, JSRef<JSVal> val)
72 {
73 ActionSheetInfo sheetInfo;
74 if (!val->IsObject()) {
75 LOGW("param is not an object.");
76 return sheetInfo;
77 }
78
79 auto obj = JSRef<JSObject>::Cast(val);
80 auto titleVal = obj->GetProperty("title");
81 std::string title;
82 if (JSActionSheet::ParseJsString(titleVal, title)) {
83 sheetInfo.title = title;
84 }
85
86 auto iconVal = obj->GetProperty("icon");
87 std::string icon;
88 if (JSActionSheet::ParseJsMedia(iconVal, icon)) {
89 sheetInfo.icon = icon;
90 }
91
92 auto actionValue = obj->GetProperty("action");
93 if (actionValue->IsFunction()) {
94 WeakPtr<NG::FrameNode> frameNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
95 auto actionFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(actionValue));
96 auto eventFunc = [execCtx = args.GetExecutionContext(), func = std::move(actionFunc), node = frameNode]
97 (const GestureEvent&) {
98 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
99 ACE_SCORING_EVENT("SheetInfo.action");
100 auto pipelineContext = PipelineContext::GetCurrentContextSafely();
101 CHECK_NULL_VOID(pipelineContext);
102 pipelineContext->UpdateCurrentActiveNode(node);
103 func->ExecuteJS();
104 };
105 ActionSheetModel::GetInstance()->SetAction(eventFunc, sheetInfo);
106 }
107 return sheetInfo;
108 }
109
Show(const JSCallbackInfo & args)110 void JSActionSheet::Show(const JSCallbackInfo& args)
111 {
112 auto scopedDelegate = EngineHelper::GetCurrentDelegateSafely();
113 if (!scopedDelegate) {
114 // this case usually means there is no foreground container, need to figure out the reason.
115 LOGE("scopedDelegate is null, please check");
116 return;
117 }
118 if (!args[0]->IsObject()) {
119 LOGE("args is not an object, can't show ActionSheet.");
120 return;
121 }
122
123 DialogProperties properties {
124 .type = DialogType::ACTION_SHEET, .alignment = DialogAlignment::BOTTOM, .offset = ACTION_SHEET_OFFSET_DEFAULT
125 };
126 auto obj = JSRef<JSObject>::Cast(args[0]);
127 // Parse title.
128 auto titleValue = obj->GetProperty("title");
129 std::string title;
130 if (ParseJsString(titleValue, title)) {
131 properties.title = title;
132 }
133
134 // Parse subtitle.
135 auto subtitleValue = obj->GetProperty("subtitle");
136 std::string subtitle;
137 if (ParseJsString(subtitleValue, subtitle)) {
138 properties.subtitle = subtitle;
139 }
140
141 // Parses message.
142 auto messageValue = obj->GetProperty("message");
143 std::string message;
144 if (ParseJsString(messageValue, message)) {
145 properties.content = message;
146 }
147
148 // Parse auto autoCancel.
149 auto autoCancelValue = obj->GetProperty("autoCancel");
150 if (autoCancelValue->IsBoolean()) {
151 properties.autoCancel = autoCancelValue->ToBoolean();
152 }
153
154 // Parse cancel.
155 auto cancelValue = obj->GetProperty("cancel");
156 if (cancelValue->IsFunction()) {
157 WeakPtr<NG::FrameNode> frameNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
158 auto cancelFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(cancelValue));
159 auto eventFunc = [execCtx = args.GetExecutionContext(), func = std::move(cancelFunc), node = frameNode]() {
160 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
161 ACE_SCORING_EVENT("ActionSheet.cancel");
162 auto pipelineContext = PipelineContext::GetCurrentContextSafely();
163 CHECK_NULL_VOID(pipelineContext);
164 pipelineContext->UpdateCurrentActiveNode(node);
165 func->Execute();
166 };
167 ActionSheetModel::GetInstance()->SetCancel(eventFunc, properties);
168 }
169
170 // Parse confirm.
171 auto confirmVal = obj->GetProperty("confirm");
172 if (confirmVal->IsObject()) {
173 JSRef<JSObject> confirmObj = JSRef<JSObject>::Cast(confirmVal);
174 JSRef<JSVal> value = confirmObj->GetProperty("value");
175 std::string buttonValue;
176 if (ParseJsString(value, buttonValue)) {
177 ButtonInfo buttonInfo = { .text = buttonValue };
178 JSRef<JSVal> actionValue = confirmObj->GetProperty("action");
179 // parse confirm action
180 if (actionValue->IsFunction()) {
181 WeakPtr<NG::FrameNode> frameNode = NG::ViewStackProcessor::GetInstance()->GetMainFrameNode();
182 auto actionFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(actionValue));
183 auto gestureEvent = [execCtx = args.GetExecutionContext(),
184 func = std::move(actionFunc), node = frameNode](GestureEvent&) {
185 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
186 ACE_SCORING_EVENT("ActionSheet.confirm.action");
187 auto pipelineContext = PipelineContext::GetCurrentContextSafely();
188 CHECK_NULL_VOID(pipelineContext);
189 pipelineContext->UpdateCurrentActiveNode(node);
190 func->ExecuteJS();
191 };
192 actionFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(actionValue));
193 auto eventFunc = [execCtx = args.GetExecutionContext(), func = std::move(actionFunc),
194 node = frameNode]() {
195 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
196 ACE_SCORING_EVENT("ActionSheet.confirm.action");
197 auto pipelineContext = PipelineContext::GetCurrentContextSafely();
198 CHECK_NULL_VOID(pipelineContext);
199 pipelineContext->UpdateCurrentActiveNode(node);
200 func->Execute();
201 };
202 ActionSheetModel::GetInstance()->SetConfirm(gestureEvent, eventFunc, buttonInfo, properties);
203 }
204
205 // Parse enabled
206 auto enabledValue = confirmObj->GetProperty("enabled");
207 if (enabledValue->IsBoolean()) {
208 buttonInfo.enabled = enabledValue->ToBoolean();
209 }
210
211 // Parse defaultFocus
212 auto defaultFocusValue = confirmObj->GetProperty("defaultFocus");
213 if (defaultFocusValue->IsBoolean()) {
214 buttonInfo.defaultFocus = defaultFocusValue->ToBoolean();
215 }
216
217 // Parse style
218 auto style = confirmObj->GetProperty("style");
219 if (style->IsNumber()) {
220 auto styleValue = style->ToNumber<int32_t>();
221 SetParseStyle(buttonInfo, styleValue);
222 }
223
224 if (buttonInfo.IsValid()) {
225 properties.buttons.emplace_back(buttonInfo);
226 }
227 }
228 }
229
230 // Parse sheets
231 auto sheetsVal = obj->GetProperty("sheets");
232 if (sheetsVal->IsArray()) {
233 std::vector<ActionSheetInfo> sheetsInfo;
234 auto sheetsArr = JSRef<JSArray>::Cast(sheetsVal);
235 for (size_t index = 0; index < sheetsArr->Length(); ++index) {
236 sheetsInfo.emplace_back(ParseSheetInfo(args, sheetsArr->GetValueAt(index)));
237 }
238 properties.sheetsInfo = std::move(sheetsInfo);
239 }
240
241 // Parse alignment
242 auto alignmentValue = obj->GetProperty("alignment");
243 if (alignmentValue->IsNumber()) {
244 auto alignment = alignmentValue->ToNumber<int32_t>();
245 if (alignment >= 0 && alignment <= static_cast<int32_t>(DIALOG_ALIGNMENT.size())) {
246 properties.alignment = DIALOG_ALIGNMENT[alignment];
247 }
248 if (alignment == static_cast<int32_t>(DialogAlignment::TOP) ||
249 alignment == static_cast<int32_t>(DialogAlignment::TOP_START) ||
250 alignment == static_cast<int32_t>(DialogAlignment::TOP_END)) {
251 properties.offset = ACTION_SHEET_OFFSET_DEFAULT_TOP;
252 }
253 }
254
255 // Parse offset
256 auto offsetValue = obj->GetProperty("offset");
257 if (offsetValue->IsObject()) {
258 auto offsetObj = JSRef<JSObject>::Cast(offsetValue);
259 CalcDimension dx;
260 auto dxValue = offsetObj->GetProperty("dx");
261 ParseJsDimensionVp(dxValue, dx);
262 CalcDimension dy;
263 auto dyValue = offsetObj->GetProperty("dy");
264 ParseJsDimensionVp(dyValue, dy);
265 properties.offset = DimensionOffset(dx, dy);
266 }
267
268 // Parse maskRect.
269 auto maskRectValue = obj->GetProperty("maskRect");
270 DimensionRect maskRect;
271 if (JSViewAbstract::ParseJsDimensionRect(maskRectValue, maskRect)) {
272 properties.maskRect = maskRect;
273 }
274
275 // Parses gridCount.
276 auto gridCountValue = obj->GetProperty("gridCount");
277 if (gridCountValue->IsNumber()) {
278 properties.gridCount = gridCountValue->ToNumber<int32_t>();
279 }
280
281 // Parse showInSubWindowValue.
282 auto showInSubWindowValue = obj->GetProperty("showInSubWindow");
283 if (showInSubWindowValue->IsBoolean()) {
284 LOGI("Parse showInSubWindowValue");
285 properties.isShowInSubWindow = showInSubWindowValue->ToBoolean();
286 }
287
288 // Parse isModalValue.
289 auto isModalValue = obj->GetProperty("isModal");
290 if (isModalValue->IsBoolean()) {
291 LOGI("Parse isModalValue");
292 properties.isModal = isModalValue->ToBoolean();
293 }
294
295 auto backgroundColorValue = obj->GetProperty("backgroundColor");
296 Color backgroundColor;
297 if (JSViewAbstract::ParseJsColor(backgroundColorValue, backgroundColor)) {
298 properties.backgroundColor = backgroundColor;
299 }
300
301 auto backgroundBlurStyle = obj->GetProperty("backgroundBlurStyle");
302 BlurStyleOption styleOption;
303 if (backgroundBlurStyle->IsNumber()) {
304 auto blurStyle = backgroundBlurStyle->ToNumber<int32_t>();
305 if (blurStyle >= static_cast<int>(BlurStyle::NO_MATERIAL) &&
306 blurStyle <= static_cast<int>(BlurStyle::COMPONENT_ULTRA_THICK)) {
307 properties.backgroundBlurStyle = blurStyle;
308 }
309 }
310 ActionSheetModel::GetInstance()->ShowActionSheet(properties);
311 args.SetReturnValue(args.This());
312 }
313
JSBind(BindingTarget globalObj)314 void JSActionSheet::JSBind(BindingTarget globalObj)
315 {
316 JSClass<JSActionSheet>::Declare("ActionSheet");
317 JSClass<JSActionSheet>::StaticMethod("show", &JSActionSheet::Show);
318 JSClass<JSActionSheet>::InheritAndBind<JSViewAbstract>(globalObj);
319 }
320 } // namespace OHOS::Ace::Framework
321