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