1 /*
2 * Copyright (c) 2021-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 "bridge/declarative_frontend/jsview/js_datepicker.h"
17
18 #include <utility>
19
20 #include "base/log/ace_scoring_log.h"
21 #include "base/utils/utils.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/js_interactable_view.h"
25 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
26 #include "bridge/declarative_frontend/jsview/models/picker_model_impl.h"
27 #include "bridge/declarative_frontend/jsview/models/timepicker_model_impl.h"
28 #include "bridge/declarative_frontend/view_stack_processor.h"
29 #include "core/components/picker/picker_data.h"
30 #include "core/components/picker/picker_date_component.h"
31 #include "core/components/picker/picker_theme.h"
32 #include "core/components/picker/picker_time_component.h"
33 #include "core/components_ng/base/view_stack_processor.h"
34 #include "core/components_ng/pattern/picker/datepicker_model_ng.h"
35 #include "core/components_ng/pattern/time_picker/timepicker_model.h"
36 #include "core/components_ng/pattern/time_picker/timepicker_model_ng.h"
37 #include "core/components_v2/inspector/inspector_constants.h"
38 #include "core/event/ace_event_helper.h"
39 #include "core/pipeline_ng/pipeline_context.h"
40
41 namespace OHOS::Ace {
42 namespace {
43 const DimensionOffset DATEPICKER_OFFSET_DEFAULT_TOP = DimensionOffset(0.0_vp, 40.0_vp);
44 const std::vector<DialogAlignment> DIALOG_ALIGNMENT = { DialogAlignment::TOP, DialogAlignment::CENTER,
45 DialogAlignment::BOTTOM, DialogAlignment::DEFAULT, DialogAlignment::TOP_START, DialogAlignment::TOP_END,
46 DialogAlignment::CENTER_START, DialogAlignment::CENTER_END, DialogAlignment::BOTTOM_START,
47 DialogAlignment::BOTTOM_END };
48 }
49
50 std::unique_ptr<DatePickerModel> DatePickerModel::datePickerInstance_ = nullptr;
51 std::unique_ptr<DatePickerDialogModel> DatePickerDialogModel::datePickerDialogInstance_ = nullptr;
52 std::unique_ptr<TimePickerModel> TimePickerModel::timePickerInstance_ = nullptr;
53 std::unique_ptr<TimePickerDialogModel> TimePickerDialogModel::timePickerDialogInstance_ = nullptr;
54 std::mutex DatePickerModel::mutex_;
55 std::mutex DatePickerDialogModel::mutex_;
56 std::mutex TimePickerModel::mutex_;
57 std::mutex TimePickerDialogModel::mutex_;
58
GetInstance()59 DatePickerModel* DatePickerModel::GetInstance()
60 {
61 if (!datePickerInstance_) {
62 std::lock_guard<std::mutex> lock(mutex_);
63 if (!datePickerInstance_) {
64 #ifdef NG_BUILD
65 datePickerInstance_.reset(new NG::DatePickerModelNG());
66 #else
67 if (Container::IsCurrentUseNewPipeline()) {
68 datePickerInstance_.reset(new NG::DatePickerModelNG());
69 } else {
70 datePickerInstance_.reset(new Framework::DatePickerModelImpl());
71 }
72 #endif
73 }
74 }
75 return datePickerInstance_.get();
76 }
77
GetInstance()78 DatePickerDialogModel* DatePickerDialogModel::GetInstance()
79 {
80 if (!datePickerDialogInstance_) {
81 std::lock_guard<std::mutex> lock(mutex_);
82 if (!datePickerDialogInstance_) {
83 #ifdef NG_BUILD
84 datePickerDialogInstance_.reset(new NG::DatePickerDialogModelNG());
85 #else
86 if (Container::IsCurrentUseNewPipeline()) {
87 datePickerDialogInstance_.reset(new NG::DatePickerDialogModelNG());
88 } else {
89 datePickerDialogInstance_.reset(new Framework::DatePickerDialogModelImpl());
90 }
91 #endif
92 }
93 }
94 return datePickerDialogInstance_.get();
95 }
96
GetInstance()97 TimePickerModel* TimePickerModel::GetInstance()
98 {
99 if (!timePickerInstance_) {
100 std::lock_guard<std::mutex> lock(mutex_);
101 if (!timePickerInstance_) {
102 #ifdef NG_BUILD
103 timePickerInstance_.reset(new NG::TimePickerModelNG());
104 #else
105 if (Container::IsCurrentUseNewPipeline()) {
106 timePickerInstance_.reset(new NG::TimePickerModelNG());
107 } else {
108 timePickerInstance_.reset(new Framework::TimePickerModelImpl());
109 }
110 #endif
111 }
112 }
113 return timePickerInstance_.get();
114 }
115
GetInstance()116 TimePickerDialogModel* TimePickerDialogModel::GetInstance()
117 {
118 if (!timePickerDialogInstance_) {
119 std::lock_guard<std::mutex> lock(mutex_);
120 if (!timePickerDialogInstance_) {
121 #ifdef NG_BUILD
122 timePickerDialogInstance_.reset(new NG::TimePickerDialogModelNG());
123 #else
124 if (Container::IsCurrentUseNewPipeline()) {
125 timePickerDialogInstance_.reset(new NG::TimePickerDialogModelNG());
126 } else {
127 timePickerDialogInstance_.reset(new Framework::TimePickerDialogModelImpl());
128 }
129 #endif
130 }
131 }
132 return timePickerDialogInstance_.get();
133 }
134 } // namespace OHOS::Ace
135
136 namespace OHOS::Ace::Framework {
137 namespace {
DatePickerChangeEventToJSValue(const DatePickerChangeEvent & eventInfo)138 JSRef<JSVal> DatePickerChangeEventToJSValue(const DatePickerChangeEvent& eventInfo)
139 {
140 JSRef<JSObject> obj = JSRef<JSObject>::New();
141 std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(eventInfo.GetSelectedStr());
142 if (!argsPtr) {
143 LOGW("selectedStr is not exist.");
144 return JSRef<JSVal>::Cast(obj);
145 }
146 std::vector<std::string> keys = { "year", "month", "day", "hour", "minute", "second" };
147 for (auto iter = keys.begin(); iter != keys.end(); iter++) {
148 const std::string key = *iter;
149 const auto value = argsPtr->GetValue(key);
150 if (!value || value->ToString().empty()) {
151 LOGI("key[%{public}s] is not exist.", key.c_str());
152 continue;
153 }
154 obj->SetProperty<int32_t>(key.c_str(), value->GetInt());
155 }
156 return JSRef<JSVal>::Cast(obj);
157 }
158
DatePickerDateChangeEventToJSValue(const DatePickerChangeEvent & eventInfo)159 JSRef<JSVal> DatePickerDateChangeEventToJSValue(const DatePickerChangeEvent& eventInfo)
160 {
161 JSRef<JSObject> obj = JSRef<JSObject>::New();
162 std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(eventInfo.GetSelectedStr());
163 if (!argsPtr) {
164 LOGW("selectedStr is not exist.");
165 return JSRef<JSVal>::Cast(obj);
166 }
167 std::tm dateTime = { 0 };
168 auto year = argsPtr->GetValue("year");
169 if (year && year->IsNumber()) {
170 dateTime.tm_year = year->GetInt() - 1900; // local date start from 1900
171 }
172 auto month = argsPtr->GetValue("month");
173 if (month && month->IsNumber()) {
174 dateTime.tm_mon = month->GetInt();
175 }
176 auto day = argsPtr->GetValue("day");
177 if (day && day->IsNumber()) {
178 dateTime.tm_mday = day->GetInt();
179 }
180 auto hour = argsPtr->GetValue("hour");
181 if (hour && hour->IsNumber()) {
182 dateTime.tm_hour = hour->GetInt();
183 }
184 auto minute = argsPtr->GetValue("minute");
185 if (minute && minute->IsNumber()) {
186 dateTime.tm_min = minute->GetInt();
187 }
188
189 auto milliseconds = Date::GetMilliSecondsByDateTime(dateTime);
190 auto dateObj = JSDate::New(milliseconds);
191 return JSRef<JSVal>::Cast(dateObj);
192 }
193 } // namespace
194
JSBind(BindingTarget globalObj)195 void JSDatePicker::JSBind(BindingTarget globalObj)
196 {
197 JSClass<JSDatePicker>::Declare("DatePicker");
198 MethodOptions opt = MethodOptions::NONE;
199 JSClass<JSDatePicker>::StaticMethod("create", &JSDatePicker::Create, opt);
200 JSClass<JSDatePicker>::StaticMethod("lunar", &JSDatePicker::SetLunar);
201 JSClass<JSDatePicker>::StaticMethod("onChange", &JSDatePicker::OnChange);
202 JSClass<JSDatePicker>::StaticMethod("onDateChange", &JSDatePicker::OnDateChange);
203 JSClass<JSDatePicker>::StaticMethod("backgroundColor", &JSDatePicker::PickerBackgroundColor);
204 // keep compatible, need remove after
205 JSClass<JSDatePicker>::StaticMethod("useMilitaryTime", &JSDatePicker::UseMilitaryTime);
206 JSClass<JSDatePicker>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
207 JSClass<JSDatePicker>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
208 JSClass<JSDatePicker>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
209 JSClass<JSDatePicker>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
210 JSClass<JSDatePicker>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
211 JSClass<JSDatePicker>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
212 JSClass<JSDatePicker>::StaticMethod("disappearTextStyle", &JSDatePicker::SetDisappearTextStyle);
213 JSClass<JSDatePicker>::StaticMethod("textStyle", &JSDatePicker::SetTextStyle);
214 JSClass<JSDatePicker>::StaticMethod("selectedTextStyle", &JSDatePicker::SetSelectedTextStyle);
215 JSClass<JSDatePicker>::InheritAndBind<JSViewAbstract>(globalObj);
216 }
217
Create(const JSCallbackInfo & info)218 void JSDatePicker::Create(const JSCallbackInfo& info)
219 {
220 DatePickerType pickerType = DatePickerType::DATE;
221 JSRef<JSObject> paramObject;
222 if (info.Length() >= 1 && info[0]->IsObject()) {
223 paramObject = JSRef<JSObject>::Cast(info[0]);
224 auto type = paramObject->GetProperty("type");
225 if (type->IsNumber()) {
226 pickerType = static_cast<DatePickerType>(type->ToNumber<int32_t>());
227 }
228 }
229 switch (pickerType) {
230 case DatePickerType::TIME: {
231 CreateTimePicker(info, paramObject);
232 break;
233 }
234 case DatePickerType::DATE: {
235 CreateDatePicker(info, paramObject);
236 break;
237 }
238 default: {
239 LOGE("Undefined date picker type.");
240 break;
241 }
242 }
243 }
244
SetLunar(bool isLunar)245 void JSDatePicker::SetLunar(bool isLunar)
246 {
247 DatePickerModel::GetInstance()->SetShowLunar(isLunar);
248 }
249
UseMilitaryTime(bool isUseMilitaryTime)250 void JSDatePicker::UseMilitaryTime(bool isUseMilitaryTime)
251 {
252 DatePickerModel::GetInstance()->SetHour24(isUseMilitaryTime);
253 }
254
ParseTextProperties(const JSRef<JSObject> & paramObj,NG::PickerTextProperties & result)255 void JSDatePicker::ParseTextProperties(const JSRef<JSObject>& paramObj, NG::PickerTextProperties& result)
256 {
257 auto disappearProperty = paramObj->GetProperty("disappearTextStyle");
258 auto normalProperty = paramObj->GetProperty("textStyle");
259 auto selectedProperty = paramObj->GetProperty("selectedTextStyle");
260
261 if (!disappearProperty->IsNull() && disappearProperty->IsObject()) {
262 JSRef<JSObject> disappearObj = JSRef<JSObject>::Cast(disappearProperty);
263 JSDatePicker::ParseTextStyle(disappearObj, result.disappearTextStyle_);
264 }
265
266 if (!normalProperty->IsNull() && normalProperty->IsObject()) {
267 JSRef<JSObject> noramlObj = JSRef<JSObject>::Cast(normalProperty);
268 JSDatePicker::ParseTextStyle(noramlObj, result.normalTextStyle_);
269 }
270
271 if (!selectedProperty->IsNull() && selectedProperty->IsObject()) {
272 JSRef<JSObject> selectedObj = JSRef<JSObject>::Cast(selectedProperty);
273 JSDatePicker::ParseTextStyle(selectedObj, result.selectedTextStyle_);
274 }
275 }
276
ParseTextStyle(const JSRef<JSObject> & paramObj,NG::PickerTextStyle & textStyle)277 void JSDatePicker::ParseTextStyle(const JSRef<JSObject>& paramObj, NG::PickerTextStyle& textStyle)
278 {
279 auto fontColor = paramObj->GetProperty("color");
280 auto fontOptions = paramObj->GetProperty("font");
281
282 Color textColor;
283 if (JSViewAbstract::ParseJsColor(fontColor, textColor)) {
284 textStyle.textColor = textColor;
285 }
286
287 if (!fontOptions->IsObject()) {
288 return;
289 }
290 JSRef<JSObject> fontObj = JSRef<JSObject>::Cast(fontOptions);
291 auto fontSize = fontObj->GetProperty("size");
292 auto fontWeight = fontObj->GetProperty("weight");
293 auto fontFamily = fontObj->GetProperty("family");
294 auto fontStyle = fontObj->GetProperty("style");
295 if (fontSize->IsNull() || fontSize->IsUndefined()) {
296 textStyle.fontSize = Dimension(-1);
297 } else {
298 CalcDimension size;
299 if (!ParseJsDimensionFp(fontSize, size) || size.Unit() == DimensionUnit::PERCENT) {
300 textStyle.fontSize = Dimension(-1);
301 LOGW("Parse to dimension FP failed.");
302 } else {
303 textStyle.fontSize = size;
304 }
305 }
306
307 if (!fontWeight->IsNull() && !fontWeight->IsUndefined()) {
308 std::string weight;
309 if (fontWeight->IsNumber()) {
310 weight = std::to_string(fontWeight->ToNumber<int32_t>());
311 } else {
312 ParseJsString(fontWeight, weight);
313 }
314 textStyle.fontWeight = ConvertStrToFontWeight(weight);
315 }
316
317 if (!fontFamily->IsNull() && !fontFamily->IsUndefined()) {
318 std::vector<std::string> families;
319 if (ParseJsFontFamilies(fontFamily, families)) {
320 textStyle.fontFamily = families;
321 }
322 }
323
324 if (fontStyle->IsNumber()) {
325 auto style = fontStyle->ToNumber<int32_t>();
326 if (style < 0 || style > 1) {
327 LOGE("Text fontStyle(%d) is invalid value", style);
328 return;
329 }
330 textStyle.fontStyle = static_cast<FontStyle>(style);
331 }
332 }
333
SetDisappearTextStyle(const JSCallbackInfo & info)334 void JSDatePicker::SetDisappearTextStyle(const JSCallbackInfo& info)
335 {
336 auto theme = GetTheme<PickerTheme>();
337 if (!theme) {
338 LOGE("datePicker Theme is null");
339 return;
340 }
341 NG::PickerTextStyle textStyle;
342 if (info.Length() < 1 || !info[0]->IsObject()) {
343 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
344 } else {
345 JSDatePicker::ParseTextStyle(info[0], textStyle);
346 }
347 DatePickerModel::GetInstance()->SetDisappearTextStyle(theme, textStyle);
348 }
349
SetTextStyle(const JSCallbackInfo & info)350 void JSDatePicker::SetTextStyle(const JSCallbackInfo& info)
351 {
352 auto theme = GetTheme<PickerTheme>();
353 if (!theme) {
354 LOGE("datePicker Theme is null");
355 return;
356 }
357 NG::PickerTextStyle textStyle;
358 if (info.Length() < 1 || !info[0]->IsObject()) {
359 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
360 } else {
361 JSDatePicker::ParseTextStyle(info[0], textStyle);
362 }
363 DatePickerModel::GetInstance()->SetNormalTextStyle(theme, textStyle);
364 }
365
SetSelectedTextStyle(const JSCallbackInfo & info)366 void JSDatePicker::SetSelectedTextStyle(const JSCallbackInfo& info)
367 {
368 auto theme = GetTheme<PickerTheme>();
369 if (!theme) {
370 LOGE("datePicker Theme is null");
371 return;
372 }
373 NG::PickerTextStyle textStyle;
374 if (info.Length() < 1 || !info[0]->IsObject()) {
375 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
376 } else {
377 JSDatePicker::ParseTextStyle(info[0], textStyle);
378 }
379 DatePickerModel::GetInstance()->SetSelectedTextStyle(theme, textStyle);
380 }
381
OnChange(const JSCallbackInfo & info)382 void JSDatePicker::OnChange(const JSCallbackInfo& info)
383 {
384 if (info.Length() < 1 || !info[0]->IsFunction()) {
385 LOGI("info not function");
386 return;
387 }
388
389 auto jsFunc = AceType::MakeRefPtr<JsEventFunction<DatePickerChangeEvent, 1>>(
390 JSRef<JSFunc>::Cast(info[0]), DatePickerChangeEventToJSValue);
391 auto onChange = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](const BaseEventInfo* info) {
392 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
393 ACE_SCORING_EVENT("datePicker.onChange");
394 const auto* eventInfo = TypeInfoHelper::DynamicCast<DatePickerChangeEvent>(info);
395 func->Execute(*eventInfo);
396 };
397 DatePickerModel::GetInstance()->SetOnChange(std::move(onChange));
398 }
399
OnDateChange(const JSCallbackInfo & info)400 void JSDatePicker::OnDateChange(const JSCallbackInfo& info)
401 {
402 if (info.Length() < 1 || !info[0]->IsFunction()) {
403 LOGI("info not function");
404 return;
405 }
406 auto jsFunc = AceType::MakeRefPtr<JsEventFunction<DatePickerChangeEvent, 1>>(
407 JSRef<JSFunc>::Cast(info[0]), DatePickerDateChangeEventToJSValue);
408 auto onDateChange = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](const BaseEventInfo* info) {
409 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
410 ACE_SCORING_EVENT("datePicker.onDateChange");
411 const auto* eventInfo = TypeInfoHelper::DynamicCast<DatePickerChangeEvent>(info);
412 func->Execute(*eventInfo);
413 };
414 DatePickerModel::GetInstance()->SetOnDateChange(std::move(onDateChange));
415 }
416
OnChange(const JSCallbackInfo & info)417 void JSTimePicker::OnChange(const JSCallbackInfo& info)
418 {
419 if (info.Length() < 1 || !info[0]->IsFunction()) {
420 LOGI("info not function");
421 return;
422 }
423
424 auto jsFunc = AceType::MakeRefPtr<JsEventFunction<DatePickerChangeEvent, 1>>(
425 JSRef<JSFunc>::Cast(info[0]), DatePickerChangeEventToJSValue);
426 auto onChange = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](const BaseEventInfo* index) {
427 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
428 ACE_SCORING_EVENT("datePicker.onChange");
429 const auto* eventInfo = TypeInfoHelper::DynamicCast<DatePickerChangeEvent>(index);
430 func->Execute(*eventInfo);
431 };
432 TimePickerModel::GetInstance()->SetOnChange(std::move(onChange));
433 }
434
PickerBackgroundColor(const JSCallbackInfo & info)435 void JSDatePicker::PickerBackgroundColor(const JSCallbackInfo& info)
436 {
437 JSViewAbstract::JsBackgroundColor(info);
438
439 if (info.Length() < 1) {
440 LOGI("The arg(PickerBackgroundColor) is wrong, it is supposed to have at least 1 argument");
441 return;
442 }
443 Color backgroundColor;
444 if (!ParseJsColor(info[0], backgroundColor)) {
445 LOGI("the info[0] is null");
446 return;
447 }
448 DatePickerModel::GetInstance()->SetBackgroundColor(backgroundColor);
449 }
450
ParseDate(const JSRef<JSVal> & dateVal)451 PickerDate JSDatePicker::ParseDate(const JSRef<JSVal>& dateVal)
452 {
453 auto pickerDate = PickerDate();
454 if (!dateVal->IsObject()) {
455 return pickerDate;
456 }
457 auto dateObj = JSRef<JSObject>::Cast(dateVal);
458 auto yearFuncJsVal = dateObj->GetProperty("getFullYear");
459 auto monthFuncJsVal = dateObj->GetProperty("getMonth");
460 auto dateFuncJsVal = dateObj->GetProperty("getDate");
461 if (!(yearFuncJsVal->IsFunction() && monthFuncJsVal->IsFunction() && dateFuncJsVal->IsFunction())) {
462 return pickerDate;
463 }
464 auto yearFunc = JSRef<JSFunc>::Cast(yearFuncJsVal);
465 auto monthFunc = JSRef<JSFunc>::Cast(monthFuncJsVal);
466 auto dateFunc = JSRef<JSFunc>::Cast(dateFuncJsVal);
467 JSRef<JSVal> year = yearFunc->Call(dateObj);
468 JSRef<JSVal> month = monthFunc->Call(dateObj);
469 JSRef<JSVal> date = dateFunc->Call(dateObj);
470
471 if (year->IsNumber() && month->IsNumber() && date->IsNumber()) {
472 pickerDate.SetYear(year->ToNumber<int32_t>());
473 pickerDate.SetMonth(month->ToNumber<int32_t>() + 1); // 0-11 means 1 to 12 months
474 pickerDate.SetDay(date->ToNumber<int32_t>());
475 }
476 return pickerDate;
477 }
478
ParseTime(const JSRef<JSVal> & timeVal)479 PickerTime JSDatePicker::ParseTime(const JSRef<JSVal>& timeVal)
480 {
481 auto pickerTime = PickerTime();
482 if (!timeVal->IsObject()) {
483 return pickerTime;
484 }
485 auto timeObj = JSRef<JSObject>::Cast(timeVal);
486 auto hourFuncJsVal = timeObj->GetProperty("getHours");
487 auto minuteFuncJsVal = timeObj->GetProperty("getMinutes");
488 auto secondFuncJsVal = timeObj->GetProperty("getSeconds");
489 if (!(hourFuncJsVal->IsFunction() && minuteFuncJsVal->IsFunction() && secondFuncJsVal->IsFunction())) {
490 return pickerTime;
491 }
492 auto hourFunc = JSRef<JSFunc>::Cast(hourFuncJsVal);
493 auto minuteFunc = JSRef<JSFunc>::Cast(minuteFuncJsVal);
494 auto secondFunc = JSRef<JSFunc>::Cast(secondFuncJsVal);
495 JSRef<JSVal> hour = hourFunc->Call(timeObj);
496 JSRef<JSVal> minute = minuteFunc->Call(timeObj);
497 JSRef<JSVal> second = secondFunc->Call(timeObj);
498
499 if (hour->IsNumber() && minute->IsNumber() && second->IsNumber()) {
500 pickerTime.SetHour(hour->ToNumber<int32_t>());
501 pickerTime.SetMinute(minute->ToNumber<int32_t>());
502 pickerTime.SetSecond(second->ToNumber<int32_t>());
503 }
504 return pickerTime;
505 }
506
ParseSelectedDateTimeObject(const JSCallbackInfo & info,const JSRef<JSObject> & selectedObject,bool isDatePicker)507 void ParseSelectedDateTimeObject(const JSCallbackInfo& info, const JSRef<JSObject>& selectedObject, bool isDatePicker)
508 {
509 JSRef<JSVal> changeEventVal = selectedObject->GetProperty("changeEvent");
510 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(changeEventVal));
511 auto changeEvent = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](const BaseEventInfo* info) {
512 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
513 ACE_SCORING_EVENT("DatePicker.SelectedDateTimeChangeEvent");
514 const auto* eventInfo = TypeInfoHelper::DynamicCast<DatePickerChangeEvent>(info);
515 CHECK_NULL_VOID(eventInfo);
516 auto selectedStr = eventInfo->GetSelectedStr();
517 auto sourceJson = JsonUtil::ParseJsonString(selectedStr);
518 if (!sourceJson || sourceJson->IsNull()) {
519 LOGE("invalid selected date value.");
520 return;
521 }
522
523 std::tm dateTime = { 0 };
524 auto year = sourceJson->GetValue("year");
525 if (year && year->IsNumber()) {
526 dateTime.tm_year = year->GetInt() - 1900; // local date start from 1900
527 }
528 auto month = sourceJson->GetValue("month");
529 if (month && month->IsNumber()) {
530 dateTime.tm_mon = month->GetInt();
531 }
532 auto day = sourceJson->GetValue("day");
533 if (day && day->IsNumber()) {
534 dateTime.tm_mday = day->GetInt();
535 }
536 auto hour = sourceJson->GetValue("hour");
537 if (hour && hour->IsNumber()) {
538 dateTime.tm_hour = hour->GetInt();
539 }
540 auto minute = sourceJson->GetValue("minute");
541 if (minute && minute->IsNumber()) {
542 dateTime.tm_min = minute->GetInt();
543 }
544 auto milliseconds = Date::GetMilliSecondsByDateTime(dateTime);
545 auto dateObj = JSDate::New(milliseconds);
546 func->ExecuteJS(1, &dateObj);
547 };
548 if (isDatePicker) {
549 DatePickerModel::GetInstance()->SetChangeEvent(std::move(changeEvent));
550 } else {
551 TimePickerModel::GetInstance()->SetChangeEvent(std::move(changeEvent));
552 }
553 }
554
CreateDatePicker(const JSCallbackInfo & info,const JSRef<JSObject> & paramObj)555 void JSDatePicker::CreateDatePicker(const JSCallbackInfo& info, const JSRef<JSObject>& paramObj)
556 {
557 auto theme = GetTheme<PickerTheme>();
558 CHECK_NULL_VOID(theme);
559 JSRef<JSVal> startDate;
560 JSRef<JSVal> endDate;
561 JSRef<JSVal> selectedDate;
562 if (!paramObj->IsUndefined()) {
563 startDate = paramObj->GetProperty("start");
564 endDate = paramObj->GetProperty("end");
565 selectedDate = paramObj->GetProperty("selected");
566 }
567 auto parseStartDate = ParseDate(startDate);
568 auto parseEndDate = ParseDate(endDate);
569 if (parseStartDate.GetYear() <= 0) {
570 parseStartDate = theme->GetDefaultStartDate();
571 }
572 if (parseEndDate.GetYear() <= 0) {
573 parseEndDate = theme->GetDefaultEndDate();
574 }
575 auto startDays = parseStartDate.ToDays();
576 auto endDays = parseEndDate.ToDays();
577 if (startDays > endDays) {
578 parseStartDate = theme->GetDefaultStartDate();
579 parseEndDate = theme->GetDefaultEndDate();
580 }
581 DatePickerModel::GetInstance()->CreateDatePicker(theme);
582 if (startDate->IsObject()) {
583 DatePickerModel::GetInstance()->SetStartDate(parseStartDate);
584 }
585 if (endDate->IsObject()) {
586 DatePickerModel::GetInstance()->SetEndDate(parseEndDate);
587 }
588 if (selectedDate->IsObject()) {
589 JSRef<JSObject> selectedDateObj = JSRef<JSObject>::Cast(selectedDate);
590 JSRef<JSVal> changeEventVal = selectedDateObj->GetProperty("changeEvent");
591 PickerDate parseSelectedDate;
592 if (!changeEventVal->IsUndefined() && changeEventVal->IsFunction()) {
593 ParseSelectedDateTimeObject(info, selectedDateObj, true);
594 parseSelectedDate = ParseDate(selectedDateObj->GetProperty("value"));
595 } else {
596 parseSelectedDate = ParseDate(selectedDate);
597 }
598 DatePickerModel::GetInstance()->SetSelectedDate(parseSelectedDate);
599 }
600 SetDefaultAttributes();
601 }
602
SetDefaultAttributes()603 void JSDatePicker::SetDefaultAttributes()
604 {
605 auto theme = GetTheme<PickerTheme>();
606 if (!theme) {
607 LOGE("datePicker Theme is null");
608 return;
609 }
610 NG::PickerTextStyle textStyle;
611 auto selectedStyle = theme->GetOptionStyle(true, false);
612 textStyle.textColor = selectedStyle.GetTextColor();
613 textStyle.fontSize = selectedStyle.GetFontSize();
614 textStyle.fontWeight = selectedStyle.GetFontWeight();
615 DatePickerModel::GetInstance()->SetSelectedTextStyle(theme, textStyle);
616
617 auto disappearStyle = theme->GetDisappearOptionStyle();
618 textStyle.textColor = disappearStyle.GetTextColor();
619 textStyle.fontSize = disappearStyle.GetFontSize();
620 textStyle.fontWeight = disappearStyle.GetFontWeight();
621 DatePickerModel::GetInstance()->SetDisappearTextStyle(theme, textStyle);
622
623 auto normalStyle = theme->GetOptionStyle(false, false);
624 textStyle.textColor = normalStyle.GetTextColor();
625 textStyle.fontSize = normalStyle.GetFontSize();
626 textStyle.fontWeight = normalStyle.GetFontWeight();
627 DatePickerModel::GetInstance()->SetNormalTextStyle(theme, textStyle);
628 }
629
CreateTimePicker(const JSCallbackInfo & info,const JSRef<JSObject> & paramObj)630 void JSDatePicker::CreateTimePicker(const JSCallbackInfo& info, const JSRef<JSObject>& paramObj)
631 {
632 auto theme = GetTheme<PickerTheme>();
633 if (!theme) {
634 LOGE("timePicker Theme is null");
635 return;
636 }
637 DatePickerModel::GetInstance()->CreateTimePicker(theme);
638 auto selectedTime = paramObj->GetProperty("selected");
639 if (selectedTime->IsObject()) {
640 JSRef<JSObject> selectedTimeObj = JSRef<JSObject>::Cast(selectedTime);
641 JSRef<JSVal> changeEventVal = selectedTimeObj->GetProperty("changeEvent");
642 if (!changeEventVal->IsUndefined() && changeEventVal->IsFunction()) {
643 ParseSelectedDateTimeObject(info, selectedTimeObj, true);
644 auto parseSelectedTime = ParseTime(selectedTimeObj->GetProperty("value"));
645 DatePickerModel::GetInstance()->SetSelectedTime(parseSelectedTime);
646 } else {
647 DatePickerModel::GetInstance()->SetSelectedTime(ParseTime(selectedTime));
648 }
649 }
650 }
651
JSBind(BindingTarget globalObj)652 void JSDatePickerDialog::JSBind(BindingTarget globalObj)
653 {
654 JSClass<JSDatePickerDialog>::Declare("DatePickerDialog");
655 JSClass<JSDatePickerDialog>::StaticMethod("show", &JSDatePickerDialog::Show);
656
657 JSClass<JSDatePickerDialog>::Bind<>(globalObj);
658 }
659
Show(const JSCallbackInfo & info)660 void JSDatePickerDialog::Show(const JSCallbackInfo& info)
661 {
662 auto scopedDelegate = EngineHelper::GetCurrentDelegate();
663 if (!scopedDelegate) {
664 // this case usually means there is no foreground container, need to figure out the reason.
665 LOGE("scopedDelegate is null, please check");
666 return;
667 }
668 if (info.Length() < 1 || !info[0]->IsObject()) {
669 LOGE("DatePicker Show dialog error, info is non-valid");
670 return;
671 }
672 auto theme = GetTheme<PickerTheme>();
673 CHECK_NULL_VOID(theme);
674
675 auto paramObject = JSRef<JSObject>::Cast(info[0]);
676 DatePickerType pickerType = DatePickerType::DATE;
677 auto type = paramObject->GetProperty("type");
678 if (type->IsNumber()) {
679 pickerType = static_cast<DatePickerType>(type->ToNumber<int32_t>());
680 }
681 std::function<void()> cancelEvent;
682 std::function<void(const std::string&)> acceptEvent;
683 std::function<void(const std::string&)> changeEvent;
684 std::function<void(const std::string&)> dateChangeEvent;
685 std::function<void(const std::string&)> dateAcceptEvent;
686 auto onChange = paramObject->GetProperty("onChange");
687 if (!onChange->IsUndefined() && onChange->IsFunction()) {
688 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onChange));
689 changeEvent = [execCtx = info.GetExecutionContext(), type = pickerType, func = std::move(jsFunc)](
690 const std::string& info) {
691 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
692 std::vector<std::string> keys;
693 keys = { "year", "month", "day" };
694 ACE_SCORING_EVENT("DatePickerDialog.onChange");
695 func->Execute(keys, info);
696 };
697 }
698 auto onAccept = paramObject->GetProperty("onAccept");
699 if (!onAccept->IsUndefined() && onAccept->IsFunction()) {
700 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onAccept));
701 acceptEvent = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](const std::string& info) {
702 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
703 std::vector<std::string> keys = { "year", "month", "day", "hour", "minute", "second" };
704 ACE_SCORING_EVENT("DatePickerDialog.onAccept");
705 func->Execute(keys, info);
706 };
707 }
708 auto onCancel = paramObject->GetProperty("onCancel");
709 if (!onCancel->IsUndefined() && onCancel->IsFunction()) {
710 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onCancel));
711 cancelEvent = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)]() {
712 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
713 ACE_SCORING_EVENT("DatePickerDialog.onCancel");
714 func->Execute();
715 };
716 }
717 auto onDateChange = paramObject->GetProperty("onDateChange");
718 if (!onDateChange->IsUndefined() && onDateChange->IsFunction()) {
719 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onDateChange));
720 dateChangeEvent = [execCtx = info.GetExecutionContext(), type = pickerType, func = std::move(jsFunc)](
721 const std::string& info) {
722 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
723 ACE_SCORING_EVENT("DatePickerDialog.onDateChange");
724 auto selectedJson = JsonUtil::ParseJsonString(info);
725 if (!selectedJson || selectedJson->IsNull()) {
726 return;
727 }
728 std::tm dateTime = { 0 };
729 auto year = selectedJson->GetValue("year");
730 if (year && year->IsNumber()) {
731 dateTime.tm_year = year->GetInt() - 1900; // local date start from 1900
732 }
733 auto month = selectedJson->GetValue("month");
734 if (month && month->IsNumber()) {
735 dateTime.tm_mon = month->GetInt();
736 }
737 auto day = selectedJson->GetValue("day");
738 if (day && day->IsNumber()) {
739 dateTime.tm_mday = day->GetInt();
740 }
741 auto hour = selectedJson->GetValue("hour");
742 if (hour && hour->IsNumber()) {
743 dateTime.tm_hour = hour->GetInt();
744 }
745 auto minute = selectedJson->GetValue("minute");
746 if (minute && minute->IsNumber()) {
747 dateTime.tm_min = minute->GetInt();
748 }
749
750 auto milliseconds = Date::GetMilliSecondsByDateTime(dateTime);
751 auto dateObj = JSDate::New(milliseconds);
752 func->ExecuteJS(1, &dateObj);
753 };
754 }
755 auto onDateAccept = paramObject->GetProperty("onDateAccept");
756 if (!onDateAccept->IsUndefined() && onDateAccept->IsFunction()) {
757 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onDateAccept));
758 dateAcceptEvent = [execCtx = info.GetExecutionContext(), type = pickerType, func = std::move(jsFunc)](
759 const std::string& info) {
760 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
761 ACE_SCORING_EVENT("DatePickerDialog.onDateAccept");
762 auto selectedJson = JsonUtil::ParseJsonString(info);
763 if (!selectedJson || selectedJson->IsNull()) {
764 return;
765 }
766 std::tm dateTime = { 0 };
767 auto year = selectedJson->GetValue("year");
768 if (year && year->IsNumber()) {
769 dateTime.tm_year = year->GetInt() - 1900; // local date start from 1900
770 }
771 auto month = selectedJson->GetValue("month");
772 if (month && month->IsNumber()) {
773 dateTime.tm_mon = month->GetInt();
774 }
775 auto day = selectedJson->GetValue("day");
776 if (day && day->IsNumber()) {
777 dateTime.tm_mday = day->GetInt();
778 }
779 auto hour = selectedJson->GetValue("hour");
780 if (hour && hour->IsNumber()) {
781 dateTime.tm_hour = hour->GetInt();
782 }
783 auto minute = selectedJson->GetValue("minute");
784 if (minute && minute->IsNumber()) {
785 dateTime.tm_min = minute->GetInt();
786 }
787
788 auto milliseconds = Date::GetMilliSecondsByDateTime(dateTime);
789 auto dateObj = JSDate::New(milliseconds);
790 func->ExecuteJS(1, &dateObj);
791 };
792 }
793 NG::DatePickerSettingData settingData;
794 PickerDialogInfo pickerDialog;
795 auto startDate = paramObject->GetProperty("start");
796 if (startDate->IsObject()) {
797 pickerDialog.isStartDate = true;
798 }
799 auto endDate = paramObject->GetProperty("end");
800 if (endDate->IsObject()) {
801 pickerDialog.isEndDate = true;
802 }
803 auto selectedDate = paramObject->GetProperty("selected");
804 if (selectedDate->IsObject()) {
805 pickerDialog.isSelectedDate = true;
806 }
807 auto lunar = paramObject->GetProperty("lunar");
808 auto lunarSwitch = paramObject->GetProperty("lunarSwitch");
809 auto sTime = paramObject->GetProperty("showTime");
810 auto useMilitary = paramObject->GetProperty("useMilitaryTime");
811 settingData.isLunar = lunar->ToBoolean();
812 settingData.lunarswitch = lunarSwitch->ToBoolean();
813 settingData.showTime = sTime->ToBoolean();
814 settingData.useMilitary = useMilitary->ToBoolean();
815 auto parseStartDate = ParseDate(startDate);
816 auto parseEndDate = ParseDate(endDate);
817 if (parseStartDate.GetYear() <= 0) {
818 parseStartDate = theme->GetDefaultStartDate();
819 }
820 if (parseEndDate.GetYear() <= 0) {
821 parseEndDate = theme->GetDefaultEndDate();
822 }
823 auto startDays = parseStartDate.ToDays();
824 auto endDays = parseEndDate.ToDays();
825 if (startDays > endDays) {
826 parseStartDate = theme->GetDefaultStartDate();
827 parseEndDate = theme->GetDefaultEndDate();
828 }
829 pickerDialog.parseStartDate = parseStartDate;
830 pickerDialog.parseEndDate = parseEndDate;
831 pickerDialog.parseSelectedDate = ParseDate(selectedDate);
832 pickerDialog.pickerTime = ParseTime(selectedDate);
833 JSDatePicker::ParseTextProperties(paramObject, settingData.properties);
834
835 // Parse alignment
836 auto alignmentValue = paramObject->GetProperty("alignment");
837 if (alignmentValue->IsNumber()) {
838 auto alignment = alignmentValue->ToNumber<int32_t>();
839 if (alignment >= 0 && alignment <= static_cast<int32_t>(DIALOG_ALIGNMENT.size())) {
840 pickerDialog.alignment = DIALOG_ALIGNMENT[alignment];
841 }
842 if (alignment == static_cast<int32_t>(DialogAlignment::TOP) ||
843 alignment == static_cast<int32_t>(DialogAlignment::TOP_START) ||
844 alignment == static_cast<int32_t>(DialogAlignment::TOP_END)) {
845 pickerDialog.offset = DATEPICKER_OFFSET_DEFAULT_TOP;
846 }
847 }
848
849 // Parse offset
850 auto offsetValue = paramObject->GetProperty("offset");
851 if (offsetValue->IsObject()) {
852 auto offsetObj = JSRef<JSObject>::Cast(offsetValue);
853 CalcDimension dx;
854 auto dxValue = offsetObj->GetProperty("dx");
855 ParseJsDimensionVp(dxValue, dx);
856 CalcDimension dy;
857 auto dyValue = offsetObj->GetProperty("dy");
858 ParseJsDimensionVp(dyValue, dy);
859 pickerDialog.offset = DimensionOffset(dx, dy);
860 }
861
862 // Parse maskRect.
863 auto maskRectValue = paramObject->GetProperty("maskRect");
864 DimensionRect maskRect;
865 if (JSViewAbstract::ParseJsDimensionRect(maskRectValue, maskRect)) {
866 pickerDialog.maskRect = maskRect;
867 }
868
869 DatePickerDialogModel::GetInstance()->SetDatePickerDialogShow(
870 pickerDialog, settingData, std::move(cancelEvent), std::move(acceptEvent), std::move(changeEvent),
871 std::move(dateAcceptEvent), std::move(dateChangeEvent), pickerType);
872 }
873
DatePickerDialogShow(const JSRef<JSObject> & paramObj,const std::map<std::string,NG::DialogEvent> & dialogEvent,const std::map<std::string,NG::DialogGestureEvent> & dialogCancelEvent)874 void JSDatePickerDialog::DatePickerDialogShow(const JSRef<JSObject>& paramObj,
875 const std::map<std::string, NG::DialogEvent>& dialogEvent,
876 const std::map<std::string, NG::DialogGestureEvent>& dialogCancelEvent)
877 {
878 auto container = Container::Current();
879 if (!container) {
880 return;
881 }
882 auto pipelineContext = AccessibilityManager::DynamicCast<NG::PipelineContext>(container->GetPipelineContext());
883 if (!pipelineContext) {
884 return;
885 }
886
887 auto executor = pipelineContext->GetTaskExecutor();
888 if (!executor) {
889 return;
890 }
891
892 NG::DatePickerSettingData settingData;
893 auto startDate = paramObj->GetProperty("start");
894 auto endDate = paramObj->GetProperty("end");
895 auto selectedDate = paramObj->GetProperty("selected");
896 auto lunar = paramObj->GetProperty("lunar");
897 auto sTime = paramObj->GetProperty("showTime");
898 auto useMilitary = paramObj->GetProperty("useMilitaryTime");
899 settingData.isLunar = lunar->ToBoolean();
900 settingData.showTime = sTime->ToBoolean();
901 settingData.useMilitary = useMilitary->ToBoolean();
902 auto parseStartDate = ParseDate(startDate);
903 auto parseEndDate = ParseDate(endDate);
904 auto parseSelectedDate = ParseDate(selectedDate);
905 auto startDays = parseStartDate.ToDays();
906 auto endDays = parseEndDate.ToDays();
907 auto selectedDays = parseSelectedDate.ToDays();
908 if (startDays > endDays || selectedDays < startDays || selectedDays > endDays) {
909 LOGE("date error");
910 }
911
912 auto theme = GetTheme<DialogTheme>();
913 if (!theme) {
914 LOGE("DialogTheme is null");
915 return;
916 }
917
918 ButtonInfo buttonInfo;
919 DialogProperties properties;
920 if (SystemProperties::GetDeviceType() == DeviceType::PHONE) {
921 properties.alignment = DialogAlignment::BOTTOM;
922 } else {
923 properties.alignment = DialogAlignment::CENTER;
924 }
925 properties.customStyle = false;
926 properties.offset = DimensionOffset(Offset(0, -theme->GetMarginBottom().ConvertToPx()));
927
928 std::map<std::string, PickerDate> datePickerProperty;
929 std::map<std::string, PickerTime> timePickerProperty;
930 if (startDate->IsObject()) {
931 settingData.datePickerProperty["start"] = parseStartDate;
932 }
933 if (endDate->IsObject()) {
934 settingData.datePickerProperty["end"] = parseEndDate;
935 }
936 if (selectedDate->IsObject()) {
937 settingData.datePickerProperty["selected"] = parseSelectedDate;
938 settingData.timePickerProperty["selected"] = ParseTime(selectedDate);
939 }
940
941 JSDatePicker::ParseTextProperties(paramObj, settingData.properties);
942 auto context = AccessibilityManager::DynamicCast<NG::PipelineContext>(pipelineContext);
943 auto overlayManager = context ? context->GetOverlayManager() : nullptr;
944 executor->PostTask(
945 [properties, settingData, dialogEvent, dialogCancelEvent, weak = WeakPtr<NG::OverlayManager>(overlayManager)] {
946 auto overlayManager = weak.Upgrade();
947 CHECK_NULL_VOID(overlayManager);
948 overlayManager->ShowDateDialog(properties, settingData, dialogEvent, dialogCancelEvent);
949 },
950 TaskExecutor::TaskType::UI);
951 }
952
CreateDatePicker(RefPtr<Component> & component,const JSRef<JSObject> & paramObj)953 void JSDatePickerDialog::CreateDatePicker(RefPtr<Component>& component, const JSRef<JSObject>& paramObj)
954 {
955 auto datePicker = AceType::MakeRefPtr<PickerDateComponent>();
956 auto startDate = paramObj->GetProperty("start");
957 auto endDate = paramObj->GetProperty("end");
958 auto selectedDate = paramObj->GetProperty("selected");
959 auto lunar = paramObj->GetProperty("lunar");
960 bool isLunar = lunar->ToBoolean();
961 auto parseStartDate = ParseDate(startDate);
962 auto parseEndDate = ParseDate(endDate);
963 auto parseSelectedDate = ParseDate(selectedDate);
964 auto startDays = parseStartDate.ToDays();
965 auto endDays = parseEndDate.ToDays();
966 auto selectedDays = parseSelectedDate.ToDays();
967 if (startDays > endDays) {
968 LOGW("startDate and endDate error");
969 parseStartDate.SetYear(0);
970 parseEndDate.SetYear(0);
971 }
972 if (selectedDays < startDays || selectedDays > endDays) {
973 LOGW("selectedDate error");
974 }
975 if (startDate->IsObject()) {
976 datePicker->SetStartDate(parseStartDate);
977 }
978 if (endDate->IsObject()) {
979 datePicker->SetEndDate(parseEndDate);
980 }
981 if (selectedDate->IsObject()) {
982 datePicker->SetSelectedDate(parseSelectedDate);
983 }
984 datePicker->SetIsDialog(true);
985 datePicker->SetIsCreateDialogComponent(true);
986 datePicker->SetShowLunar(isLunar);
987
988 component = datePicker;
989 }
990
CreateTimePicker(RefPtr<Component> & component,const JSRef<JSObject> & paramObj)991 void JSDatePickerDialog::CreateTimePicker(RefPtr<Component>& component, const JSRef<JSObject>& paramObj)
992 {
993 auto timePicker = AceType::MakeRefPtr<PickerTimeComponent>();
994 auto selectedTime = paramObj->GetProperty("selected");
995 auto useMilitaryTime = paramObj->GetProperty("useMilitaryTime");
996 bool isUseMilitaryTime = useMilitaryTime->ToBoolean();
997 if (selectedTime->IsObject()) {
998 timePicker->SetSelectedTime(ParseTime(selectedTime));
999 }
1000 timePicker->SetIsDialog(true);
1001 timePicker->SetIsCreateDialogComponent(true);
1002 timePicker->SetHour24(isUseMilitaryTime);
1003 component = timePicker;
1004 }
1005
ParseDate(const JSRef<JSVal> & dateVal)1006 PickerDate JSDatePickerDialog::ParseDate(const JSRef<JSVal>& dateVal)
1007 {
1008 auto pickerDate = PickerDate();
1009 if (!dateVal->IsObject()) {
1010 return pickerDate;
1011 }
1012 auto dateObj = JSRef<JSObject>::Cast(dateVal);
1013 auto yearFunc = JSRef<JSFunc>::Cast(dateObj->GetProperty("getFullYear"));
1014 auto monthFunc = JSRef<JSFunc>::Cast(dateObj->GetProperty("getMonth"));
1015 auto dateFunc = JSRef<JSFunc>::Cast(dateObj->GetProperty("getDate"));
1016 JSRef<JSVal> year = yearFunc->Call(dateObj);
1017 JSRef<JSVal> month = monthFunc->Call(dateObj);
1018 JSRef<JSVal> date = dateFunc->Call(dateObj);
1019
1020 if (year->IsNumber() && month->IsNumber() && date->IsNumber()) {
1021 pickerDate.SetYear(year->ToNumber<int32_t>());
1022 pickerDate.SetMonth(month->ToNumber<int32_t>() + 1); // 0-11 means 1 to 12 months
1023 pickerDate.SetDay(date->ToNumber<int32_t>());
1024 }
1025 return pickerDate;
1026 }
1027
ParseTime(const JSRef<JSVal> & timeVal)1028 PickerTime JSDatePickerDialog::ParseTime(const JSRef<JSVal>& timeVal)
1029 {
1030 auto pickerTime = PickerTime();
1031 if (!timeVal->IsObject()) {
1032 return pickerTime;
1033 }
1034 auto timeObj = JSRef<JSObject>::Cast(timeVal);
1035 auto hourFunc = JSRef<JSFunc>::Cast(timeObj->GetProperty("getHours"));
1036 auto minuteFunc = JSRef<JSFunc>::Cast(timeObj->GetProperty("getMinutes"));
1037 auto secondFunc = JSRef<JSFunc>::Cast(timeObj->GetProperty("getSeconds"));
1038 JSRef<JSVal> hour = hourFunc->Call(timeObj);
1039 JSRef<JSVal> minute = minuteFunc->Call(timeObj);
1040 JSRef<JSVal> second = secondFunc->Call(timeObj);
1041
1042 if (hour->IsNumber() && minute->IsNumber() && second->IsNumber()) {
1043 pickerTime.SetHour(hour->ToNumber<int32_t>());
1044 pickerTime.SetMinute(minute->ToNumber<int32_t>());
1045 pickerTime.SetSecond(second->ToNumber<int32_t>());
1046 }
1047 return pickerTime;
1048 }
1049
JSBind(BindingTarget globalObj)1050 void JSTimePicker::JSBind(BindingTarget globalObj)
1051 {
1052 JSClass<JSTimePicker>::Declare("TimePicker");
1053 MethodOptions opt = MethodOptions::NONE;
1054 JSClass<JSTimePicker>::StaticMethod("create", &JSTimePicker::Create, opt);
1055 JSClass<JSTimePicker>::StaticMethod("onChange", &JSTimePicker::OnChange);
1056 JSClass<JSTimePicker>::StaticMethod("backgroundColor", &JSTimePicker::PickerBackgroundColor);
1057 JSClass<JSTimePicker>::StaticMethod("useMilitaryTime", &JSTimePicker::UseMilitaryTime);
1058 JSClass<JSTimePicker>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
1059 JSClass<JSTimePicker>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
1060 JSClass<JSTimePicker>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
1061 JSClass<JSTimePicker>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
1062 JSClass<JSTimePicker>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
1063 JSClass<JSTimePicker>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
1064 JSClass<JSTimePicker>::StaticMethod("disappearTextStyle", &JSTimePicker::SetDisappearTextStyle);
1065 JSClass<JSTimePicker>::StaticMethod("textStyle", &JSTimePicker::SetTextStyle);
1066 JSClass<JSTimePicker>::StaticMethod("selectedTextStyle", &JSTimePicker::SetSelectedTextStyle);
1067 JSClass<JSTimePicker>::InheritAndBind<JSViewAbstract>(globalObj);
1068 }
1069
Create(const JSCallbackInfo & info)1070 void JSTimePicker::Create(const JSCallbackInfo& info)
1071 {
1072 JSRef<JSObject> paramObject = JSRef<JSObject>::New();
1073 if (info.Length() >= 1 && info[0]->IsObject()) {
1074 paramObject = JSRef<JSObject>::Cast(info[0]);
1075 }
1076 CreateTimePicker(info, paramObject);
1077 }
1078
UseMilitaryTime(bool isUseMilitaryTime)1079 void JSTimePicker::UseMilitaryTime(bool isUseMilitaryTime)
1080 {
1081 TimePickerModel::GetInstance()->SetHour24(isUseMilitaryTime);
1082 }
1083
PickerBackgroundColor(const JSCallbackInfo & info)1084 void JSTimePicker::PickerBackgroundColor(const JSCallbackInfo& info)
1085 {
1086 JSViewAbstract::JsBackgroundColor(info);
1087
1088 if (info.Length() < 1) {
1089 LOGI("The arg(PickerBackgroundColor) is wrong, it is supposed to have at least 1 argument");
1090 return;
1091 }
1092 Color backgroundColor;
1093 if (!ParseJsColor(info[0], backgroundColor)) {
1094 LOGI("the info[0] is null");
1095 return;
1096 }
1097 TimePickerModel::GetInstance()->SetBackgroundColor(backgroundColor);
1098 }
1099
SetDisappearTextStyle(const JSCallbackInfo & info)1100 void JSTimePicker::SetDisappearTextStyle(const JSCallbackInfo& info)
1101 {
1102 auto theme = GetTheme<PickerTheme>();
1103 if (!theme) {
1104 LOGE("timePicker Theme is null");
1105 return;
1106 }
1107 NG::PickerTextStyle textStyle;
1108 if (info.Length() < 1 || !info[0]->IsObject()) {
1109 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
1110 } else {
1111 JSDatePicker::ParseTextStyle(info[0], textStyle);
1112 }
1113 TimePickerModel::GetInstance()->SetDisappearTextStyle(theme, textStyle);
1114 }
1115
SetTextStyle(const JSCallbackInfo & info)1116 void JSTimePicker::SetTextStyle(const JSCallbackInfo& info)
1117 {
1118 auto theme = GetTheme<PickerTheme>();
1119 if (!theme) {
1120 LOGE("timePicker Theme is null");
1121 return;
1122 }
1123 NG::PickerTextStyle textStyle;
1124 if (info.Length() < 1 || !info[0]->IsObject()) {
1125 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
1126 } else {
1127 JSDatePicker::ParseTextStyle(info[0], textStyle);
1128 }
1129 TimePickerModel::GetInstance()->SetNormalTextStyle(theme, textStyle);
1130 }
1131
SetSelectedTextStyle(const JSCallbackInfo & info)1132 void JSTimePicker::SetSelectedTextStyle(const JSCallbackInfo& info)
1133 {
1134 auto theme = GetTheme<PickerTheme>();
1135 if (!theme) {
1136 LOGE("timePicker Theme is null");
1137 return;
1138 }
1139 NG::PickerTextStyle textStyle;
1140 if (info.Length() < 1 || !info[0]->IsObject()) {
1141 LOGE("The arg is wrong, it is supposed to have at least 1 argument");
1142 } else {
1143 JSDatePicker::ParseTextStyle(info[0], textStyle);
1144 }
1145 TimePickerModel::GetInstance()->SetSelectedTextStyle(theme, textStyle);
1146 }
1147
CreateTimePicker(const JSCallbackInfo & info,const JSRef<JSObject> & paramObj)1148 void JSTimePicker::CreateTimePicker(const JSCallbackInfo& info, const JSRef<JSObject>& paramObj)
1149 {
1150 auto selectedTime = paramObj->GetProperty("selected");
1151 auto theme = GetTheme<PickerTheme>();
1152 if (!theme) {
1153 LOGE("timePicker Theme is null");
1154 return;
1155 }
1156 TimePickerModel::GetInstance()->CreateTimePicker(theme);
1157 if (selectedTime->IsObject()) {
1158 JSRef<JSObject> selectedTimeObj = JSRef<JSObject>::Cast(selectedTime);
1159 JSRef<JSVal> changeEventVal = selectedTimeObj->GetProperty("changeEvent");
1160 if (!changeEventVal->IsUndefined() && changeEventVal->IsFunction()) {
1161 ParseSelectedDateTimeObject(info, selectedTimeObj, false);
1162 auto parseSelectedTime = ParseTime(selectedTimeObj->GetProperty("value"));
1163 TimePickerModel::GetInstance()->SetSelectedTime(parseSelectedTime);
1164 } else {
1165 TimePickerModel::GetInstance()->SetSelectedTime(ParseTime(selectedTime));
1166 }
1167 }
1168 SetDefaultAttributes();
1169 }
1170
SetDefaultAttributes()1171 void JSTimePicker::SetDefaultAttributes()
1172 {
1173 auto theme = GetTheme<PickerTheme>();
1174 if (!theme) {
1175 LOGE("timePicker Theme is null");
1176 return;
1177 }
1178 NG::PickerTextStyle textStyle;
1179 auto selectedStyle = theme->GetOptionStyle(true, false);
1180 textStyle.textColor = selectedStyle.GetTextColor();
1181 textStyle.fontSize = selectedStyle.GetFontSize();
1182 textStyle.fontWeight = selectedStyle.GetFontWeight();
1183 TimePickerModel::GetInstance()->SetSelectedTextStyle(theme, textStyle);
1184
1185 auto disappearStyle = theme->GetDisappearOptionStyle();
1186 textStyle.textColor = disappearStyle.GetTextColor();
1187 textStyle.fontSize = disappearStyle.GetFontSize();
1188 textStyle.fontWeight = disappearStyle.GetFontWeight();
1189 TimePickerModel::GetInstance()->SetDisappearTextStyle(theme, textStyle);
1190
1191 auto normalStyle = theme->GetOptionStyle(false, false);
1192 textStyle.textColor = normalStyle.GetTextColor();
1193 textStyle.fontSize = normalStyle.GetFontSize();
1194 textStyle.fontWeight = normalStyle.GetFontWeight();
1195 TimePickerModel::GetInstance()->SetNormalTextStyle(theme, textStyle);
1196 }
1197
ParseTime(const JSRef<JSVal> & timeVal)1198 PickerTime JSTimePicker::ParseTime(const JSRef<JSVal>& timeVal)
1199 {
1200 auto pickerTime = PickerTime();
1201 if (!timeVal->IsObject()) {
1202 return pickerTime;
1203 }
1204 auto timeObj = JSRef<JSObject>::Cast(timeVal);
1205 auto hourFuncJsVal = timeObj->GetProperty("getHours");
1206 auto minuteFuncJsVal = timeObj->GetProperty("getMinutes");
1207 auto secondFuncJsVal = timeObj->GetProperty("getSeconds");
1208 if (!(hourFuncJsVal->IsFunction() && minuteFuncJsVal->IsFunction() && secondFuncJsVal->IsFunction())) {
1209 return pickerTime;
1210 }
1211 auto hourFunc = JSRef<JSFunc>::Cast(hourFuncJsVal);
1212 auto minuteFunc = JSRef<JSFunc>::Cast(minuteFuncJsVal);
1213 auto secondFunc = JSRef<JSFunc>::Cast(secondFuncJsVal);
1214 JSRef<JSVal> hour = hourFunc->Call(timeObj);
1215 JSRef<JSVal> minute = minuteFunc->Call(timeObj);
1216 JSRef<JSVal> second = secondFunc->Call(timeObj);
1217
1218 if (hour->IsNumber() && minute->IsNumber() && second->IsNumber()) {
1219 pickerTime.SetHour(hour->ToNumber<int32_t>());
1220 pickerTime.SetMinute(minute->ToNumber<int32_t>());
1221 pickerTime.SetSecond(second->ToNumber<int32_t>());
1222 }
1223 return pickerTime;
1224 }
1225
JSBind(BindingTarget globalObj)1226 void JSTimePickerDialog::JSBind(BindingTarget globalObj)
1227 {
1228 JSClass<JSTimePickerDialog>::Declare("TimePickerDialog");
1229 JSClass<JSTimePickerDialog>::StaticMethod("show", &JSTimePickerDialog::Show);
1230
1231 JSClass<JSTimePickerDialog>::Bind<>(globalObj);
1232 }
1233
Show(const JSCallbackInfo & info)1234 void JSTimePickerDialog::Show(const JSCallbackInfo& info)
1235 {
1236 auto scopedDelegate = EngineHelper::GetCurrentDelegate();
1237 if (!scopedDelegate) {
1238 // this case usually means there is no foreground container, need to figure out the reason.
1239 LOGE("scopedDelegate is null, please check");
1240 return;
1241 }
1242 if (info.Length() < 1 || !info[0]->IsObject()) {
1243 LOGE("DatePicker Show dialog error, info is non-valid");
1244 return;
1245 }
1246 auto paramObject = JSRef<JSObject>::Cast(info[0]);
1247 std::function<void()> cancelEvent;
1248 std::function<void(const std::string&)> acceptEvent;
1249 std::function<void(const std::string&)> changeEvent;
1250 auto onChange = paramObject->GetProperty("onChange");
1251 if (!onChange->IsUndefined() && onChange->IsFunction()) {
1252 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onChange));
1253 changeEvent = [execCtx = info.GetExecutionContext(), type = DatePickerType::TIME, func = std::move(jsFunc)](
1254 const std::string& info) {
1255 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1256 std::vector<std::string> keys;
1257 keys = { "hour", "minute" };
1258 ACE_SCORING_EVENT("DatePickerDialog.onChange");
1259 func->Execute(keys, info);
1260 };
1261 }
1262 auto onAccept = paramObject->GetProperty("onAccept");
1263 if (!onAccept->IsUndefined() && onAccept->IsFunction()) {
1264 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onAccept));
1265 acceptEvent = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](const std::string& info) {
1266 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1267 std::vector<std::string> keys = { "year", "month", "day", "hour", "minute", "second" };
1268 ACE_SCORING_EVENT("DatePickerDialog.onAccept");
1269 func->Execute(keys, info);
1270 };
1271 }
1272 auto onCancel = paramObject->GetProperty("onCancel");
1273 if (!onCancel->IsUndefined() && onCancel->IsFunction()) {
1274 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onCancel));
1275 cancelEvent = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)]() {
1276 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
1277 ACE_SCORING_EVENT("DatePickerDialog.onCancel");
1278 func->Execute();
1279 };
1280 }
1281 auto selectedTime = paramObject->GetProperty("selected");
1282 auto useMilitaryTime = paramObject->GetProperty("useMilitaryTime");
1283 NG::TimePickerSettingData settingData;
1284 PickerDialogInfo pickerDialog;
1285 settingData.isUseMilitaryTime = useMilitaryTime->ToBoolean();
1286 pickerDialog.isUseMilitaryTime = useMilitaryTime->ToBoolean();
1287 if (selectedTime->IsObject()) {
1288 PickerDate dialogTitleDate = ParseDate(selectedTime);
1289 if (dialogTitleDate.GetYear() != 0) {
1290 settingData.dialogTitleDate = dialogTitleDate;
1291 pickerDialog.isSelectedTime = true;
1292 pickerDialog.pickerTime = ParseTime(selectedTime);
1293 }
1294 }
1295 JSDatePicker::ParseTextProperties(paramObject, settingData.properties);
1296
1297 // Parse alignment
1298 auto alignmentValue = paramObject->GetProperty("alignment");
1299 if (alignmentValue->IsNumber()) {
1300 auto alignment = alignmentValue->ToNumber<int32_t>();
1301 if (alignment >= 0 && alignment <= static_cast<int32_t>(DIALOG_ALIGNMENT.size())) {
1302 pickerDialog.alignment = DIALOG_ALIGNMENT[alignment];
1303 }
1304 if (alignment == static_cast<int32_t>(DialogAlignment::TOP) ||
1305 alignment == static_cast<int32_t>(DialogAlignment::TOP_START) ||
1306 alignment == static_cast<int32_t>(DialogAlignment::TOP_END)) {
1307 pickerDialog.offset = DATEPICKER_OFFSET_DEFAULT_TOP;
1308 }
1309 }
1310
1311 // Parse offset
1312 auto offsetValue = paramObject->GetProperty("offset");
1313 if (offsetValue->IsObject()) {
1314 auto offsetObj = JSRef<JSObject>::Cast(offsetValue);
1315 CalcDimension dx;
1316 auto dxValue = offsetObj->GetProperty("dx");
1317 JSAlertDialog::ParseJsDimensionVp(dxValue, dx);
1318 CalcDimension dy;
1319 auto dyValue = offsetObj->GetProperty("dy");
1320 JSAlertDialog::ParseJsDimensionVp(dyValue, dy);
1321 pickerDialog.offset = DimensionOffset(dx, dy);
1322 }
1323
1324 // Parse maskRect.
1325 auto maskRectValue = paramObject->GetProperty("maskRect");
1326 DimensionRect maskRect;
1327 if (JSViewAbstract::ParseJsDimensionRect(maskRectValue, maskRect)) {
1328 pickerDialog.maskRect = maskRect;
1329 }
1330
1331 TimePickerDialogModel::GetInstance()->SetTimePickerDialogShow(
1332 pickerDialog, settingData, std::move(cancelEvent), std::move(acceptEvent), std::move(changeEvent));
1333 }
1334
TimePickerDialogShow(const JSRef<JSObject> & paramObj,const std::map<std::string,NG::DialogEvent> & dialogEvent,const std::map<std::string,NG::DialogGestureEvent> & dialogCancelEvent)1335 void JSTimePickerDialog::TimePickerDialogShow(const JSRef<JSObject>& paramObj,
1336 const std::map<std::string, NG::DialogEvent>& dialogEvent,
1337 const std::map<std::string, NG::DialogGestureEvent>& dialogCancelEvent)
1338 {
1339 auto container = Container::Current();
1340 if (!container) {
1341 return;
1342 }
1343 auto pipelineContext = AccessibilityManager::DynamicCast<NG::PipelineContext>(container->GetPipelineContext());
1344 if (!pipelineContext) {
1345 return;
1346 }
1347
1348 auto executor = pipelineContext->GetTaskExecutor();
1349 if (!executor) {
1350 return;
1351 }
1352
1353 auto theme = JSAlertDialog::GetTheme<DialogTheme>();
1354 if (!theme) {
1355 LOGE("DialogTheme is null");
1356 return;
1357 }
1358
1359 auto selectedTime = paramObj->GetProperty("selected");
1360 auto useMilitaryTime = paramObj->GetProperty("useMilitaryTime");
1361 NG::TimePickerSettingData settingData;
1362 settingData.isUseMilitaryTime = useMilitaryTime->ToBoolean();
1363
1364 ButtonInfo buttonInfo;
1365 DialogProperties properties;
1366 if (SystemProperties::GetDeviceType() == DeviceType::PHONE) {
1367 properties.alignment = DialogAlignment::BOTTOM;
1368 } else {
1369 properties.alignment = DialogAlignment::CENTER;
1370 }
1371 properties.customStyle = false;
1372 properties.offset = DimensionOffset(Offset(0, -theme->GetMarginBottom().ConvertToPx()));
1373
1374 std::map<std::string, PickerTime> timePickerProperty;
1375 if (selectedTime->IsObject()) {
1376 settingData.dialogTitleDate = ParseDate(selectedTime);
1377 timePickerProperty["selected"] = ParseTime(selectedTime);
1378 }
1379 JSDatePicker::ParseTextProperties(paramObj, settingData.properties);
1380
1381 auto context = AccessibilityManager::DynamicCast<NG::PipelineContext>(pipelineContext);
1382 auto overlayManager = context ? context->GetOverlayManager() : nullptr;
1383 executor->PostTask(
1384 [properties, settingData, timePickerProperty, dialogEvent, dialogCancelEvent,
1385 weak = WeakPtr<NG::OverlayManager>(overlayManager)] {
1386 auto overlayManager = weak.Upgrade();
1387 CHECK_NULL_VOID(overlayManager);
1388 overlayManager->ShowTimeDialog(properties, settingData, timePickerProperty, dialogEvent, dialogCancelEvent);
1389 },
1390 TaskExecutor::TaskType::UI);
1391 }
1392
CreateTimePicker(RefPtr<Component> & component,const JSRef<JSObject> & paramObj)1393 void JSTimePickerDialog::CreateTimePicker(RefPtr<Component>& component, const JSRef<JSObject>& paramObj)
1394 {
1395 auto timePicker = AceType::MakeRefPtr<PickerTimeComponent>();
1396 auto selectedTime = paramObj->GetProperty("selected");
1397 auto useMilitaryTime = paramObj->GetProperty("useMilitaryTime");
1398 bool isUseMilitaryTime = useMilitaryTime->ToBoolean();
1399 if (selectedTime->IsObject()) {
1400 timePicker->SetSelectedTime(ParseTime(selectedTime));
1401 }
1402 timePicker->SetIsDialog(true);
1403 timePicker->SetIsCreateDialogComponent(true);
1404 timePicker->SetHour24(isUseMilitaryTime);
1405 component = timePicker;
1406 }
1407
ParseTime(const JSRef<JSVal> & timeVal)1408 PickerTime JSTimePickerDialog::ParseTime(const JSRef<JSVal>& timeVal)
1409 {
1410 auto pickerTime = PickerTime();
1411 if (!timeVal->IsObject()) {
1412 return pickerTime;
1413 }
1414 auto timeObj = JSRef<JSObject>::Cast(timeVal);
1415 auto hourFuncJsVal = timeObj->GetProperty("getHours");
1416 auto minuteFuncJsVal = timeObj->GetProperty("getMinutes");
1417 auto secondFuncJsVal = timeObj->GetProperty("getSeconds");
1418 if (!(hourFuncJsVal->IsFunction() && minuteFuncJsVal->IsFunction() && secondFuncJsVal->IsFunction())) {
1419 return pickerTime;
1420 }
1421 auto hourFunc = JSRef<JSFunc>::Cast(hourFuncJsVal);
1422 auto minuteFunc = JSRef<JSFunc>::Cast(minuteFuncJsVal);
1423 auto secondFunc = JSRef<JSFunc>::Cast(secondFuncJsVal);
1424 JSRef<JSVal> hour = hourFunc->Call(timeObj);
1425 JSRef<JSVal> minute = minuteFunc->Call(timeObj);
1426 JSRef<JSVal> second = secondFunc->Call(timeObj);
1427
1428 if (hour->IsNumber() && minute->IsNumber() && second->IsNumber()) {
1429 pickerTime.SetHour(hour->ToNumber<int32_t>());
1430 pickerTime.SetMinute(minute->ToNumber<int32_t>());
1431 pickerTime.SetSecond(second->ToNumber<int32_t>());
1432 }
1433 return pickerTime;
1434 }
1435
ParseDate(const JSRef<JSVal> & dateVal)1436 PickerDate JSTimePickerDialog::ParseDate(const JSRef<JSVal>& dateVal)
1437 {
1438 auto pickerDate = PickerDate();
1439 if (!dateVal->IsObject()) {
1440 return pickerDate;
1441 }
1442 auto dateObj = JSRef<JSObject>::Cast(dateVal);
1443 auto yearFuncJsVal = dateObj->GetProperty("getFullYear");
1444 auto monthFuncJsVal = dateObj->GetProperty("getMonth");
1445 auto dateFuncJsVal = dateObj->GetProperty("getDate");
1446 if (!(yearFuncJsVal->IsFunction() && monthFuncJsVal->IsFunction() && dateFuncJsVal->IsFunction())) {
1447 return pickerDate;
1448 }
1449 auto yearFunc = JSRef<JSFunc>::Cast(yearFuncJsVal);
1450 auto monthFunc = JSRef<JSFunc>::Cast(monthFuncJsVal);
1451 auto dateFunc = JSRef<JSFunc>::Cast(dateFuncJsVal);
1452 JSRef<JSVal> year = yearFunc->Call(dateObj);
1453 JSRef<JSVal> month = monthFunc->Call(dateObj);
1454 JSRef<JSVal> date = dateFunc->Call(dateObj);
1455
1456 if (year->IsNumber() && month->IsNumber() && date->IsNumber()) {
1457 pickerDate.SetYear(year->ToNumber<int32_t>());
1458 pickerDate.SetMonth(month->ToNumber<int32_t>() + 1); // 0-11 means 1 to 12 months
1459 pickerDate.SetDay(date->ToNumber<int32_t>());
1460 }
1461 return pickerDate;
1462 }
1463 } // namespace OHOS::Ace::Framework
1464