1 /*
2 * Copyright (c) 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_calendar_picker.h"
17
18 #include "base/log/ace_scoring_log.h"
19 #include "base/utils/date_util.h"
20 #include "bridge/common/utils/engine_helper.h"
21 #include "bridge/declarative_frontend/engine/functions/js_function.h"
22 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
23 #include "bridge/declarative_frontend/jsview/js_utils.h"
24 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
25 #include "bridge/declarative_frontend/jsview/models/calendar_picker_model_impl.h"
26 #include "core/components/calendar/calendar_theme.h"
27 #include "core/components/dialog/dialog_theme.h"
28 #include "core/components_ng/base/view_abstract_model.h"
29 #include "core/components_ng/base/view_stack_processor.h"
30 #include "core/components_ng/pattern/calendar_picker/calendar_picker_model_ng.h"
31 #include "core/pipeline_ng/pipeline_context.h"
32
33 namespace OHOS::Ace {
34 std::unique_ptr<CalendarPickerModel> CalendarPickerModel::instance_ = nullptr;
35 std::mutex CalendarPickerModel::mutex_;
GetInstance()36 CalendarPickerModel* CalendarPickerModel::GetInstance()
37 {
38 if (!instance_) {
39 std::lock_guard<std::mutex> lock(mutex_);
40 if (!instance_) {
41 #ifdef NG_BUILD
42 instance_.reset(new NG::CalendarPickerModelNG());
43 #else
44 if (Container::IsCurrentUseNewPipeline()) {
45 instance_.reset(new NG::CalendarPickerModelNG());
46 } else {
47 instance_.reset(new Framework::CalendarPickerModelImpl());
48 }
49 #endif
50 }
51 }
52 return instance_.get();
53 }
54 } // namespace OHOS::Ace
55
56 namespace OHOS::Ace::Framework {
57 namespace {
ParseFontOfButtonStyle(const JSRef<JSObject> & pickerButtonParamObject,ButtonInfo & buttonInfo)58 void ParseFontOfButtonStyle(const JSRef<JSObject>& pickerButtonParamObject, ButtonInfo& buttonInfo)
59 {
60 CalcDimension fontSize;
61 JSRef<JSVal> sizeProperty = pickerButtonParamObject->GetProperty("fontSize");
62 if (JSViewAbstract::ParseJsDimensionVpNG(sizeProperty, fontSize) && fontSize.Unit() != DimensionUnit::PERCENT &&
63 GreatOrEqual(fontSize.Value(), 0.0)) {
64 if (JSViewAbstract::ParseJsDimensionFp(sizeProperty, fontSize)) {
65 buttonInfo.fontSize = fontSize;
66 }
67 }
68 Color fontColor;
69 if (JSViewAbstract::ParseJsColor(pickerButtonParamObject->GetProperty("fontColor"), fontColor)) {
70 buttonInfo.fontColor = fontColor;
71 }
72 auto fontWeight = pickerButtonParamObject->GetProperty("fontWeight");
73 if (fontWeight->IsString() || fontWeight->IsNumber()) {
74 buttonInfo.fontWeight = ConvertStrToFontWeight(fontWeight->ToString(), FontWeight::MEDIUM);
75 }
76 JSRef<JSVal> style = pickerButtonParamObject->GetProperty("fontStyle");
77 if (style->IsNumber()) {
78 auto value = style->ToNumber<int32_t>();
79 if (value >= 0 && value < static_cast<int32_t>(FontStyle::NONE)) {
80 buttonInfo.fontStyle = static_cast<FontStyle>(value);
81 }
82 }
83 JSRef<JSVal> family = pickerButtonParamObject->GetProperty("fontFamily");
84 std::vector<std::string> fontFamilies;
85 if (JSViewAbstract::ParseJsFontFamilies(family, fontFamilies)) {
86 buttonInfo.fontFamily = fontFamilies;
87 }
88 }
89
ParseButtonStyle(const JSRef<JSObject> & pickerButtonParamObject)90 ButtonInfo ParseButtonStyle(const JSRef<JSObject>& pickerButtonParamObject)
91 {
92 ButtonInfo buttonInfo;
93 if (pickerButtonParamObject->GetProperty("type")->IsNumber()) {
94 buttonInfo.type =
95 static_cast<ButtonType>(pickerButtonParamObject->GetProperty("type")->ToNumber<int32_t>());
96 }
97 if (pickerButtonParamObject->GetProperty("style")->IsNumber()) {
98 auto styleModeIntValue = pickerButtonParamObject->GetProperty("style")->ToNumber<int32_t>();
99 if (styleModeIntValue >= static_cast<int32_t>(ButtonStyleMode::NORMAL) &&
100 styleModeIntValue <= static_cast<int32_t>(ButtonStyleMode::TEXT)) {
101 buttonInfo.buttonStyle = static_cast<ButtonStyleMode>(styleModeIntValue);
102 }
103 }
104 if (pickerButtonParamObject->GetProperty("role")->IsNumber()) {
105 auto buttonRoleIntValue = pickerButtonParamObject->GetProperty("role")->ToNumber<int32_t>();
106 if (buttonRoleIntValue >= static_cast<int32_t>(ButtonRole::NORMAL) &&
107 buttonRoleIntValue <= static_cast<int32_t>(ButtonRole::ERROR)) {
108 buttonInfo.role = static_cast<ButtonRole>(buttonRoleIntValue);
109 }
110 }
111 ParseFontOfButtonStyle(pickerButtonParamObject, buttonInfo);
112 Color backgroundColor;
113 if (JSViewAbstract::ParseJsColor(pickerButtonParamObject->GetProperty("backgroundColor"), backgroundColor)) {
114 buttonInfo.backgroundColor = backgroundColor;
115 }
116 auto radius = ParseBorderRadiusAttr(pickerButtonParamObject->GetProperty("borderRadius"));
117 if (radius.has_value()) {
118 buttonInfo.borderRadius = radius.value();
119 }
120
121 auto primaryValue = pickerButtonParamObject->GetProperty("primary");
122 if (primaryValue->IsBoolean()) {
123 buttonInfo.isPrimary = primaryValue->ToBoolean();
124 }
125
126 return buttonInfo;
127 }
128
ParseButtonStyles(const JSRef<JSObject> & paramObject)129 std::vector<ButtonInfo> ParseButtonStyles(const JSRef<JSObject>& paramObject)
130 {
131 std::vector<ButtonInfo> buttonInfos;
132 auto acceptButtonStyle = paramObject->GetProperty("acceptButtonStyle");
133 if (acceptButtonStyle->IsObject()) {
134 auto acceptButtonStyleParamObject = JSRef<JSObject>::Cast(acceptButtonStyle);
135 buttonInfos.emplace_back(ParseButtonStyle(acceptButtonStyleParamObject));
136 buttonInfos[0].isAcceptButton = true;
137 } else {
138 ButtonInfo buttonInfo;
139 buttonInfos.emplace_back(buttonInfo);
140 }
141 auto cancelButtonStyle = paramObject->GetProperty("cancelButtonStyle");
142 if (cancelButtonStyle->IsObject()) {
143 auto cancelButtonStyleParamObject = JSRef<JSObject>::Cast(cancelButtonStyle);
144 buttonInfos.emplace_back(ParseButtonStyle(cancelButtonStyleParamObject));
145 }
146
147 return buttonInfos;
148 }
149 } // namespace
150
GetMSByDate(const std::string & date)151 double GetMSByDate(const std::string& date)
152 {
153 auto json = JsonUtil::ParseJsonString(date);
154 if (!json || json->IsNull()) {
155 return 0.0f;
156 }
157
158 std::tm dateTime = { 0 };
159 auto year = json->GetValue("year");
160 if (year && year->IsNumber()) {
161 dateTime.tm_year = year->GetInt() - 1900; // local date start from 1900
162 }
163 auto month = json->GetValue("month");
164 if (month && month->IsNumber()) {
165 dateTime.tm_mon = month->GetInt() - 1;
166 }
167 auto day = json->GetValue("day");
168 if (day && day->IsNumber()) {
169 dateTime.tm_mday = day->GetInt();
170 }
171 auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
172 auto local = std::localtime(&now);
173 CHECK_NULL_RETURN(local, 0.0f);
174 dateTime.tm_hour = local->tm_hour;
175 dateTime.tm_min = local->tm_min;
176 dateTime.tm_sec = local->tm_sec;
177 return Date::GetMilliSecondsByDateTime(dateTime);
178 }
179
JSBind(BindingTarget globalObj)180 void JSCalendarPicker::JSBind(BindingTarget globalObj)
181 {
182 JSClass<JSCalendarPicker>::Declare("CalendarPicker");
183 JSClass<JSCalendarPicker>::StaticMethod("create", &JSCalendarPicker::Create, MethodOptions::NONE);
184 JSClass<JSCalendarPicker>::StaticMethod("edgeAlign", &JSCalendarPicker::SetEdgeAlign);
185 JSClass<JSCalendarPicker>::StaticMethod("textStyle", &JSCalendarPicker::SetTextStyle);
186 JSClass<JSCalendarPicker>::StaticMethod("onChange", &JSCalendarPicker::SetOnChange);
187 JSClass<JSCalendarPicker>::StaticMethod("border", &JSCalendarPicker::SetBorder);
188 JSClass<JSCalendarPicker>::StaticMethod("padding", &JSCalendarPicker::JsPadding);
189 JSClass<JSCalendarPicker>::InheritAndBind<JSViewAbstract>(globalObj);
190 }
191
SetBorder(const JSCallbackInfo & info)192 void JSCalendarPicker::SetBorder(const JSCallbackInfo& info)
193 {
194 if (!info[0]->IsObject()) {
195 return;
196 }
197 JSRef<JSObject> object = JSRef<JSObject>::Cast(info[0]);
198 auto valueWidth = object->GetProperty("width");
199 if (!valueWidth->IsUndefined()) {
200 ParseBorderWidth(valueWidth);
201 }
202
203 // use default value when undefined.
204 ParseCalendarPickerBorderColor(object->GetProperty("color"));
205
206 auto valueRadius = object->GetProperty("radius");
207 if (!valueRadius->IsUndefined()) {
208 ParseBorderRadius(valueRadius);
209 }
210 // use default value when undefined.
211 ParseBorderStyle(object->GetProperty("style"));
212
213 info.ReturnSelf();
214 }
215
ParseCalendarPickerBorderColor(const JSRef<JSVal> & args)216 void JSCalendarPicker::ParseCalendarPickerBorderColor(const JSRef<JSVal>& args)
217 {
218 auto pipelineContext = PipelineContext::GetCurrentContext();
219 CHECK_NULL_VOID(pipelineContext);
220 RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
221 CHECK_NULL_VOID(theme);
222 if (!args->IsObject() && !args->IsNumber() && !args->IsString()) {
223 ViewAbstractModel::GetInstance()->SetBorderColor(theme->GetEntryBorderColor());
224 } else {
225 JSViewAbstract::ParseBorderColor(args);
226 }
227 }
228
SetEdgeAlign(const JSCallbackInfo & info)229 void JSCalendarPicker::SetEdgeAlign(const JSCallbackInfo& info)
230 {
231 NG::CalendarEdgeAlign alignType = NG::CalendarEdgeAlign::EDGE_ALIGN_END;
232 DimensionOffset offset;
233 if (info[0]->IsNumber()) {
234 alignType = static_cast<NG::CalendarEdgeAlign>(info[0]->ToNumber<int32_t>());
235 }
236
237 if (!info[1]->IsObject()) {
238 CalendarPickerModel::GetInstance()->SetEdgeAlign(alignType, offset);
239 return;
240 }
241 auto offsetObj = JSRef<JSObject>::Cast(info[1]);
242 CalcDimension dx;
243 auto dxValue = offsetObj->GetProperty("dx");
244 ParseJsDimensionVp(dxValue, dx);
245 CalcDimension dy;
246 auto dyValue = offsetObj->GetProperty("dy");
247 ParseJsDimensionVp(dyValue, dy);
248 offset = DimensionOffset(dx, dy);
249
250 CalendarPickerModel::GetInstance()->SetEdgeAlign(alignType, offset);
251 }
252
SetTextStyle(const JSCallbackInfo & info)253 void JSCalendarPicker::SetTextStyle(const JSCallbackInfo& info)
254 {
255 auto pipeline = PipelineBase::GetCurrentContext();
256 CHECK_NULL_VOID(pipeline);
257 RefPtr<CalendarTheme> calendarTheme = pipeline->GetTheme<CalendarTheme>();
258 CHECK_NULL_VOID(calendarTheme);
259 NG::PickerTextStyle textStyle;
260 textStyle.fontSize = calendarTheme->GetEntryFontSize();
261 textStyle.textColor = calendarTheme->GetEntryFontColor();
262 textStyle.fontWeight = FontWeight::NORMAL;
263 if (!info[0]->IsObject()) {
264 CalendarPickerModel::GetInstance()->SetTextStyle(textStyle);
265 return;
266 }
267 JSCalendarPicker::ParseTextStyle(info[0], textStyle);
268 CalendarPickerModel::GetInstance()->SetTextStyle(textStyle);
269 }
270
SetOnChange(const JSCallbackInfo & info)271 void JSCalendarPicker::SetOnChange(const JSCallbackInfo& info)
272 {
273 if (!info[0]->IsFunction()) {
274 return;
275 }
276
277 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
278 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
279 auto onChange = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
280 const std::string& info) {
281 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
282 ACE_SCORING_EVENT("CalendarPicker.onChange");
283 PipelineContext::SetCallBackNode(node);
284 auto dateObj = JSDate::New(GetMSByDate(info));
285 func->ExecuteJS(1, &dateObj);
286 };
287 CalendarPickerModel::GetInstance()->SetOnChange(std::move(onChange));
288 }
289
JsPadding(const JSCallbackInfo & info)290 void JSCalendarPicker::JsPadding(const JSCallbackInfo& info)
291 {
292 NG::PaddingProperty padding;
293 if (info[0]->IsObject()) {
294 std::optional<CalcDimension> left;
295 std::optional<CalcDimension> right;
296 std::optional<CalcDimension> top;
297 std::optional<CalcDimension> bottom;
298 JSRef<JSObject> paddingObj = JSRef<JSObject>::Cast(info[0]);
299
300 CalcDimension leftDimen;
301 if (ParseJsDimensionVp(paddingObj->GetProperty("left"), leftDimen)) {
302 left = leftDimen;
303 }
304 CalcDimension rightDimen;
305 if (ParseJsDimensionVp(paddingObj->GetProperty("right"), rightDimen)) {
306 right = rightDimen;
307 }
308 CalcDimension topDimen;
309 if (ParseJsDimensionVp(paddingObj->GetProperty("top"), topDimen)) {
310 top = topDimen;
311 }
312 CalcDimension bottomDimen;
313 if (ParseJsDimensionVp(paddingObj->GetProperty("bottom"), bottomDimen)) {
314 bottom = bottomDimen;
315 }
316 if (left.has_value() || right.has_value() || top.has_value() || bottom.has_value()) {
317 padding = SetPaddings(top, bottom, left, right);
318 CalendarPickerModel::GetInstance()->SetPadding(padding);
319 return;
320 }
321 }
322
323 CalcDimension length(-1);
324 ParseJsDimensionVp(info[0], length);
325 if (length.IsNonNegative()) {
326 padding.SetEdges(NG::CalcLength(length));
327 }
328 CalendarPickerModel::GetInstance()->SetPadding(padding);
329 }
330
SetPaddings(const std::optional<CalcDimension> & top,const std::optional<CalcDimension> & bottom,const std::optional<CalcDimension> & left,const std::optional<CalcDimension> & right)331 NG::PaddingProperty JSCalendarPicker::SetPaddings(const std::optional<CalcDimension>& top,
332 const std::optional<CalcDimension>& bottom, const std::optional<CalcDimension>& left,
333 const std::optional<CalcDimension>& right)
334 {
335 NG::PaddingProperty paddings;
336 if (top.has_value()) {
337 if (top.value().Unit() == DimensionUnit::CALC) {
338 paddings.top =
339 NG::CalcLength(top.value().IsNonNegative() ? top.value().CalcValue() : CalcDimension().CalcValue());
340 } else {
341 paddings.top = NG::CalcLength(top.value().IsNonNegative() ? top.value() : CalcDimension());
342 }
343 }
344 if (bottom.has_value()) {
345 if (bottom.value().Unit() == DimensionUnit::CALC) {
346 paddings.bottom = NG::CalcLength(
347 bottom.value().IsNonNegative() ? bottom.value().CalcValue() : CalcDimension().CalcValue());
348 } else {
349 paddings.bottom = NG::CalcLength(bottom.value().IsNonNegative() ? bottom.value() : CalcDimension());
350 }
351 }
352 if (left.has_value()) {
353 if (left.value().Unit() == DimensionUnit::CALC) {
354 paddings.left =
355 NG::CalcLength(left.value().IsNonNegative() ? left.value().CalcValue() : CalcDimension().CalcValue());
356 } else {
357 paddings.left = NG::CalcLength(left.value().IsNonNegative() ? left.value() : CalcDimension());
358 }
359 }
360 if (right.has_value()) {
361 if (right.value().Unit() == DimensionUnit::CALC) {
362 paddings.right =
363 NG::CalcLength(right.value().IsNonNegative() ? right.value().CalcValue() : CalcDimension().CalcValue());
364 } else {
365 paddings.right = NG::CalcLength(right.value().IsNonNegative() ? right.value() : CalcDimension());
366 }
367 }
368
369 return paddings;
370 }
371
ParseSelectedDateObject(const JSCallbackInfo & info,const JSRef<JSObject> & selectedObject)372 void JSCalendarPicker::ParseSelectedDateObject(const JSCallbackInfo& info, const JSRef<JSObject>& selectedObject)
373 {
374 JSRef<JSVal> changeEventVal = selectedObject->GetProperty("changeEvent");
375 if (!changeEventVal->IsFunction()) {
376 return;
377 }
378 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(changeEventVal));
379 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
380 auto changeEvent = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
381 const std::string& info) {
382 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
383 ACE_SCORING_EVENT("DatePicker.SelectedDateTimeChangeEvent");
384 PipelineContext::SetCallBackNode(node);
385 auto dateObj = JSDate::New(GetMSByDate(info));
386 func->ExecuteJS(1, &dateObj);
387 };
388 CalendarPickerModel::GetInstance()->SetChangeEvent(std::move(changeEvent));
389 }
390
Create(const JSCallbackInfo & info)391 void JSCalendarPicker::Create(const JSCallbackInfo& info)
392 {
393 NG::CalendarSettingData settingData;
394 RefPtr<CalendarTheme> calendarTheme = GetTheme<CalendarTheme>();
395 CHECK_NULL_VOID(calendarTheme);
396 CalcDimension dayRadius;
397 if (info[0]->IsObject()) {
398 auto obj = JSRef<JSObject>::Cast(info[0]);
399 if (!ParseJsDimensionVpNG(obj->GetProperty("hintRadius"), dayRadius)) {
400 dayRadius = calendarTheme->GetCalendarDayRadius();
401 }
402 auto selected = obj->GetProperty("selected");
403 auto parseSelectedDate = ParseDate(selected);
404 if (selected->IsObject() && parseSelectedDate.GetYear() != 0) {
405 JSRef<JSObject> selectedDateObj = JSRef<JSObject>::Cast(selected);
406 JSRef<JSVal> changeEventVal = selectedDateObj->GetProperty("changeEvent");
407 if (!changeEventVal->IsUndefined() && changeEventVal->IsFunction()) {
408 ParseSelectedDateObject(info, selectedDateObj);
409 settingData.selectedDate = ParseDate(selectedDateObj->GetProperty("value"));
410 } else {
411 settingData.selectedDate = parseSelectedDate;
412 }
413 }
414 } else {
415 dayRadius = calendarTheme->GetCalendarDayRadius();
416 }
417 settingData.dayRadius = dayRadius;
418 CalendarPickerModel::GetInstance()->Create(settingData);
419 }
420
ParseTextStyle(const JSRef<JSObject> & paramObj,NG::PickerTextStyle & textStyle)421 void JSCalendarPicker::ParseTextStyle(const JSRef<JSObject>& paramObj, NG::PickerTextStyle& textStyle)
422 {
423 auto fontColor = paramObj->GetProperty("color");
424 auto fontStyle = paramObj->GetProperty("font");
425
426 Color color;
427 if (ParseJsColor(fontColor, color)) {
428 textStyle.textColor = color;
429 }
430
431 if (!fontStyle->IsObject()) {
432 return;
433 }
434 JSRef<JSObject> fontObj = JSRef<JSObject>::Cast(fontStyle);
435 auto fontSize = fontObj->GetProperty("size");
436 auto fontWeight = fontObj->GetProperty("weight");
437 if (fontSize->IsNull() || fontSize->IsUndefined()) {
438 textStyle.fontSize = Dimension(-1);
439 } else {
440 CalcDimension size;
441 if (!ParseJsDimensionFpNG(fontSize, size) || size.Unit() == DimensionUnit::PERCENT) {
442 textStyle.fontSize = Dimension(-1);
443 } else {
444 textStyle.fontSize = size;
445 }
446 }
447
448 if (!fontWeight->IsNull() && !fontWeight->IsUndefined()) {
449 std::string weight;
450 if (fontWeight->IsNumber()) {
451 weight = std::to_string(fontWeight->ToNumber<int32_t>());
452 } else {
453 ParseJsString(fontWeight, weight);
454 }
455 textStyle.fontWeight = ConvertStrToFontWeight(weight);
456 }
457 }
458
ParseDate(const JSRef<JSVal> & dateVal)459 PickerDate JSCalendarPicker::ParseDate(const JSRef<JSVal>& dateVal)
460 {
461 auto pickerDate = PickerDate::Current();
462 if (!dateVal->IsObject()) {
463 return pickerDate;
464 }
465 auto dateObj = JSRef<JSObject>::Cast(dateVal);
466 auto yearFuncJsVal = dateObj->GetProperty("getFullYear");
467 auto monthFuncJsVal = dateObj->GetProperty("getMonth");
468 auto dateFuncJsVal = dateObj->GetProperty("getDate");
469 if (!(yearFuncJsVal->IsFunction() && monthFuncJsVal->IsFunction() && dateFuncJsVal->IsFunction())) {
470 return pickerDate;
471 }
472 auto yearFunc = JSRef<JSFunc>::Cast(yearFuncJsVal);
473 auto monthFunc = JSRef<JSFunc>::Cast(monthFuncJsVal);
474 auto dateFunc = JSRef<JSFunc>::Cast(dateFuncJsVal);
475 JSRef<JSVal> year = yearFunc->Call(dateObj);
476 JSRef<JSVal> month = monthFunc->Call(dateObj);
477 JSRef<JSVal> date = dateFunc->Call(dateObj);
478
479 if (year->IsNumber() && month->IsNumber() && date->IsNumber()) {
480 pickerDate.SetYear(year->ToNumber<int32_t>());
481 pickerDate.SetMonth(month->ToNumber<int32_t>() + 1); // 0-11 means 1 to 12 months
482 pickerDate.SetDay(date->ToNumber<int32_t>());
483 }
484 return pickerDate;
485 }
486
JSBind(BindingTarget globalObj)487 void JSCalendarPickerDialog::JSBind(BindingTarget globalObj)
488 {
489 JSClass<JSCalendarPickerDialog>::Declare("CalendarPickerDialog");
490 JSClass<JSCalendarPickerDialog>::StaticMethod("show", &JSCalendarPickerDialog::Show);
491 JSClass<JSCalendarPickerDialog>::Bind<>(globalObj);
492 }
493
Show(const JSCallbackInfo & info)494 void JSCalendarPickerDialog::Show(const JSCallbackInfo& info)
495 {
496 auto scopedDelegate = EngineHelper::GetCurrentDelegateSafely();
497 CHECK_NULL_VOID(scopedDelegate);
498 if (!info[0]->IsObject()) {
499 return;
500 }
501
502 if (Container::IsCurrentUseNewPipeline()) {
503 auto paramObject = JSRef<JSObject>::Cast(info[0]);
504 auto buttonInfos = ParseButtonStyles(paramObject);
505 auto dialogEvent = ChangeDialogEvent(info);
506 auto dialogCancelEvent = DialogCancelEvent(info);
507 auto dialogLifeCycleEvent = LifeCycleDialogEvent(info);
508 CalendarPickerDialogShow(paramObject, dialogEvent, dialogCancelEvent, dialogLifeCycleEvent, buttonInfos);
509 }
510 }
511
ChangeDialogEvent(const JSCallbackInfo & info)512 std::map<std::string, NG::DialogEvent> JSCalendarPickerDialog::ChangeDialogEvent(const JSCallbackInfo& info)
513 {
514 std::map<std::string, NG::DialogEvent> dialogEvent;
515 if (!info[0]->IsObject()) {
516 return dialogEvent;
517 }
518 auto paramObject = JSRef<JSObject>::Cast(info[0]);
519 auto onChange = paramObject->GetProperty("onChange");
520 if (!onChange->IsUndefined() && onChange->IsFunction()) {
521 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onChange));
522 auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
523 auto changeId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
524 const std::string& info) {
525 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
526 ACE_SCORING_EVENT("CalendarDialog.onChange");
527 PipelineContext::SetCallBackNode(node);
528 auto dateObj = JSDate::New(GetMSByDate(info));
529 func->ExecuteJS(1, &dateObj);
530 };
531 dialogEvent["changeId"] = changeId;
532 }
533 auto onAccept = paramObject->GetProperty("onAccept");
534 if (!onAccept->IsUndefined() && onAccept->IsFunction()) {
535 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onAccept));
536 auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
537 auto acceptId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
538 const std::string& info) {
539 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
540 ACE_SCORING_EVENT("CalendarDialog.onAccept");
541 PipelineContext::SetCallBackNode(node);
542 auto dateObj = JSDate::New(GetMSByDate(info));
543 func->ExecuteJS(1, &dateObj);
544 };
545 dialogEvent["acceptId"] = acceptId;
546 }
547 return dialogEvent;
548 }
549
DialogCancelEvent(const JSCallbackInfo & info)550 std::map<std::string, NG::DialogGestureEvent> JSCalendarPickerDialog::DialogCancelEvent(const JSCallbackInfo& info)
551 {
552 std::map<std::string, NG::DialogGestureEvent> dialogCancelEvent;
553 if (!info[0]->IsObject()) {
554 return dialogCancelEvent;
555 }
556 auto paramObject = JSRef<JSObject>::Cast(info[0]);
557 auto onCancel = paramObject->GetProperty("onCancel");
558 if (!onCancel->IsUndefined() && onCancel->IsFunction()) {
559 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onCancel));
560 auto targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
561 auto cancelId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode](
562 const GestureEvent& /* info */) {
563 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
564 ACE_SCORING_EVENT("CalendarDialog.onCancel");
565 PipelineContext::SetCallBackNode(node);
566 func->Execute();
567 };
568 dialogCancelEvent["cancelId"] = cancelId;
569 }
570 return dialogCancelEvent;
571 }
572
AppearDialogEvent(const JSCallbackInfo & info,std::map<std::string,NG::DialogCancelEvent> & dialogLifeCycleEvent)573 void AppearDialogEvent(const JSCallbackInfo& info, std::map<std::string, NG::DialogCancelEvent>& dialogLifeCycleEvent)
574 {
575 if (!info[0]->IsObject()) {
576 return;
577 }
578 auto paramObject = JSRef<JSObject>::Cast(info[0]);
579 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
580 auto onDidAppear = paramObject->GetProperty("onDidAppear");
581 if (!onDidAppear->IsUndefined() && onDidAppear->IsFunction()) {
582 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onDidAppear));
583 auto didAppearId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode]() {
584 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
585 ACE_SCORING_EVENT("CalendarDialog.onDidAppear");
586 PipelineContext::SetCallBackNode(node);
587 func->Execute();
588 };
589 dialogLifeCycleEvent["didAppearId"] = didAppearId;
590 }
591 auto onWillAppear = paramObject->GetProperty("onWillAppear");
592 if (!onWillAppear->IsUndefined() && onWillAppear->IsFunction()) {
593 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onWillAppear));
594 auto willAppearId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode]() {
595 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
596 ACE_SCORING_EVENT("CalendarDialog.onWillAppear");
597 PipelineContext::SetCallBackNode(node);
598 func->Execute();
599 };
600 dialogLifeCycleEvent["willAppearId"] = willAppearId;
601 }
602 }
603
DisappearDialogEvent(const JSCallbackInfo & info,std::map<std::string,NG::DialogCancelEvent> & dialogLifeCycleEvent)604 void DisappearDialogEvent(
605 const JSCallbackInfo& info, std::map<std::string, NG::DialogCancelEvent>& dialogLifeCycleEvent)
606 {
607 if (!info[0]->IsObject()) {
608 return;
609 }
610 auto paramObject = JSRef<JSObject>::Cast(info[0]);
611 WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
612 auto onDidDisappear = paramObject->GetProperty("onDidDisappear");
613 if (!onDidDisappear->IsUndefined() && onDidDisappear->IsFunction()) {
614 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onDidDisappear));
615 auto didDisappearId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc), node = targetNode]() {
616 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
617 ACE_SCORING_EVENT("CalendarDialog.onDidDisappear");
618 PipelineContext::SetCallBackNode(node);
619 func->Execute();
620 };
621 dialogLifeCycleEvent["didDisappearId"] = didDisappearId;
622 }
623 auto onWillDisappear = paramObject->GetProperty("onWillDisappear");
624 if (!onWillDisappear->IsUndefined() && onWillDisappear->IsFunction()) {
625 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onWillDisappear));
626 auto willDisappearId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc),
627 node = targetNode]() {
628 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
629 ACE_SCORING_EVENT("CalendarDialog.onWillDisappear");
630 PipelineContext::SetCallBackNode(node);
631 func->Execute();
632 };
633 dialogLifeCycleEvent["willDisappearId"] = willDisappearId;
634 }
635 }
636
LifeCycleDialogEvent(const JSCallbackInfo & info)637 std::map<std::string, NG::DialogCancelEvent> JSCalendarPickerDialog::LifeCycleDialogEvent(const JSCallbackInfo& info)
638 {
639 std::map<std::string, NG::DialogCancelEvent> dialogLifeCycleEvent;
640 if (!info[0]->IsObject()) {
641 return dialogLifeCycleEvent;
642 }
643 AppearDialogEvent(info, dialogLifeCycleEvent);
644 DisappearDialogEvent(info, dialogLifeCycleEvent);
645 return dialogLifeCycleEvent;
646 }
647
ParseDate(const JSRef<JSVal> & dateVal)648 PickerDate JSCalendarPickerDialog::ParseDate(const JSRef<JSVal>& dateVal)
649 {
650 auto pickerDate = PickerDate();
651 if (!dateVal->IsObject()) {
652 return pickerDate;
653 }
654 auto dateObj = JSRef<JSObject>::Cast(dateVal);
655
656 auto yearFuncJsVal = dateObj->GetProperty("getFullYear");
657 auto monthFuncJsVal = dateObj->GetProperty("getMonth");
658 auto dateFuncJsVal = dateObj->GetProperty("getDate");
659 if (!(yearFuncJsVal->IsFunction() && monthFuncJsVal->IsFunction() && dateFuncJsVal->IsFunction())) {
660 return pickerDate;
661 }
662 auto yearFunc = JSRef<JSFunc>::Cast(yearFuncJsVal);
663 auto monthFunc = JSRef<JSFunc>::Cast(monthFuncJsVal);
664 auto dateFunc = JSRef<JSFunc>::Cast(dateFuncJsVal);
665 JSRef<JSVal> year = yearFunc->Call(dateObj);
666 JSRef<JSVal> month = monthFunc->Call(dateObj);
667 JSRef<JSVal> date = dateFunc->Call(dateObj);
668
669 if (year->IsNumber() && month->IsNumber() && date->IsNumber()) {
670 pickerDate.SetYear(year->ToNumber<int32_t>());
671 pickerDate.SetMonth(month->ToNumber<int32_t>() + 1); // 0-11 means 1 to 12 months
672 pickerDate.SetDay(date->ToNumber<int32_t>());
673 }
674 return pickerDate;
675 }
676
CalendarPickerDialogShow(const JSRef<JSObject> & paramObj,const std::map<std::string,NG::DialogEvent> & dialogEvent,const std::map<std::string,NG::DialogGestureEvent> & dialogCancelEvent,const std::map<std::string,NG::DialogCancelEvent> & dialogLifeCycleEvent,const std::vector<ButtonInfo> & buttonInfos)677 void JSCalendarPickerDialog::CalendarPickerDialogShow(const JSRef<JSObject>& paramObj,
678 const std::map<std::string, NG::DialogEvent>& dialogEvent,
679 const std::map<std::string, NG::DialogGestureEvent>& dialogCancelEvent,
680 const std::map<std::string, NG::DialogCancelEvent>& dialogLifeCycleEvent,
681 const std::vector<ButtonInfo>& buttonInfos)
682 {
683 auto container = Container::CurrentSafely();
684 CHECK_NULL_VOID(container);
685 auto pipelineContext = AccessibilityManager::DynamicCast<NG::PipelineContext>(container->GetPipelineContext());
686 CHECK_NULL_VOID(pipelineContext);
687 auto executor = pipelineContext->GetTaskExecutor();
688 CHECK_NULL_VOID(executor);
689
690 auto theme = GetTheme<DialogTheme>();
691 CHECK_NULL_VOID(theme);
692 auto calendarTheme = pipelineContext->GetTheme<CalendarTheme>();
693 NG::CalendarSettingData settingData;
694 auto selectedDate = paramObj->GetProperty("selected");
695 auto parseSelectedDate = ParseDate(selectedDate);
696 if (selectedDate->IsObject() && parseSelectedDate.GetYear() != 0) {
697 settingData.selectedDate = parseSelectedDate;
698 }
699
700 CalcDimension radius;
701 if (ParseJsDimensionVpNG(paramObj->GetProperty("hintRadius"), radius)) {
702 settingData.dayRadius = radius;
703 }
704
705 DialogProperties properties;
706 properties.alignment = theme->GetAlignment();
707 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
708 properties.alignment = DialogAlignment::CENTER;
709 }
710
711 auto backgroundColorValue = paramObj->GetProperty("backgroundColor");
712 Color backgroundColor;
713 if (JSViewAbstract::ParseJsColor(backgroundColorValue, backgroundColor)) {
714 properties.backgroundColor = backgroundColor;
715 }
716
717 auto backgroundBlurStyle = paramObj->GetProperty("backgroundBlurStyle");
718 BlurStyleOption styleOption;
719 if (backgroundBlurStyle->IsNumber()) {
720 auto blurStyle = backgroundBlurStyle->ToNumber<int32_t>();
721 if (blurStyle >= static_cast<int>(BlurStyle::NO_MATERIAL) &&
722 blurStyle <= static_cast<int>(BlurStyle::COMPONENT_ULTRA_THICK)) {
723 properties.backgroundBlurStyle = blurStyle;
724 }
725 }
726
727 auto shadowValue = paramObj->GetProperty("shadow");
728 Shadow shadow;
729 if ((shadowValue->IsObject() || shadowValue->IsNumber()) && JSViewAbstract::ParseShadowProps(shadowValue, shadow)) {
730 properties.shadow = shadow;
731 }
732 properties.customStyle = false;
733 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_TWELVE)) {
734 properties.offset = DimensionOffset(Offset(0, -theme->GetMarginBottom().ConvertToPx()));
735 NG::BorderRadiusProperty dialogRadius;
736 dialogRadius.SetRadius(calendarTheme->GetDialogBorderRadius());
737 properties.borderRadius = dialogRadius;
738 }
739
740 auto context = AccessibilityManager::DynamicCast<NG::PipelineContext>(pipelineContext);
741 auto overlayManager = context ? context->GetOverlayManager() : nullptr;
742 executor->PostTask(
743 [properties, settingData, dialogEvent, dialogCancelEvent, dialogLifeCycleEvent, buttonInfos,
744 weak = WeakPtr<NG::OverlayManager>(overlayManager)] {
745 auto overlayManager = weak.Upgrade();
746 CHECK_NULL_VOID(overlayManager);
747 overlayManager->ShowCalendarDialog(
748 properties, settingData, dialogEvent, dialogCancelEvent, dialogLifeCycleEvent, buttonInfos);
749 },
750 TaskExecutor::TaskType::UI, "ArkUIDialogShowCalendarPicker");
751 }
752 } // namespace OHOS::Ace::Framework
753