/* * Copyright (c) 2021-2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "bridge/declarative_frontend/jsview/js_datepicker.h" #include #include "base/log/ace_scoring_log.h" #include "base/utils/utils.h" #include "bridge/common/utils/engine_helper.h" #include "bridge/declarative_frontend/engine/functions/js_function.h" #include "bridge/declarative_frontend/jsview/js_interactable_view.h" #include "bridge/declarative_frontend/jsview/js_view_common_def.h" #include "bridge/declarative_frontend/jsview/models/picker_model_impl.h" #include "bridge/declarative_frontend/jsview/models/timepicker_model_impl.h" #include "bridge/declarative_frontend/view_stack_processor.h" #include "core/components/picker/picker_data.h" #include "core/components/picker/picker_date_component.h" #include "core/components/picker/picker_theme.h" #include "core/components/picker/picker_time_component.h" #include "core/components_ng/base/view_stack_processor.h" #include "core/components_ng/pattern/picker/datepicker_model_ng.h" #include "core/components_ng/pattern/time_picker/timepicker_model.h" #include "core/components_ng/pattern/time_picker/timepicker_model_ng.h" #include "core/components_v2/inspector/inspector_constants.h" #include "core/event/ace_event_helper.h" #include "core/pipeline_ng/pipeline_context.h" namespace OHOS::Ace { std::unique_ptr DatePickerModel::datePickerInstance_ = nullptr; std::unique_ptr TimePickerModel::timePickerInstance_ = nullptr; DatePickerModel* DatePickerModel::GetInstance() { if (!datePickerInstance_) { #ifdef NG_BUILD datePickerInstance_.reset(new NG::DatePickerModelNG()); #else if (Container::IsCurrentUseNewPipeline()) { datePickerInstance_.reset(new NG::DatePickerModelNG()); } else { datePickerInstance_.reset(new Framework::DatePickerModelImpl()); } #endif } return datePickerInstance_.get(); } TimePickerModel* TimePickerModel::GetInstance() { if (!timePickerInstance_) { #ifdef NG_BUILD timePickerInstance_.reset(new NG::TimePickerModelNG()); #else if (Container::IsCurrentUseNewPipeline()) { timePickerInstance_.reset(new NG::TimePickerModelNG()); } else { timePickerInstance_.reset(new Framework::TimePickerModelImpl()); } #endif } return timePickerInstance_.get(); } } // namespace OHOS::Ace namespace OHOS::Ace::Framework { namespace { void AddEvent(RefPtr& picker, const JSCallbackInfo& info, DatePickerType pickerType) { if (info.Length() < 1 || !info[0]->IsObject()) { LOGE("DatePicker AddEvent error, info is non-valid"); return; } auto paramObject = JSRef::Cast(info[0]); auto onAccept = paramObject->GetProperty("onAccept"); if (!onAccept->IsUndefined() && onAccept->IsFunction()) { auto jsFunc = AceType::MakeRefPtr(JSRef(), JSRef::Cast(onAccept)); auto acceptId = EventMarker([execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](const std::string& info) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); std::vector keys = { "year", "month", "day", "hour", "minute", "second" }; ACE_SCORING_EVENT("DatePickerDialog.onAccept"); func->Execute(keys, info); }); picker->SetDialogAcceptEvent(acceptId); } auto onCancel = paramObject->GetProperty("onCancel"); if (!onCancel->IsUndefined() && onCancel->IsFunction()) { auto jsFunc = AceType::MakeRefPtr(JSRef(), JSRef::Cast(onCancel)); auto cancelId = EventMarker([execCtx = info.GetExecutionContext(), func = std::move(jsFunc)]() { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); ACE_SCORING_EVENT("DatePickerDialog.onCancel"); func->Execute(); }); picker->SetDialogCancelEvent(cancelId); } auto onChange = paramObject->GetProperty("onChange"); if (!onChange->IsUndefined() && onChange->IsFunction()) { auto jsFunc = AceType::MakeRefPtr(JSRef(), JSRef::Cast(onChange)); auto changeId = EventMarker([execCtx = info.GetExecutionContext(), type = pickerType, func = std::move(jsFunc)]( const std::string& info) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); std::vector keys; if (type == DatePickerType::DATE) { keys = { "year", "month", "day" }; } else { keys = { "hour", "minute" }; } ACE_SCORING_EVENT("DatePickerDialog.onChange"); func->Execute(keys, info); }); picker->SetDialogChangeEvent(changeId); } } std::map ChangeDialogEvent(const JSCallbackInfo& info, DatePickerType pickerType) { std::map dialogEvent; if (info.Length() < 1 || !info[0]->IsObject()) { LOGE("DatePicker AddEvent error, info is non-valid"); return dialogEvent; } auto paramObject = JSRef::Cast(info[0]); auto onChange = paramObject->GetProperty("onChange"); if (!onChange->IsUndefined() && onChange->IsFunction()) { auto jsFunc = AceType::MakeRefPtr(JSRef(), JSRef::Cast(onChange)); auto changeId = [execCtx = info.GetExecutionContext(), type = pickerType, func = std::move(jsFunc)]( const std::string& info) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); std::vector keys; if (type == DatePickerType::DATE) { keys = { "year", "month", "day" }; } else { keys = { "hour", "minute" }; } ACE_SCORING_EVENT("DatePickerDialog.onChange"); func->Execute(keys, info); }; dialogEvent["changeId"] = changeId; } auto onAccept = paramObject->GetProperty("onAccept"); if (!onAccept->IsUndefined() && onAccept->IsFunction()) { auto jsFunc = AceType::MakeRefPtr(JSRef(), JSRef::Cast(onAccept)); auto acceptId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](const std::string& info) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); std::vector keys = { "year", "month", "day", "hour", "minute", "second" }; ACE_SCORING_EVENT("DatePickerDialog.onAccept"); func->Execute(keys, info); }; dialogEvent["acceptId"] = acceptId; } return dialogEvent; } std::map DialogCancelEvent(const JSCallbackInfo& info) { std::map dialogCancelEvent; if (info.Length() < 1 || !info[0]->IsObject()) { LOGE("DatePicker AddEvent error, info is non-valid"); return dialogCancelEvent; } auto paramObject = JSRef::Cast(info[0]); auto onCancel = paramObject->GetProperty("onCancel"); if (!onCancel->IsUndefined() && onCancel->IsFunction()) { auto jsFunc = AceType::MakeRefPtr(JSRef(), JSRef::Cast(onCancel)); auto cancelId = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](const GestureEvent& /*info*/) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); ACE_SCORING_EVENT("DatePickerDialog.onCancel"); func->Execute(); }; dialogCancelEvent["cancelId"] = cancelId; } return dialogCancelEvent; } JSRef DatePickerChangeEventToJSValue(const DatePickerChangeEvent& eventInfo) { JSRef obj = JSRef::New(); std::unique_ptr argsPtr = JsonUtil::ParseJsonString(eventInfo.GetSelectedStr()); if (!argsPtr) { LOGW("selectedStr is not exist."); return JSRef::Cast(obj); } std::vector keys = { "year", "month", "day", "hour", "minute", "second" }; for (auto iter = keys.begin(); iter != keys.end(); iter++) { const std::string key = *iter; const auto value = argsPtr->GetValue(key); if (!value || value->ToString().empty()) { LOGI("key[%{public}s] is not exist.", key.c_str()); continue; } obj->SetProperty(key.c_str(), value->GetInt()); } return JSRef::Cast(obj); } } // namespace void JSDatePicker::JSBind(BindingTarget globalObj) { JSClass::Declare("DatePicker"); MethodOptions opt = MethodOptions::NONE; JSClass::StaticMethod("create", &JSDatePicker::Create, opt); JSClass::StaticMethod("lunar", &JSDatePicker::SetLunar); JSClass::StaticMethod("onChange", &JSDatePicker::OnChange); JSClass::StaticMethod("backgroundColor", &JSDatePicker::PickerBackgroundColor); // keep compatible, need remove after JSClass::StaticMethod("useMilitaryTime", &JSDatePicker::UseMilitaryTime); JSClass::StaticMethod("onClick", &JSInteractableView::JsOnClick); JSClass::StaticMethod("onTouch", &JSInteractableView::JsOnTouch); JSClass::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey); JSClass::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete); JSClass::StaticMethod("onAppear", &JSInteractableView::JsOnAppear); JSClass::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear); JSClass::Inherit(); JSClass::Bind(globalObj); } void JSDatePicker::Create(const JSCallbackInfo& info) { DatePickerType pickerType = DatePickerType::DATE; JSRef paramObject; if (info.Length() >= 1 && info[0]->IsObject()) { paramObject = JSRef::Cast(info[0]); auto type = paramObject->GetProperty("type"); if (type->IsNumber()) { pickerType = static_cast(type->ToNumber()); } } switch (pickerType) { case DatePickerType::TIME: { CreateTimePicker(paramObject); break; } case DatePickerType::DATE: { CreateDatePicker(paramObject); break; } default: { LOGE("Undefined date picker type."); break; } } } void JSDatePicker::SetLunar(bool isLunar) { DatePickerModel::GetInstance()->SetShowLunar(isLunar); } void JSDatePicker::UseMilitaryTime(bool isUseMilitaryTime) { DatePickerModel::GetInstance()->SetHour24(isUseMilitaryTime); } void JSDatePicker::OnChange(const JSCallbackInfo& info) { if (info.Length() < 1 || !info[0]->IsFunction()) { LOGI("info not function"); return; } auto jsFunc = AceType::MakeRefPtr>( JSRef::Cast(info[0]), DatePickerChangeEventToJSValue); auto onChange = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](const BaseEventInfo* info) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); ACE_SCORING_EVENT("datePicker.onChange"); const auto* eventInfo = TypeInfoHelper::DynamicCast(info); func->Execute(*eventInfo); }; DatePickerModel::GetInstance()->SetOnChange(std::move(onChange)); } void JSTimePicker::OnChange(const JSCallbackInfo& info) { if (info.Length() < 1 || !info[0]->IsFunction()) { LOGI("info not function"); return; } auto jsFunc = AceType::MakeRefPtr>( JSRef::Cast(info[0]), DatePickerChangeEventToJSValue); auto onChange = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](const BaseEventInfo* index) { JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx); ACE_SCORING_EVENT("datePicker.onChange"); const auto* eventInfo = TypeInfoHelper::DynamicCast(index); func->Execute(*eventInfo); }; TimePickerModel::GetInstance()->SetOnChange(std::move(onChange)); } void JSDatePicker::PickerBackgroundColor(const JSCallbackInfo& info) { JSViewAbstract::JsBackgroundColor(info); auto pickerBase = AceType::DynamicCast(ViewStackProcessor::GetInstance()->GetMainComponent()); if (!pickerBase) { LOGE("PickerBaseComponent is null"); return; } pickerBase->SetHasBackgroundColor(true); } PickerDate JSDatePicker::ParseDate(const JSRef& dateVal) { auto pickerDate = PickerDate(); if (!dateVal->IsObject()) { return pickerDate; } auto dateObj = JSRef::Cast(dateVal); auto yearFunc = JSRef::Cast(dateObj->GetProperty("getFullYear")); auto monthFunc = JSRef::Cast(dateObj->GetProperty("getMonth")); auto dateFunc = JSRef::Cast(dateObj->GetProperty("getDate")); JSRef year = yearFunc->Call(dateObj); JSRef month = monthFunc->Call(dateObj); JSRef date = dateFunc->Call(dateObj); if (year->IsNumber() && month->IsNumber() && date->IsNumber()) { pickerDate.SetYear(year->ToNumber()); pickerDate.SetMonth(month->ToNumber() + 1); // 0-11 means 1 to 12 months pickerDate.SetDay(date->ToNumber()); } return pickerDate; } PickerTime JSDatePicker::ParseTime(const JSRef& timeVal) { auto pickerTime = PickerTime(); if (!timeVal->IsObject()) { return pickerTime; } auto timeObj = JSRef::Cast(timeVal); auto hourFunc = JSRef::Cast(timeObj->GetProperty("getHours")); auto minuteFunc = JSRef::Cast(timeObj->GetProperty("getMinutes")); auto secondFunc = JSRef::Cast(timeObj->GetProperty("getSeconds")); JSRef hour = hourFunc->Call(timeObj); JSRef minute = minuteFunc->Call(timeObj); JSRef second = secondFunc->Call(timeObj); if (hour->IsNumber() && minute->IsNumber() && second->IsNumber()) { pickerTime.SetHour(hour->ToNumber()); pickerTime.SetMinute(minute->ToNumber()); pickerTime.SetSecond(second->ToNumber()); } return pickerTime; } void JSDatePicker::CreateDatePicker(const JSRef& paramObj) { JSRef startDate; JSRef endDate; JSRef selectedDate; if (!paramObj->IsUndefined()) { startDate = paramObj->GetProperty("start"); endDate = paramObj->GetProperty("end"); selectedDate = paramObj->GetProperty("selected"); } auto parseStartDate = ParseDate(startDate); auto parseEndDate = ParseDate(endDate); auto parseSelectedDate = ParseDate(selectedDate); auto startDays = parseStartDate.ToDays(); auto endDays = parseEndDate.ToDays(); auto selectedDays = parseSelectedDate.ToDays(); if (startDays > endDays || selectedDays < startDays || selectedDays > endDays) { LOGE("date error"); } auto theme = GetTheme(); if (!theme) { LOGE("datePicker Theme is null"); return; } DatePickerModel::GetInstance()->CreateDatePicker(theme); if (startDate->IsObject()) { DatePickerModel::GetInstance()->SetStartDate(parseStartDate); } if (endDate->IsObject()) { DatePickerModel::GetInstance()->SetEndDate(parseEndDate); } if (selectedDate->IsObject()) { DatePickerModel::GetInstance()->SetSelectedDate(parseSelectedDate); } } void JSDatePicker::CreateTimePicker(const JSRef& paramObj) { auto theme = GetTheme(); if (!theme) { LOGE("timePicker Theme is null"); return; } DatePickerModel::GetInstance()->CreateTimePicker(theme); auto selectedTime = paramObj->GetProperty("selected"); if (selectedTime->IsObject()) { DatePickerModel::GetInstance()->SetSelectedTime(ParseTime(selectedTime)); } } void JSDatePickerDialog::JSBind(BindingTarget globalObj) { JSClass::Declare("DatePickerDialog"); JSClass::StaticMethod("show", &JSDatePickerDialog::Show); JSClass::Bind<>(globalObj); } void JSDatePickerDialog::Show(const JSCallbackInfo& info) { auto scopedDelegate = EngineHelper::GetCurrentDelegate(); if (!scopedDelegate) { // this case usually means there is no foreground container, need to figure out the reason. LOGE("scopedDelegate is null, please check"); return; } if (info.Length() < 1 || !info[0]->IsObject()) { LOGE("DatePicker Show dialog error, info is non-valid"); return; } auto paramObject = JSRef::Cast(info[0]); DatePickerType pickerType = DatePickerType::DATE; auto type = paramObject->GetProperty("type"); if (type->IsNumber()) { pickerType = static_cast(type->ToNumber()); } if (Container::IsCurrentUseNewPipeline()) { auto dialogEvent = ChangeDialogEvent(info, DatePickerType::DATE); auto dialogCancelEvent = DialogCancelEvent(info); DatePickerDialogShow(paramObject, dialogEvent, dialogCancelEvent); return; } std::string name; RefPtr component; switch (pickerType) { case DatePickerType::TIME: { CreateTimePicker(component, paramObject); name = "TimePickerDialog"; break; } case DatePickerType::DATE: { CreateDatePicker(component, paramObject); name = "DatePickerDialog"; break; } default: { LOGE("Undefined date picker type."); return; } } auto datePicker = AceType::DynamicCast(component); DialogProperties properties {}; properties.alignment = DialogAlignment::CENTER; properties.customComponent = datePicker; properties.customStyle = true; if (pickerType == DatePickerType::DATE) { AddEvent(datePicker, info, DatePickerType::DATE); } else { AddEvent(datePicker, info, DatePickerType::TIME); } datePicker->SetDialogName(name); datePicker->OpenDialog(properties); } void JSDatePickerDialog::DatePickerDialogShow(const JSRef& paramObj, const std::map& dialogEvent, const std::map& dialogCancelEvent) { auto container = Container::Current(); if (!container) { return; } auto pipelineContext = AccessibilityManager::DynamicCast(container->GetPipelineContext()); if (!pipelineContext) { return; } auto executor = pipelineContext->GetTaskExecutor(); if (!executor) { return; } auto startDate = paramObj->GetProperty("start"); auto endDate = paramObj->GetProperty("end"); auto selectedDate = paramObj->GetProperty("selected"); auto lunar = paramObj->GetProperty("lunar"); bool isLunar = lunar->ToBoolean(); auto parseStartDate = ParseDate(startDate); auto parseEndDate = ParseDate(endDate); auto parseSelectedDate = ParseDate(selectedDate); auto startDays = parseStartDate.ToDays(); auto endDays = parseEndDate.ToDays(); auto selectedDays = parseSelectedDate.ToDays(); if (startDays > endDays || selectedDays < startDays || selectedDays > endDays) { LOGE("date error"); } auto theme = GetTheme(); if (!theme) { LOGE("DialogTheme is null"); return; } ButtonInfo buttonInfo; DialogProperties properties; if (SystemProperties::GetDeviceType() == DeviceType::PHONE) { properties.alignment = DialogAlignment::BOTTOM; } else { properties.alignment = DialogAlignment::CENTER; } properties.customStyle = false; properties.offset = DimensionOffset(Offset(0, -theme->GetMarginBottom().ConvertToPx())); std::map datePickerProperty; if (startDate->IsObject()) { datePickerProperty["start"] = parseStartDate; } if (endDate->IsObject()) { datePickerProperty["end"] = parseEndDate; } if (selectedDate->IsObject()) { datePickerProperty["selected"] = parseSelectedDate; } auto context = AccessibilityManager::DynamicCast(pipelineContext); auto overlayManager = context ? context->GetOverlayManager() : nullptr; executor->PostTask( [properties, datePickerProperty, isLunar, dialogEvent, dialogCancelEvent, weak = WeakPtr(overlayManager)] { auto overlayManager = weak.Upgrade(); CHECK_NULL_VOID(overlayManager); overlayManager->ShowDateDialog(properties, datePickerProperty, isLunar, dialogEvent, dialogCancelEvent); }, TaskExecutor::TaskType::UI); } void JSDatePickerDialog::CreateDatePicker(RefPtr& component, const JSRef& paramObj) { auto datePicker = AceType::MakeRefPtr(); auto startDate = paramObj->GetProperty("start"); auto endDate = paramObj->GetProperty("end"); auto selectedDate = paramObj->GetProperty("selected"); auto lunar = paramObj->GetProperty("lunar"); bool isLunar = lunar->ToBoolean(); auto parseStartDate = ParseDate(startDate); auto parseEndDate = ParseDate(endDate); auto parseSelectedDate = ParseDate(selectedDate); auto startDays = parseStartDate.ToDays(); auto endDays = parseEndDate.ToDays(); auto selectedDays = parseSelectedDate.ToDays(); if (startDays > endDays || selectedDays < startDays || selectedDays > endDays) { LOGE("date error"); } if (startDate->IsObject()) { datePicker->SetStartDate(parseStartDate); } if (endDate->IsObject()) { datePicker->SetEndDate(parseEndDate); } if (selectedDate->IsObject()) { datePicker->SetSelectedDate(parseSelectedDate); } datePicker->SetIsDialog(true); datePicker->SetIsCreateDialogComponent(true); datePicker->SetShowLunar(isLunar); component = datePicker; } void JSDatePickerDialog::CreateTimePicker(RefPtr& component, const JSRef& paramObj) { auto timePicker = AceType::MakeRefPtr(); auto selectedTime = paramObj->GetProperty("selected"); auto useMilitaryTime = paramObj->GetProperty("useMilitaryTime"); bool isUseMilitaryTime = useMilitaryTime->ToBoolean(); if (selectedTime->IsObject()) { timePicker->SetSelectedTime(ParseTime(selectedTime)); } timePicker->SetIsDialog(true); timePicker->SetIsCreateDialogComponent(true); timePicker->SetHour24(isUseMilitaryTime); component = timePicker; } PickerDate JSDatePickerDialog::ParseDate(const JSRef& dateVal) { auto pickerDate = PickerDate(); if (!dateVal->IsObject()) { return pickerDate; } auto dateObj = JSRef::Cast(dateVal); auto yearFunc = JSRef::Cast(dateObj->GetProperty("getFullYear")); auto monthFunc = JSRef::Cast(dateObj->GetProperty("getMonth")); auto dateFunc = JSRef::Cast(dateObj->GetProperty("getDate")); JSRef year = yearFunc->Call(dateObj); JSRef month = monthFunc->Call(dateObj); JSRef date = dateFunc->Call(dateObj); if (year->IsNumber() && month->IsNumber() && date->IsNumber()) { pickerDate.SetYear(year->ToNumber()); pickerDate.SetMonth(month->ToNumber() + 1); // 0-11 means 1 to 12 months pickerDate.SetDay(date->ToNumber()); } return pickerDate; } PickerTime JSDatePickerDialog::ParseTime(const JSRef& timeVal) { auto pickerTime = PickerTime(); if (!timeVal->IsObject()) { return pickerTime; } auto timeObj = JSRef::Cast(timeVal); auto hourFunc = JSRef::Cast(timeObj->GetProperty("getHours")); auto minuteFunc = JSRef::Cast(timeObj->GetProperty("getMinutes")); auto secondFunc = JSRef::Cast(timeObj->GetProperty("getSeconds")); JSRef hour = hourFunc->Call(timeObj); JSRef minute = minuteFunc->Call(timeObj); JSRef second = secondFunc->Call(timeObj); if (hour->IsNumber() && minute->IsNumber() && second->IsNumber()) { pickerTime.SetHour(hour->ToNumber()); pickerTime.SetMinute(minute->ToNumber()); pickerTime.SetSecond(second->ToNumber()); } return pickerTime; } void JSTimePicker::JSBind(BindingTarget globalObj) { JSClass::Declare("TimePicker"); MethodOptions opt = MethodOptions::NONE; JSClass::StaticMethod("create", &JSTimePicker::Create, opt); JSClass::StaticMethod("onChange", &JSTimePicker::OnChange); JSClass::StaticMethod("backgroundColor", &JSDatePicker::PickerBackgroundColor); JSClass::StaticMethod("useMilitaryTime", &JSTimePicker::UseMilitaryTime); JSClass::StaticMethod("onClick", &JSInteractableView::JsOnClick); JSClass::StaticMethod("onTouch", &JSInteractableView::JsOnTouch); JSClass::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey); JSClass::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete); JSClass::StaticMethod("onAppear", &JSInteractableView::JsOnAppear); JSClass::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear); JSClass::Inherit(); JSClass::Bind(globalObj); } void JSTimePicker::Create(const JSCallbackInfo& info) { JSRef paramObject = JSRef::New(); if (info.Length() >= 1 && info[0]->IsObject()) { paramObject = JSRef::Cast(info[0]); } CreateTimePicker(paramObject); } void JSTimePicker::UseMilitaryTime(bool isUseMilitaryTime) { TimePickerModel::GetInstance()->SetHour24(isUseMilitaryTime); } void JSTimePicker::CreateTimePicker(const JSRef& paramObj) { auto selectedTime = paramObj->GetProperty("selected"); auto theme = GetTheme(); if (!theme) { LOGE("timePicker Theme is null"); return; } TimePickerModel::GetInstance()->CreateTimePicker(theme); if (selectedTime->IsObject()) { TimePickerModel::GetInstance()->SetSelectedTime(ParseTime(selectedTime)); } } PickerTime JSTimePicker::ParseTime(const JSRef& timeVal) { auto pickerTime = PickerTime(); if (!timeVal->IsObject()) { return pickerTime; } auto timeObj = JSRef::Cast(timeVal); auto hourFunc = JSRef::Cast(timeObj->GetProperty("getHours")); auto minuteFunc = JSRef::Cast(timeObj->GetProperty("getMinutes")); auto secondFunc = JSRef::Cast(timeObj->GetProperty("getSeconds")); JSRef hour = hourFunc->Call(timeObj); JSRef minute = minuteFunc->Call(timeObj); JSRef second = secondFunc->Call(timeObj); if (hour->IsNumber() && minute->IsNumber() && second->IsNumber()) { pickerTime.SetHour(hour->ToNumber()); pickerTime.SetMinute(minute->ToNumber()); pickerTime.SetSecond(second->ToNumber()); } return pickerTime; } void JSTimePickerDialog::JSBind(BindingTarget globalObj) { JSClass::Declare("TimePickerDialog"); JSClass::StaticMethod("show", &JSTimePickerDialog::Show); JSClass::Bind<>(globalObj); } void JSTimePickerDialog::Show(const JSCallbackInfo& info) { auto scopedDelegate = EngineHelper::GetCurrentDelegate(); if (!scopedDelegate) { // this case usually means there is no foreground container, need to figure out the reason. LOGE("scopedDelegate is null, please check"); return; } if (info.Length() < 1 || !info[0]->IsObject()) { LOGE("DatePicker Show dialog error, info is non-valid"); return; } auto paramObject = JSRef::Cast(info[0]); if (Container::IsCurrentUseNewPipeline()) { auto dialogEvent = ChangeDialogEvent(info, DatePickerType::TIME); auto dialogCancelEvent = DialogCancelEvent(info); TimePickerDialogShow(paramObject, dialogEvent, dialogCancelEvent); return; } RefPtr component; CreateTimePicker(component, paramObject); auto datePicker = AceType::DynamicCast(component); DialogProperties properties {}; properties.alignment = DialogAlignment::CENTER; properties.customComponent = datePicker; properties.customStyle = true; AddEvent(datePicker, info, DatePickerType::TIME); datePicker->SetDialogName("TimePickerDialog"); datePicker->OpenDialog(properties); } void JSTimePickerDialog::TimePickerDialogShow(const JSRef& paramObj, const std::map& dialogEvent, const std::map& dialogCancelEvent) { auto container = Container::Current(); if (!container) { return; } auto pipelineContext = AccessibilityManager::DynamicCast(container->GetPipelineContext()); if (!pipelineContext) { return; } auto executor = pipelineContext->GetTaskExecutor(); if (!executor) { return; } auto selectedTime = paramObj->GetProperty("selected"); auto useMilitaryTime = paramObj->GetProperty("useMilitaryTime"); bool isUseMilitaryTime = useMilitaryTime->ToBoolean(); PickerDate dialogTitleDate = PickerDate::Current(); auto theme = JSAlertDialog::GetTheme(); if (!theme) { LOGE("DialogTheme is null"); return; } ButtonInfo buttonInfo; DialogProperties properties; if (SystemProperties::GetDeviceType() == DeviceType::PHONE) { properties.alignment = DialogAlignment::BOTTOM; } else { properties.alignment = DialogAlignment::CENTER; } properties.customStyle = false; properties.offset = DimensionOffset(Offset(0, -theme->GetMarginBottom().ConvertToPx())); std::map timePickerProperty; if (selectedTime->IsObject()) { dialogTitleDate = ParseDate(selectedTime); timePickerProperty["selected"] = ParseTime(selectedTime); } auto context = AccessibilityManager::DynamicCast(pipelineContext); auto overlayManager = context ? context->GetOverlayManager() : nullptr; executor->PostTask( [properties, timePickerProperty, isUseMilitaryTime, dialogTitleDate, dialogEvent, dialogCancelEvent, weak = WeakPtr(overlayManager)] { auto overlayManager = weak.Upgrade(); CHECK_NULL_VOID(overlayManager); overlayManager->ShowTimeDialog( properties, timePickerProperty, isUseMilitaryTime, dialogTitleDate, dialogEvent, dialogCancelEvent); }, TaskExecutor::TaskType::UI); } PickerDate JSTimePickerDialog::ParseDate(const JSRef& dateVal) { auto pickerDate = PickerDate(); if (!dateVal->IsObject()) { return pickerDate; } auto dateObj = JSRef::Cast(dateVal); auto yearFunc = JSRef::Cast(dateObj->GetProperty("getFullYear")); auto monthFunc = JSRef::Cast(dateObj->GetProperty("getMonth")); auto dateFunc = JSRef::Cast(dateObj->GetProperty("getDate")); JSRef year = yearFunc->Call(dateObj); JSRef month = monthFunc->Call(dateObj); JSRef date = dateFunc->Call(dateObj); if (year->IsNumber() && month->IsNumber() && date->IsNumber()) { pickerDate.SetYear(year->ToNumber()); pickerDate.SetMonth(month->ToNumber() + 1); // 0-11 means 1 to 12 months pickerDate.SetDay(date->ToNumber()); } return pickerDate; } void JSTimePickerDialog::CreateTimePicker(RefPtr& component, const JSRef& paramObj) { auto timePicker = AceType::MakeRefPtr(); auto selectedTime = paramObj->GetProperty("selected"); auto useMilitaryTime = paramObj->GetProperty("useMilitaryTime"); bool isUseMilitaryTime = useMilitaryTime->ToBoolean(); if (selectedTime->IsObject()) { timePicker->SetSelectedTime(ParseTime(selectedTime)); } timePicker->SetIsDialog(true); timePicker->SetIsCreateDialogComponent(true); timePicker->SetHour24(isUseMilitaryTime); component = timePicker; } PickerTime JSTimePickerDialog::ParseTime(const JSRef& timeVal) { auto pickerTime = PickerTime(); if (!timeVal->IsObject()) { return pickerTime; } auto timeObj = JSRef::Cast(timeVal); auto hourFunc = JSRef::Cast(timeObj->GetProperty("getHours")); auto minuteFunc = JSRef::Cast(timeObj->GetProperty("getMinutes")); auto secondFunc = JSRef::Cast(timeObj->GetProperty("getSeconds")); JSRef hour = hourFunc->Call(timeObj); JSRef minute = minuteFunc->Call(timeObj); JSRef second = secondFunc->Call(timeObj); if (hour->IsNumber() && minute->IsNumber() && second->IsNumber()) { pickerTime.SetHour(hour->ToNumber()); pickerTime.SetMinute(minute->ToNumber()); pickerTime.SetSecond(second->ToNumber()); } return pickerTime; } } // namespace OHOS::Ace::Framework