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