• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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