• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "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 std::unique_ptr<DatePickerModel> DatePickerModel::datePickerInstance_ = nullptr;
43 std::unique_ptr<TimePickerModel> TimePickerModel::timePickerInstance_ = nullptr;
GetInstance()44 DatePickerModel* DatePickerModel::GetInstance()
45 {
46     if (!datePickerInstance_) {
47 #ifdef NG_BUILD
48         datePickerInstance_.reset(new NG::DatePickerModelNG());
49 #else
50         if (Container::IsCurrentUseNewPipeline()) {
51             datePickerInstance_.reset(new NG::DatePickerModelNG());
52         } else {
53             datePickerInstance_.reset(new Framework::DatePickerModelImpl());
54         }
55 #endif
56     }
57     return datePickerInstance_.get();
58 }
59 
GetInstance()60 TimePickerModel* TimePickerModel::GetInstance()
61 {
62     if (!timePickerInstance_) {
63 #ifdef NG_BUILD
64         timePickerInstance_.reset(new NG::TimePickerModelNG());
65 #else
66         if (Container::IsCurrentUseNewPipeline()) {
67             timePickerInstance_.reset(new NG::TimePickerModelNG());
68         } else {
69             timePickerInstance_.reset(new Framework::TimePickerModelImpl());
70         }
71 #endif
72     }
73     return timePickerInstance_.get();
74 }
75 
76 } // namespace OHOS::Ace
77 
78 namespace OHOS::Ace::Framework {
79 namespace {
AddEvent(RefPtr<PickerBaseComponent> & picker,const JSCallbackInfo & info,DatePickerType pickerType)80 void AddEvent(RefPtr<PickerBaseComponent>& picker, const JSCallbackInfo& info, DatePickerType pickerType)
81 {
82     if (info.Length() < 1 || !info[0]->IsObject()) {
83         LOGE("DatePicker AddEvent error, info is non-valid");
84         return;
85     }
86     auto paramObject = JSRef<JSObject>::Cast(info[0]);
87     auto onAccept = paramObject->GetProperty("onAccept");
88     if (!onAccept->IsUndefined() && onAccept->IsFunction()) {
89         auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onAccept));
90         auto acceptId =
91             EventMarker([execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](const std::string& info) {
92                 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
93                 std::vector<std::string> keys = { "year", "month", "day", "hour", "minute", "second" };
94                 ACE_SCORING_EVENT("DatePickerDialog.onAccept");
95                 func->Execute(keys, info);
96             });
97         picker->SetDialogAcceptEvent(acceptId);
98     }
99     auto onCancel = paramObject->GetProperty("onCancel");
100     if (!onCancel->IsUndefined() && onCancel->IsFunction()) {
101         auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onCancel));
102         auto cancelId = EventMarker([execCtx = info.GetExecutionContext(), func = std::move(jsFunc)]() {
103             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
104             ACE_SCORING_EVENT("DatePickerDialog.onCancel");
105             func->Execute();
106         });
107         picker->SetDialogCancelEvent(cancelId);
108     }
109     auto onChange = paramObject->GetProperty("onChange");
110     if (!onChange->IsUndefined() && onChange->IsFunction()) {
111         auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onChange));
112         auto changeId = EventMarker([execCtx = info.GetExecutionContext(), type = pickerType, func = std::move(jsFunc)](
113                                         const std::string& info) {
114             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
115             std::vector<std::string> keys;
116             if (type == DatePickerType::DATE) {
117                 keys = { "year", "month", "day" };
118             } else {
119                 keys = { "hour", "minute" };
120             }
121             ACE_SCORING_EVENT("DatePickerDialog.onChange");
122             func->Execute(keys, info);
123         });
124         picker->SetDialogChangeEvent(changeId);
125     }
126 }
127 
ChangeDialogEvent(const JSCallbackInfo & info,DatePickerType pickerType)128 std::map<std::string, NG::DialogEvent> ChangeDialogEvent(const JSCallbackInfo& info, DatePickerType pickerType)
129 {
130     std::map<std::string, NG::DialogEvent> dialogEvent;
131     if (info.Length() < 1 || !info[0]->IsObject()) {
132         LOGE("DatePicker AddEvent error, info is non-valid");
133         return dialogEvent;
134     }
135     auto paramObject = JSRef<JSObject>::Cast(info[0]);
136     auto onChange = paramObject->GetProperty("onChange");
137     if (!onChange->IsUndefined() && onChange->IsFunction()) {
138         auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onChange));
139         auto changeId = [execCtx = info.GetExecutionContext(), type = pickerType, func = std::move(jsFunc)](
140                             const std::string& info) {
141             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
142             std::vector<std::string> keys;
143             if (type == DatePickerType::DATE) {
144                 keys = { "year", "month", "day" };
145             } else {
146                 keys = { "hour", "minute" };
147             }
148             ACE_SCORING_EVENT("DatePickerDialog.onChange");
149             func->Execute(keys, info);
150         };
151         dialogEvent["changeId"] = changeId;
152     }
153     auto onAccept = paramObject->GetProperty("onAccept");
154     if (!onAccept->IsUndefined() && onAccept->IsFunction()) {
155         auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onAccept));
156         auto acceptId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](const std::string& info) {
157             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
158             std::vector<std::string> keys = { "year", "month", "day", "hour", "minute", "second" };
159             ACE_SCORING_EVENT("DatePickerDialog.onAccept");
160             func->Execute(keys, info);
161         };
162         dialogEvent["acceptId"] = acceptId;
163     }
164     return dialogEvent;
165 }
166 
DialogCancelEvent(const JSCallbackInfo & info)167 std::map<std::string, NG::DialogGestureEvent> DialogCancelEvent(const JSCallbackInfo& info)
168 {
169     std::map<std::string, NG::DialogGestureEvent> dialogCancelEvent;
170     if (info.Length() < 1 || !info[0]->IsObject()) {
171         LOGE("DatePicker AddEvent error, info is non-valid");
172         return dialogCancelEvent;
173     }
174     auto paramObject = JSRef<JSObject>::Cast(info[0]);
175     auto onCancel = paramObject->GetProperty("onCancel");
176     if (!onCancel->IsUndefined() && onCancel->IsFunction()) {
177         auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(onCancel));
178         auto cancelId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](const GestureEvent& /*info*/) {
179             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
180             ACE_SCORING_EVENT("DatePickerDialog.onCancel");
181             func->Execute();
182         };
183         dialogCancelEvent["cancelId"] = cancelId;
184     }
185     return dialogCancelEvent;
186 }
187 
DatePickerChangeEventToJSValue(const DatePickerChangeEvent & eventInfo)188 JSRef<JSVal> DatePickerChangeEventToJSValue(const DatePickerChangeEvent& eventInfo)
189 {
190     JSRef<JSObject> obj = JSRef<JSObject>::New();
191     std::unique_ptr<JsonValue> argsPtr = JsonUtil::ParseJsonString(eventInfo.GetSelectedStr());
192     if (!argsPtr) {
193         LOGW("selectedStr is not exist.");
194         return JSRef<JSVal>::Cast(obj);
195     }
196     std::vector<std::string> keys = { "year", "month", "day", "hour", "minute", "second" };
197     for (auto iter = keys.begin(); iter != keys.end(); iter++) {
198         const std::string key = *iter;
199         const auto value = argsPtr->GetValue(key);
200         if (!value || value->ToString().empty()) {
201             LOGI("key[%{public}s] is not exist.", key.c_str());
202             continue;
203         }
204         obj->SetProperty<int32_t>(key.c_str(), value->GetInt());
205     }
206     return JSRef<JSVal>::Cast(obj);
207 }
208 } // namespace
209 
JSBind(BindingTarget globalObj)210 void JSDatePicker::JSBind(BindingTarget globalObj)
211 {
212     JSClass<JSDatePicker>::Declare("DatePicker");
213     MethodOptions opt = MethodOptions::NONE;
214     JSClass<JSDatePicker>::StaticMethod("create", &JSDatePicker::Create, opt);
215     JSClass<JSDatePicker>::StaticMethod("lunar", &JSDatePicker::SetLunar);
216     JSClass<JSDatePicker>::StaticMethod("onChange", &JSDatePicker::OnChange);
217     JSClass<JSDatePicker>::StaticMethod("backgroundColor", &JSDatePicker::PickerBackgroundColor);
218     // keep compatible, need remove after
219     JSClass<JSDatePicker>::StaticMethod("useMilitaryTime", &JSDatePicker::UseMilitaryTime);
220     JSClass<JSDatePicker>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
221     JSClass<JSDatePicker>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
222     JSClass<JSDatePicker>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
223     JSClass<JSDatePicker>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
224     JSClass<JSDatePicker>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
225     JSClass<JSDatePicker>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
226     JSClass<JSDatePicker>::Inherit<JSViewAbstract>();
227     JSClass<JSDatePicker>::Bind(globalObj);
228 }
229 
Create(const JSCallbackInfo & info)230 void JSDatePicker::Create(const JSCallbackInfo& info)
231 {
232     DatePickerType pickerType = DatePickerType::DATE;
233     JSRef<JSObject> paramObject;
234     if (info.Length() >= 1 && info[0]->IsObject()) {
235         paramObject = JSRef<JSObject>::Cast(info[0]);
236         auto type = paramObject->GetProperty("type");
237         if (type->IsNumber()) {
238             pickerType = static_cast<DatePickerType>(type->ToNumber<int32_t>());
239         }
240     }
241     switch (pickerType) {
242         case DatePickerType::TIME: {
243             CreateTimePicker(paramObject);
244             break;
245         }
246         case DatePickerType::DATE: {
247             CreateDatePicker(paramObject);
248             break;
249         }
250         default: {
251             LOGE("Undefined date picker type.");
252             break;
253         }
254     }
255 }
256 
SetLunar(bool isLunar)257 void JSDatePicker::SetLunar(bool isLunar)
258 {
259     DatePickerModel::GetInstance()->SetShowLunar(isLunar);
260 }
261 
UseMilitaryTime(bool isUseMilitaryTime)262 void JSDatePicker::UseMilitaryTime(bool isUseMilitaryTime)
263 {
264     DatePickerModel::GetInstance()->SetHour24(isUseMilitaryTime);
265 }
266 
OnChange(const JSCallbackInfo & info)267 void JSDatePicker::OnChange(const JSCallbackInfo& info)
268 {
269     if (info.Length() < 1 || !info[0]->IsFunction()) {
270         LOGI("info not function");
271         return;
272     }
273 
274     auto jsFunc = AceType::MakeRefPtr<JsEventFunction<DatePickerChangeEvent, 1>>(
275         JSRef<JSFunc>::Cast(info[0]), DatePickerChangeEventToJSValue);
276     auto onChange = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](const BaseEventInfo* info) {
277         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
278         ACE_SCORING_EVENT("datePicker.onChange");
279         const auto* eventInfo = TypeInfoHelper::DynamicCast<DatePickerChangeEvent>(info);
280         func->Execute(*eventInfo);
281     };
282     DatePickerModel::GetInstance()->SetOnChange(std::move(onChange));
283 }
284 
OnChange(const JSCallbackInfo & info)285 void JSTimePicker::OnChange(const JSCallbackInfo& info)
286 {
287     if (info.Length() < 1 || !info[0]->IsFunction()) {
288         LOGI("info not function");
289         return;
290     }
291 
292     auto jsFunc = AceType::MakeRefPtr<JsEventFunction<DatePickerChangeEvent, 1>>(
293         JSRef<JSFunc>::Cast(info[0]), DatePickerChangeEventToJSValue);
294     auto onChange = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](const BaseEventInfo* index) {
295         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
296         ACE_SCORING_EVENT("datePicker.onChange");
297         const auto* eventInfo = TypeInfoHelper::DynamicCast<DatePickerChangeEvent>(index);
298         func->Execute(*eventInfo);
299     };
300     TimePickerModel::GetInstance()->SetOnChange(std::move(onChange));
301 }
302 
PickerBackgroundColor(const JSCallbackInfo & info)303 void JSDatePicker::PickerBackgroundColor(const JSCallbackInfo& info)
304 {
305     JSViewAbstract::JsBackgroundColor(info);
306 
307     auto pickerBase = AceType::DynamicCast<PickerBaseComponent>(ViewStackProcessor::GetInstance()->GetMainComponent());
308     if (!pickerBase) {
309         LOGE("PickerBaseComponent is null");
310         return;
311     }
312 
313     pickerBase->SetHasBackgroundColor(true);
314 }
315 
ParseDate(const JSRef<JSVal> & dateVal)316 PickerDate JSDatePicker::ParseDate(const JSRef<JSVal>& dateVal)
317 {
318     auto pickerDate = PickerDate();
319     if (!dateVal->IsObject()) {
320         return pickerDate;
321     }
322     auto dateObj = JSRef<JSObject>::Cast(dateVal);
323     auto yearFunc = JSRef<JSFunc>::Cast(dateObj->GetProperty("getFullYear"));
324     auto monthFunc = JSRef<JSFunc>::Cast(dateObj->GetProperty("getMonth"));
325     auto dateFunc = JSRef<JSFunc>::Cast(dateObj->GetProperty("getDate"));
326     JSRef<JSVal> year = yearFunc->Call(dateObj);
327     JSRef<JSVal> month = monthFunc->Call(dateObj);
328     JSRef<JSVal> date = dateFunc->Call(dateObj);
329 
330     if (year->IsNumber() && month->IsNumber() && date->IsNumber()) {
331         pickerDate.SetYear(year->ToNumber<int32_t>());
332         pickerDate.SetMonth(month->ToNumber<int32_t>() + 1); // 0-11 means 1 to 12 months
333         pickerDate.SetDay(date->ToNumber<int32_t>());
334     }
335     return pickerDate;
336 }
337 
ParseTime(const JSRef<JSVal> & timeVal)338 PickerTime JSDatePicker::ParseTime(const JSRef<JSVal>& timeVal)
339 {
340     auto pickerTime = PickerTime();
341     if (!timeVal->IsObject()) {
342         return pickerTime;
343     }
344     auto timeObj = JSRef<JSObject>::Cast(timeVal);
345     auto hourFunc = JSRef<JSFunc>::Cast(timeObj->GetProperty("getHours"));
346     auto minuteFunc = JSRef<JSFunc>::Cast(timeObj->GetProperty("getMinutes"));
347     auto secondFunc = JSRef<JSFunc>::Cast(timeObj->GetProperty("getSeconds"));
348     JSRef<JSVal> hour = hourFunc->Call(timeObj);
349     JSRef<JSVal> minute = minuteFunc->Call(timeObj);
350     JSRef<JSVal> second = secondFunc->Call(timeObj);
351 
352     if (hour->IsNumber() && minute->IsNumber() && second->IsNumber()) {
353         pickerTime.SetHour(hour->ToNumber<int32_t>());
354         pickerTime.SetMinute(minute->ToNumber<int32_t>());
355         pickerTime.SetSecond(second->ToNumber<int32_t>());
356     }
357     return pickerTime;
358 }
359 
CreateDatePicker(const JSRef<JSObject> & paramObj)360 void JSDatePicker::CreateDatePicker(const JSRef<JSObject>& paramObj)
361 {
362     JSRef<JSVal> startDate;
363     JSRef<JSVal> endDate;
364     JSRef<JSVal> selectedDate;
365     if (!paramObj->IsUndefined()) {
366         startDate = paramObj->GetProperty("start");
367         endDate = paramObj->GetProperty("end");
368         selectedDate = paramObj->GetProperty("selected");
369     }
370     auto parseStartDate = ParseDate(startDate);
371     auto parseEndDate = ParseDate(endDate);
372     auto parseSelectedDate = ParseDate(selectedDate);
373     auto startDays = parseStartDate.ToDays();
374     auto endDays = parseEndDate.ToDays();
375     auto selectedDays = parseSelectedDate.ToDays();
376     if (startDays > endDays || selectedDays < startDays || selectedDays > endDays) {
377         LOGE("date error");
378     }
379     auto theme = GetTheme<PickerTheme>();
380     if (!theme) {
381         LOGE("datePicker Theme is null");
382         return;
383     }
384     DatePickerModel::GetInstance()->CreateDatePicker(theme);
385     if (startDate->IsObject()) {
386         DatePickerModel::GetInstance()->SetStartDate(parseStartDate);
387     }
388     if (endDate->IsObject()) {
389         DatePickerModel::GetInstance()->SetEndDate(parseEndDate);
390     }
391     if (selectedDate->IsObject()) {
392         DatePickerModel::GetInstance()->SetSelectedDate(parseSelectedDate);
393     }
394 }
395 
CreateTimePicker(const JSRef<JSObject> & paramObj)396 void JSDatePicker::CreateTimePicker(const JSRef<JSObject>& paramObj)
397 {
398     auto theme = GetTheme<PickerTheme>();
399     if (!theme) {
400         LOGE("timePicker Theme is null");
401         return;
402     }
403     DatePickerModel::GetInstance()->CreateTimePicker(theme);
404     auto selectedTime = paramObj->GetProperty("selected");
405     if (selectedTime->IsObject()) {
406         DatePickerModel::GetInstance()->SetSelectedTime(ParseTime(selectedTime));
407     }
408 }
409 
JSBind(BindingTarget globalObj)410 void JSDatePickerDialog::JSBind(BindingTarget globalObj)
411 {
412     JSClass<JSDatePickerDialog>::Declare("DatePickerDialog");
413     JSClass<JSDatePickerDialog>::StaticMethod("show", &JSDatePickerDialog::Show);
414 
415     JSClass<JSDatePickerDialog>::Bind<>(globalObj);
416 }
417 
Show(const JSCallbackInfo & info)418 void JSDatePickerDialog::Show(const JSCallbackInfo& info)
419 {
420     auto scopedDelegate = EngineHelper::GetCurrentDelegate();
421     if (!scopedDelegate) {
422         // this case usually means there is no foreground container, need to figure out the reason.
423         LOGE("scopedDelegate is null, please check");
424         return;
425     }
426     if (info.Length() < 1 || !info[0]->IsObject()) {
427         LOGE("DatePicker Show dialog error, info is non-valid");
428         return;
429     }
430 
431     auto paramObject = JSRef<JSObject>::Cast(info[0]);
432     DatePickerType pickerType = DatePickerType::DATE;
433     auto type = paramObject->GetProperty("type");
434     if (type->IsNumber()) {
435         pickerType = static_cast<DatePickerType>(type->ToNumber<int32_t>());
436     }
437     if (Container::IsCurrentUseNewPipeline()) {
438         auto dialogEvent = ChangeDialogEvent(info, DatePickerType::DATE);
439         auto dialogCancelEvent = DialogCancelEvent(info);
440         DatePickerDialogShow(paramObject, dialogEvent, dialogCancelEvent);
441         return;
442     }
443 
444     std::string name;
445     RefPtr<Component> component;
446     switch (pickerType) {
447         case DatePickerType::TIME: {
448             CreateTimePicker(component, paramObject);
449             name = "TimePickerDialog";
450             break;
451         }
452         case DatePickerType::DATE: {
453             CreateDatePicker(component, paramObject);
454             name = "DatePickerDialog";
455             break;
456         }
457         default: {
458             LOGE("Undefined date picker type.");
459             return;
460         }
461     }
462 
463     auto datePicker = AceType::DynamicCast<PickerBaseComponent>(component);
464     DialogProperties properties {};
465     properties.alignment = DialogAlignment::CENTER;
466     properties.customComponent = datePicker;
467     properties.customStyle = true;
468     if (pickerType == DatePickerType::DATE) {
469         AddEvent(datePicker, info, DatePickerType::DATE);
470     } else {
471         AddEvent(datePicker, info, DatePickerType::TIME);
472     }
473     datePicker->SetDialogName(name);
474     datePicker->OpenDialog(properties);
475 }
476 
DatePickerDialogShow(const JSRef<JSObject> & paramObj,const std::map<std::string,NG::DialogEvent> & dialogEvent,const std::map<std::string,NG::DialogGestureEvent> & dialogCancelEvent)477 void JSDatePickerDialog::DatePickerDialogShow(const JSRef<JSObject>& paramObj,
478     const std::map<std::string, NG::DialogEvent>& dialogEvent,
479     const std::map<std::string, NG::DialogGestureEvent>& dialogCancelEvent)
480 {
481     auto container = Container::Current();
482     if (!container) {
483         return;
484     }
485     auto pipelineContext = AccessibilityManager::DynamicCast<NG::PipelineContext>(container->GetPipelineContext());
486     if (!pipelineContext) {
487         return;
488     }
489 
490     auto executor = pipelineContext->GetTaskExecutor();
491     if (!executor) {
492         return;
493     }
494 
495     auto startDate = paramObj->GetProperty("start");
496     auto endDate = paramObj->GetProperty("end");
497     auto selectedDate = paramObj->GetProperty("selected");
498     auto lunar = paramObj->GetProperty("lunar");
499     bool isLunar = lunar->ToBoolean();
500     auto parseStartDate = ParseDate(startDate);
501     auto parseEndDate = ParseDate(endDate);
502     auto parseSelectedDate = ParseDate(selectedDate);
503     auto startDays = parseStartDate.ToDays();
504     auto endDays = parseEndDate.ToDays();
505     auto selectedDays = parseSelectedDate.ToDays();
506     if (startDays > endDays || selectedDays < startDays || selectedDays > endDays) {
507         LOGE("date error");
508     }
509 
510     auto theme = GetTheme<DialogTheme>();
511     if (!theme) {
512         LOGE("DialogTheme is null");
513         return;
514     }
515 
516     ButtonInfo buttonInfo;
517     DialogProperties properties;
518     if (SystemProperties::GetDeviceType() == DeviceType::PHONE) {
519         properties.alignment = DialogAlignment::BOTTOM;
520     } else {
521         properties.alignment = DialogAlignment::CENTER;
522     }
523     properties.customStyle = false;
524     properties.offset = DimensionOffset(Offset(0, -theme->GetMarginBottom().ConvertToPx()));
525 
526     std::map<std::string, PickerDate> datePickerProperty;
527     if (startDate->IsObject()) {
528         datePickerProperty["start"] = parseStartDate;
529     }
530     if (endDate->IsObject()) {
531         datePickerProperty["end"] = parseEndDate;
532     }
533     if (selectedDate->IsObject()) {
534         datePickerProperty["selected"] = parseSelectedDate;
535     }
536 
537     auto context = AccessibilityManager::DynamicCast<NG::PipelineContext>(pipelineContext);
538     auto overlayManager = context ? context->GetOverlayManager() : nullptr;
539     executor->PostTask(
540         [properties, datePickerProperty, isLunar, dialogEvent, dialogCancelEvent,
541             weak = WeakPtr<NG::OverlayManager>(overlayManager)] {
542             auto overlayManager = weak.Upgrade();
543             CHECK_NULL_VOID(overlayManager);
544             overlayManager->ShowDateDialog(properties, datePickerProperty, isLunar, dialogEvent, dialogCancelEvent);
545         },
546         TaskExecutor::TaskType::UI);
547 }
548 
CreateDatePicker(RefPtr<Component> & component,const JSRef<JSObject> & paramObj)549 void JSDatePickerDialog::CreateDatePicker(RefPtr<Component>& component, const JSRef<JSObject>& paramObj)
550 {
551     auto datePicker = AceType::MakeRefPtr<PickerDateComponent>();
552     auto startDate = paramObj->GetProperty("start");
553     auto endDate = paramObj->GetProperty("end");
554     auto selectedDate = paramObj->GetProperty("selected");
555     auto lunar = paramObj->GetProperty("lunar");
556     bool isLunar = lunar->ToBoolean();
557     auto parseStartDate = ParseDate(startDate);
558     auto parseEndDate = ParseDate(endDate);
559     auto parseSelectedDate = ParseDate(selectedDate);
560     auto startDays = parseStartDate.ToDays();
561     auto endDays = parseEndDate.ToDays();
562     auto selectedDays = parseSelectedDate.ToDays();
563     if (startDays > endDays || selectedDays < startDays || selectedDays > endDays) {
564         LOGE("date error");
565     }
566     if (startDate->IsObject()) {
567         datePicker->SetStartDate(parseStartDate);
568     }
569     if (endDate->IsObject()) {
570         datePicker->SetEndDate(parseEndDate);
571     }
572     if (selectedDate->IsObject()) {
573         datePicker->SetSelectedDate(parseSelectedDate);
574     }
575     datePicker->SetIsDialog(true);
576     datePicker->SetIsCreateDialogComponent(true);
577     datePicker->SetShowLunar(isLunar);
578 
579     component = datePicker;
580 }
581 
CreateTimePicker(RefPtr<Component> & component,const JSRef<JSObject> & paramObj)582 void JSDatePickerDialog::CreateTimePicker(RefPtr<Component>& component, const JSRef<JSObject>& paramObj)
583 {
584     auto timePicker = AceType::MakeRefPtr<PickerTimeComponent>();
585     auto selectedTime = paramObj->GetProperty("selected");
586     auto useMilitaryTime = paramObj->GetProperty("useMilitaryTime");
587     bool isUseMilitaryTime = useMilitaryTime->ToBoolean();
588     if (selectedTime->IsObject()) {
589         timePicker->SetSelectedTime(ParseTime(selectedTime));
590     }
591     timePicker->SetIsDialog(true);
592     timePicker->SetIsCreateDialogComponent(true);
593     timePicker->SetHour24(isUseMilitaryTime);
594     component = timePicker;
595 }
596 
ParseDate(const JSRef<JSVal> & dateVal)597 PickerDate JSDatePickerDialog::ParseDate(const JSRef<JSVal>& dateVal)
598 {
599     auto pickerDate = PickerDate();
600     if (!dateVal->IsObject()) {
601         return pickerDate;
602     }
603     auto dateObj = JSRef<JSObject>::Cast(dateVal);
604     auto yearFunc = JSRef<JSFunc>::Cast(dateObj->GetProperty("getFullYear"));
605     auto monthFunc = JSRef<JSFunc>::Cast(dateObj->GetProperty("getMonth"));
606     auto dateFunc = JSRef<JSFunc>::Cast(dateObj->GetProperty("getDate"));
607     JSRef<JSVal> year = yearFunc->Call(dateObj);
608     JSRef<JSVal> month = monthFunc->Call(dateObj);
609     JSRef<JSVal> date = dateFunc->Call(dateObj);
610 
611     if (year->IsNumber() && month->IsNumber() && date->IsNumber()) {
612         pickerDate.SetYear(year->ToNumber<int32_t>());
613         pickerDate.SetMonth(month->ToNumber<int32_t>() + 1); // 0-11 means 1 to 12 months
614         pickerDate.SetDay(date->ToNumber<int32_t>());
615     }
616     return pickerDate;
617 }
618 
ParseTime(const JSRef<JSVal> & timeVal)619 PickerTime JSDatePickerDialog::ParseTime(const JSRef<JSVal>& timeVal)
620 {
621     auto pickerTime = PickerTime();
622     if (!timeVal->IsObject()) {
623         return pickerTime;
624     }
625     auto timeObj = JSRef<JSObject>::Cast(timeVal);
626     auto hourFunc = JSRef<JSFunc>::Cast(timeObj->GetProperty("getHours"));
627     auto minuteFunc = JSRef<JSFunc>::Cast(timeObj->GetProperty("getMinutes"));
628     auto secondFunc = JSRef<JSFunc>::Cast(timeObj->GetProperty("getSeconds"));
629     JSRef<JSVal> hour = hourFunc->Call(timeObj);
630     JSRef<JSVal> minute = minuteFunc->Call(timeObj);
631     JSRef<JSVal> second = secondFunc->Call(timeObj);
632 
633     if (hour->IsNumber() && minute->IsNumber() && second->IsNumber()) {
634         pickerTime.SetHour(hour->ToNumber<int32_t>());
635         pickerTime.SetMinute(minute->ToNumber<int32_t>());
636         pickerTime.SetSecond(second->ToNumber<int32_t>());
637     }
638     return pickerTime;
639 }
640 
JSBind(BindingTarget globalObj)641 void JSTimePicker::JSBind(BindingTarget globalObj)
642 {
643     JSClass<JSTimePicker>::Declare("TimePicker");
644     MethodOptions opt = MethodOptions::NONE;
645     JSClass<JSTimePicker>::StaticMethod("create", &JSTimePicker::Create, opt);
646     JSClass<JSTimePicker>::StaticMethod("onChange", &JSTimePicker::OnChange);
647     JSClass<JSTimePicker>::StaticMethod("backgroundColor", &JSDatePicker::PickerBackgroundColor);
648     JSClass<JSTimePicker>::StaticMethod("useMilitaryTime", &JSTimePicker::UseMilitaryTime);
649     JSClass<JSTimePicker>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
650     JSClass<JSTimePicker>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
651     JSClass<JSTimePicker>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
652     JSClass<JSTimePicker>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
653     JSClass<JSTimePicker>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
654     JSClass<JSTimePicker>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
655     JSClass<JSTimePicker>::Inherit<JSViewAbstract>();
656     JSClass<JSTimePicker>::Bind(globalObj);
657 }
658 
Create(const JSCallbackInfo & info)659 void JSTimePicker::Create(const JSCallbackInfo& info)
660 {
661     JSRef<JSObject> paramObject = JSRef<JSObject>::New();
662     if (info.Length() >= 1 && info[0]->IsObject()) {
663         paramObject = JSRef<JSObject>::Cast(info[0]);
664     }
665     CreateTimePicker(paramObject);
666 }
667 
UseMilitaryTime(bool isUseMilitaryTime)668 void JSTimePicker::UseMilitaryTime(bool isUseMilitaryTime)
669 {
670     TimePickerModel::GetInstance()->SetHour24(isUseMilitaryTime);
671 }
672 
CreateTimePicker(const JSRef<JSObject> & paramObj)673 void JSTimePicker::CreateTimePicker(const JSRef<JSObject>& paramObj)
674 {
675     auto selectedTime = paramObj->GetProperty("selected");
676     auto theme = GetTheme<PickerTheme>();
677     if (!theme) {
678         LOGE("timePicker Theme is null");
679         return;
680     }
681     TimePickerModel::GetInstance()->CreateTimePicker(theme);
682     if (selectedTime->IsObject()) {
683         TimePickerModel::GetInstance()->SetSelectedTime(ParseTime(selectedTime));
684     }
685 }
686 
ParseTime(const JSRef<JSVal> & timeVal)687 PickerTime JSTimePicker::ParseTime(const JSRef<JSVal>& timeVal)
688 {
689     auto pickerTime = PickerTime();
690     if (!timeVal->IsObject()) {
691         return pickerTime;
692     }
693     auto timeObj = JSRef<JSObject>::Cast(timeVal);
694     auto hourFunc = JSRef<JSFunc>::Cast(timeObj->GetProperty("getHours"));
695     auto minuteFunc = JSRef<JSFunc>::Cast(timeObj->GetProperty("getMinutes"));
696     auto secondFunc = JSRef<JSFunc>::Cast(timeObj->GetProperty("getSeconds"));
697     JSRef<JSVal> hour = hourFunc->Call(timeObj);
698     JSRef<JSVal> minute = minuteFunc->Call(timeObj);
699     JSRef<JSVal> second = secondFunc->Call(timeObj);
700 
701     if (hour->IsNumber() && minute->IsNumber() && second->IsNumber()) {
702         pickerTime.SetHour(hour->ToNumber<int32_t>());
703         pickerTime.SetMinute(minute->ToNumber<int32_t>());
704         pickerTime.SetSecond(second->ToNumber<int32_t>());
705     }
706     return pickerTime;
707 }
708 
JSBind(BindingTarget globalObj)709 void JSTimePickerDialog::JSBind(BindingTarget globalObj)
710 {
711     JSClass<JSTimePickerDialog>::Declare("TimePickerDialog");
712     JSClass<JSTimePickerDialog>::StaticMethod("show", &JSTimePickerDialog::Show);
713 
714     JSClass<JSTimePickerDialog>::Bind<>(globalObj);
715 }
716 
Show(const JSCallbackInfo & info)717 void JSTimePickerDialog::Show(const JSCallbackInfo& info)
718 {
719     auto scopedDelegate = EngineHelper::GetCurrentDelegate();
720     if (!scopedDelegate) {
721         // this case usually means there is no foreground container, need to figure out the reason.
722         LOGE("scopedDelegate is null, please check");
723         return;
724     }
725     if (info.Length() < 1 || !info[0]->IsObject()) {
726         LOGE("DatePicker Show dialog error, info is non-valid");
727         return;
728     }
729 
730     auto paramObject = JSRef<JSObject>::Cast(info[0]);
731 
732     if (Container::IsCurrentUseNewPipeline()) {
733         auto dialogEvent = ChangeDialogEvent(info, DatePickerType::TIME);
734         auto dialogCancelEvent = DialogCancelEvent(info);
735         TimePickerDialogShow(paramObject, dialogEvent, dialogCancelEvent);
736         return;
737     }
738 
739     RefPtr<Component> component;
740     CreateTimePicker(component, paramObject);
741 
742     auto datePicker = AceType::DynamicCast<PickerBaseComponent>(component);
743     DialogProperties properties {};
744     properties.alignment = DialogAlignment::CENTER;
745     properties.customComponent = datePicker;
746     properties.customStyle = true;
747     AddEvent(datePicker, info, DatePickerType::TIME);
748     datePicker->SetDialogName("TimePickerDialog");
749     datePicker->OpenDialog(properties);
750 }
751 
TimePickerDialogShow(const JSRef<JSObject> & paramObj,const std::map<std::string,NG::DialogEvent> & dialogEvent,const std::map<std::string,NG::DialogGestureEvent> & dialogCancelEvent)752 void JSTimePickerDialog::TimePickerDialogShow(const JSRef<JSObject>& paramObj,
753     const std::map<std::string, NG::DialogEvent>& dialogEvent,
754     const std::map<std::string, NG::DialogGestureEvent>& dialogCancelEvent)
755 {
756     auto container = Container::Current();
757     if (!container) {
758         return;
759     }
760     auto pipelineContext = AccessibilityManager::DynamicCast<NG::PipelineContext>(container->GetPipelineContext());
761     if (!pipelineContext) {
762         return;
763     }
764 
765     auto executor = pipelineContext->GetTaskExecutor();
766     if (!executor) {
767         return;
768     }
769 
770     auto selectedTime = paramObj->GetProperty("selected");
771     auto useMilitaryTime = paramObj->GetProperty("useMilitaryTime");
772     bool isUseMilitaryTime = useMilitaryTime->ToBoolean();
773     PickerDate dialogTitleDate = PickerDate::Current();
774 
775     auto theme = JSAlertDialog::GetTheme<DialogTheme>();
776     if (!theme) {
777         LOGE("DialogTheme is null");
778         return;
779     }
780 
781     ButtonInfo buttonInfo;
782     DialogProperties properties;
783     if (SystemProperties::GetDeviceType() == DeviceType::PHONE) {
784         properties.alignment = DialogAlignment::BOTTOM;
785     } else {
786         properties.alignment = DialogAlignment::CENTER;
787     }
788     properties.customStyle = false;
789     properties.offset = DimensionOffset(Offset(0, -theme->GetMarginBottom().ConvertToPx()));
790 
791     std::map<std::string, PickerTime> timePickerProperty;
792     if (selectedTime->IsObject()) {
793         dialogTitleDate = ParseDate(selectedTime);
794         timePickerProperty["selected"] = ParseTime(selectedTime);
795     }
796     auto context = AccessibilityManager::DynamicCast<NG::PipelineContext>(pipelineContext);
797     auto overlayManager = context ? context->GetOverlayManager() : nullptr;
798     executor->PostTask(
799         [properties, timePickerProperty, isUseMilitaryTime, dialogTitleDate, dialogEvent, dialogCancelEvent,
800             weak = WeakPtr<NG::OverlayManager>(overlayManager)] {
801             auto overlayManager = weak.Upgrade();
802             CHECK_NULL_VOID(overlayManager);
803             overlayManager->ShowTimeDialog(
804                 properties, timePickerProperty, isUseMilitaryTime, dialogTitleDate, dialogEvent, dialogCancelEvent);
805         },
806         TaskExecutor::TaskType::UI);
807 }
808 
ParseDate(const JSRef<JSVal> & dateVal)809 PickerDate JSTimePickerDialog::ParseDate(const JSRef<JSVal>& dateVal)
810 {
811     auto pickerDate = PickerDate();
812     if (!dateVal->IsObject()) {
813         return pickerDate;
814     }
815     auto dateObj = JSRef<JSObject>::Cast(dateVal);
816     auto yearFunc = JSRef<JSFunc>::Cast(dateObj->GetProperty("getFullYear"));
817     auto monthFunc = JSRef<JSFunc>::Cast(dateObj->GetProperty("getMonth"));
818     auto dateFunc = JSRef<JSFunc>::Cast(dateObj->GetProperty("getDate"));
819     JSRef<JSVal> year = yearFunc->Call(dateObj);
820     JSRef<JSVal> month = monthFunc->Call(dateObj);
821     JSRef<JSVal> date = dateFunc->Call(dateObj);
822 
823     if (year->IsNumber() && month->IsNumber() && date->IsNumber()) {
824         pickerDate.SetYear(year->ToNumber<int32_t>());
825         pickerDate.SetMonth(month->ToNumber<int32_t>() + 1); // 0-11 means 1 to 12 months
826         pickerDate.SetDay(date->ToNumber<int32_t>());
827     }
828     return pickerDate;
829 }
830 
CreateTimePicker(RefPtr<Component> & component,const JSRef<JSObject> & paramObj)831 void JSTimePickerDialog::CreateTimePicker(RefPtr<Component>& component, const JSRef<JSObject>& paramObj)
832 {
833     auto timePicker = AceType::MakeRefPtr<PickerTimeComponent>();
834     auto selectedTime = paramObj->GetProperty("selected");
835     auto useMilitaryTime = paramObj->GetProperty("useMilitaryTime");
836     bool isUseMilitaryTime = useMilitaryTime->ToBoolean();
837     if (selectedTime->IsObject()) {
838         timePicker->SetSelectedTime(ParseTime(selectedTime));
839     }
840     timePicker->SetIsDialog(true);
841     timePicker->SetIsCreateDialogComponent(true);
842     timePicker->SetHour24(isUseMilitaryTime);
843     component = timePicker;
844 }
845 
ParseTime(const JSRef<JSVal> & timeVal)846 PickerTime JSTimePickerDialog::ParseTime(const JSRef<JSVal>& timeVal)
847 {
848     auto pickerTime = PickerTime();
849     if (!timeVal->IsObject()) {
850         return pickerTime;
851     }
852     auto timeObj = JSRef<JSObject>::Cast(timeVal);
853     auto hourFunc = JSRef<JSFunc>::Cast(timeObj->GetProperty("getHours"));
854     auto minuteFunc = JSRef<JSFunc>::Cast(timeObj->GetProperty("getMinutes"));
855     auto secondFunc = JSRef<JSFunc>::Cast(timeObj->GetProperty("getSeconds"));
856     JSRef<JSVal> hour = hourFunc->Call(timeObj);
857     JSRef<JSVal> minute = minuteFunc->Call(timeObj);
858     JSRef<JSVal> second = secondFunc->Call(timeObj);
859 
860     if (hour->IsNumber() && minute->IsNumber() && second->IsNumber()) {
861         pickerTime.SetHour(hour->ToNumber<int32_t>());
862         pickerTime.SetMinute(minute->ToNumber<int32_t>());
863         pickerTime.SetSecond(second->ToNumber<int32_t>());
864     }
865     return pickerTime;
866 }
867 } // namespace OHOS::Ace::Framework
868