1 /*
2 * Copyright (c) 2022-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 "core/components_ng/pattern/picker/datepicker_pattern.h"
17
18 #include <functional>
19 #include <stdint.h>
20 #include <string>
21 #include <utility>
22 #include <vector>
23
24 #include "base/i18n/date_time_sequence.h"
25 #include "base/memory/ace_type.h"
26 #include "base/utils/utils.h"
27 #include "core/components/picker/picker_base_component.h"
28 #include "core/components/theme/icon_theme.h"
29 #include "core/components_ng/base/frame_node.h"
30 #include "core/components_ng/base/inspector_filter.h"
31 #include "core/components_ng/event/click_event.h"
32 #include "core/components_ng/pattern/button/button_pattern.h"
33 #include "core/components_ng/pattern/image/image_layout_property.h"
34 #include "core/components_ng/pattern/picker/datepicker_column_pattern.h"
35 #include "core/components_v2/inspector/inspector_constants.h"
36 #include "core/pipeline/pipeline_base.h"
37 #include "core/pipeline_ng/ui_task_scheduler.h"
38 #include "interfaces/inner_api/ui_session/ui_session_manager.h"
39
40 namespace OHOS::Ace::NG {
41 namespace {
42 constexpr int32_t SINGLE_CHILD_SIZE = 1;
43 constexpr int32_t CHILD_SIZE = 3;
44 constexpr uint32_t MIN_MONTH = 1;
45 constexpr uint32_t MAX_MONTH = 12;
46 constexpr uint32_t MIN_DAY = 1;
47 const Dimension PRESS_INTERVAL = 4.0_vp;
48 const Dimension FOCUS_INTERVAL = 2.0_vp;
49 const Dimension LINE_WIDTH = 1.5_vp;
50 const Dimension PRESS_RADIUS = 8.0_vp;
51 const int32_t INVISIBLE_OPTIONS_COUNT = 2;
52 const int32_t COLUMNS_SIZE = 3;
53 const int32_t COLUMNS_ZERO = 0;
54 const int32_t COLUMNS_ONE = 1;
55 const int32_t COLUMNS_TWO = 2;
56 const int32_t INDEX_YEAR = 0;
57 const int32_t INDEX_MONTH = 1;
58 const int32_t INDEX_DAY = 2;
59 constexpr float DISABLE_ALPHA = 0.6f;
60 const int32_t RATE = 2;
61 const int32_t MONTH_DECEMBER = 12;
62 constexpr int32_t RATIO_ZERO = 0;
63 constexpr int32_t RATIO_ONE = 1;
64 constexpr int32_t SECOND_PAGE = 1;
65 constexpr float PICKER_MAXFONTSCALE = 1.0f;
66 constexpr float DEFAULT_SIZE_ZERO = 0.0f;
67 } // namespace
68 bool DatePickerPattern::inited_ = false;
69 const std::string DatePickerPattern::empty_;
70 const PickerDateF DatePickerPattern::emptyPickerDate_;
71 std::unordered_map<uint32_t, std::string> DatePickerPattern::years_; // year from 1900 to 2100,count is 201
72 std::unordered_map<uint32_t, std::string> DatePickerPattern::solarMonths_; // solar month from 1 to 12,count is 12
73 std::unordered_map<uint32_t, std::string> DatePickerPattern::solarDays_; // solar day from 1 to 31, count is 31
74 std::unordered_map<uint32_t, std::string> DatePickerPattern::lunarMonths_; // lunar month from 1 to 24, count is 24
75 std::unordered_map<uint32_t, std::string> DatePickerPattern::lunarDays_; // lunar day from 1 to 30, count is 30
76 std::vector<std::string> DatePickerPattern::tagOrder_; // order of year month day
77 std::vector<std::string> DatePickerPattern::localizedMonths_;
78
OnAttachToFrameNode()79 void DatePickerPattern::OnAttachToFrameNode()
80 {
81 auto host = GetHost();
82 CHECK_NULL_VOID(host);
83 host->GetRenderContext()->SetClipToFrame(true);
84 host->GetRenderContext()->UpdateClipEdge(true);
85 }
86
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)87 bool DatePickerPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
88 {
89 if (config.skipLayout || config.skipMeasure) {
90 return false;
91 }
92
93 CHECK_NULL_RETURN(dirty, false);
94 auto host = GetHost();
95 CHECK_NULL_RETURN(host, false);
96 auto context = host->GetContext();
97 CHECK_NULL_RETURN(context, false);
98 auto pickerTheme = context->GetTheme<PickerTheme>();
99 CHECK_NULL_RETURN(pickerTheme, false);
100 auto children = host->GetChildren();
101 auto height = pickerTheme->GetDividerSpacing();
102 auto buttonSpace = pickerTheme->GetSelectorItemSpace();
103 auto currentFocusStackChild = DynamicCast<FrameNode>(host->GetChildAtIndex(focusKeyID_));
104 CHECK_NULL_RETURN(currentFocusStackChild, false);
105 auto currentFocusButtonNode = DynamicCast<FrameNode>(currentFocusStackChild->GetFirstChild());
106 CHECK_NULL_RETURN(currentFocusButtonNode, false);
107 for (const auto& child : children) {
108 auto columnNode = DynamicCast<FrameNode>(child->GetLastChild()->GetLastChild());
109 CHECK_NULL_RETURN(columnNode, false);
110 auto width = columnNode->GetGeometryNode()->GetFrameSize().Width();
111 auto datePickerColumnNode = DynamicCast<FrameNode>(child->GetLastChild());
112 CHECK_NULL_RETURN(datePickerColumnNode, false);
113 auto buttonNode = DynamicCast<FrameNode>(child->GetFirstChild());
114 CHECK_NULL_RETURN(buttonNode, false);
115 auto buttonConfirmLayoutProperty = buttonNode->GetLayoutProperty<ButtonLayoutProperty>();
116 buttonConfirmLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT_MAIN_AXIS);
117 buttonConfirmLayoutProperty->UpdateType(ButtonType::NORMAL);
118 buttonConfirmLayoutProperty->UpdateBorderRadius(BorderRadiusProperty(selectorItemRadius_));
119 auto standardButtonHeight = static_cast<float>((height - PRESS_INTERVAL).ConvertToPx());
120 auto maxButtonHeight = static_cast<float>(datePickerColumnNode->GetGeometryNode()->GetFrameSize().Height());
121 auto buttonHeight = Dimension(std::min(standardButtonHeight, maxButtonHeight), DimensionUnit::PX);
122 buttonConfirmLayoutProperty->UpdateUserDefinedIdealSize(
123 CalcSize(CalcLength(width - buttonSpace.ConvertToPx()), CalcLength(buttonHeight)));
124 auto buttonConfirmRenderContext = buttonNode->GetRenderContext();
125 if (!useButtonFocusArea_) {
126 buttonConfirmRenderContext->UpdateBackgroundColor(Color::TRANSPARENT);
127 } else {
128 auto isFocusButton = haveFocus_ && (currentFocusButtonNode == buttonNode);
129 UpdateColumnButtonStyles(columnNode, isFocusButton, false);
130 }
131 buttonNode->MarkModifyDone();
132 buttonNode->MarkDirtyNode();
133 if (GetIsShowInDialog() && GreatNotEqual(standardButtonHeight, maxButtonHeight) &&
134 GreatNotEqual(maxButtonHeight, 0.0f)) {
135 auto parentNode = DynamicCast<FrameNode>(host->GetParent());
136 CHECK_NULL_RETURN(parentNode, false);
137 parentNode->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST);
138 }
139 }
140 return true;
141 }
142
InitSelectorProps()143 void DatePickerPattern::InitSelectorProps()
144 {
145 auto host = GetHost();
146 CHECK_NULL_VOID(host);
147 auto context = host->GetContextRefPtr();
148 CHECK_NULL_VOID(context);
149 auto pickerTheme = context->GetTheme<PickerTheme>();
150 CHECK_NULL_VOID(pickerTheme);
151
152 selectorItemRadius_ = pickerTheme->GetSelectorItemRadius();
153 useButtonFocusArea_ = pickerTheme->NeedButtonFocusAreaType();
154 }
155
InitFocusEvent()156 void DatePickerPattern::InitFocusEvent()
157 {
158 CHECK_NULL_VOID(!focusEventInitialized_);
159 auto host = GetHost();
160 CHECK_NULL_VOID(host);
161 auto context = host->GetContextRefPtr();
162 CHECK_NULL_VOID(context);
163 auto pickerTheme = context->GetTheme<PickerTheme>();
164 CHECK_NULL_VOID(pickerTheme);
165 auto focusHub = host->GetOrCreateFocusHub();
166 CHECK_NULL_VOID(focusHub);
167 auto focusTask = [weak = WeakClaim(this)](FocusReason reason) {
168 auto pattern = weak.Upgrade();
169 CHECK_NULL_VOID(pattern);
170 pattern->HandleFocusEvent();
171 };
172 focusHub->SetOnFocusInternal(focusTask);
173
174 auto blurTask = [weak = WeakClaim(this)]() {
175 auto pattern = weak.Upgrade();
176 CHECK_NULL_VOID(pattern);
177 pattern->HandleBlurEvent();
178 };
179 focusHub->SetOnBlurInternal(blurTask);
180
181 focusEventInitialized_ = true;
182 }
183
AddIsFocusActiveUpdateEvent()184 void DatePickerPattern::AddIsFocusActiveUpdateEvent()
185 {
186 if (!isFocusActiveUpdateEvent_) {
187 isFocusActiveUpdateEvent_ = [weak = WeakClaim(this)](bool isFocusAcitve) {
188 auto pickerPattern = weak.Upgrade();
189 CHECK_NULL_VOID(pickerPattern);
190 pickerPattern->SetHaveFocus(isFocusAcitve);
191 pickerPattern->UpdateFocusButtonState();
192 };
193 }
194
195 auto context = GetContext();
196 CHECK_NULL_VOID(context);
197 context->AddIsFocusActiveUpdateEvent(GetHost(), isFocusActiveUpdateEvent_);
198 }
199
RemoveIsFocusActiveUpdateEvent()200 void DatePickerPattern::RemoveIsFocusActiveUpdateEvent()
201 {
202 auto host = GetHost();
203 CHECK_NULL_VOID(host);
204 auto pipeline = host->GetContext();
205 CHECK_NULL_VOID(pipeline);
206 pipeline->RemoveIsFocusActiveUpdateEvent(host);
207 }
208
SetHaveFocus(bool haveFocus)209 void DatePickerPattern::SetHaveFocus(bool haveFocus)
210 {
211 haveFocus_ = haveFocus;
212 }
213
HandleFocusEvent()214 void DatePickerPattern::HandleFocusEvent()
215 {
216 auto host = GetHost();
217 CHECK_NULL_VOID(host);
218 auto context = host->GetContextRefPtr();
219 CHECK_NULL_VOID(context);
220
221 AddIsFocusActiveUpdateEvent();
222 if (context->GetIsFocusActive()) {
223 SetHaveFocus(true);
224 UpdateFocusButtonState();
225 }
226 }
227
HandleBlurEvent()228 void DatePickerPattern::HandleBlurEvent()
229 {
230 SetHaveFocus(false);
231 RemoveIsFocusActiveUpdateEvent();
232 UpdateFocusButtonState();
233 }
234
UpdateFocusButtonState()235 void DatePickerPattern::UpdateFocusButtonState()
236 {
237 auto host = GetHost();
238 CHECK_NULL_VOID(host);
239 if (useButtonFocusArea_) {
240 auto currentFocusStackNode = DynamicCast<FrameNode>(host->GetChildAtIndex(focusKeyID_));
241 CHECK_NULL_VOID(currentFocusStackNode);
242 auto blendColumnNode = currentFocusStackNode->GetLastChild();
243 CHECK_NULL_VOID(blendColumnNode);
244 auto currentFocusColumnNode = DynamicCast<FrameNode>(blendColumnNode->GetLastChild());
245 CHECK_NULL_VOID(currentFocusColumnNode);
246
247 UpdateColumnButtonStyles(currentFocusColumnNode, haveFocus_, true);
248 }
249 }
250
UpdateColumnButtonStyles(const RefPtr<FrameNode> & columnNode,bool haveFocus,bool needMarkDirty)251 void DatePickerPattern::UpdateColumnButtonStyles(
252 const RefPtr<FrameNode>& columnNode, bool haveFocus, bool needMarkDirty)
253 {
254 CHECK_NULL_VOID(columnNode);
255
256 auto datePickerColumnPattern = columnNode->GetPattern<DatePickerColumnPattern>();
257 CHECK_NULL_VOID(datePickerColumnPattern);
258 datePickerColumnPattern->UpdateColumnButtonFocusState(haveFocus, needMarkDirty);
259 }
260
GetInnerFocusButtonPaintRect(RoundRect & paintRect,float focusButtonXOffset)261 void DatePickerPattern::GetInnerFocusButtonPaintRect(RoundRect& paintRect, float focusButtonXOffset)
262 {
263 auto host = GetHost();
264 CHECK_NULL_VOID(host);
265
266 auto geometryNode = host->GetGeometryNode();
267 CHECK_NULL_VOID(geometryNode);
268 auto context = host->GetContext();
269 CHECK_NULL_VOID(context);
270 auto pickerTheme = context->GetTheme<PickerTheme>();
271 CHECK_NULL_VOID(pickerTheme);
272 auto stackNode = DynamicCast<FrameNode>(host->GetChildAtIndex(focusKeyID_));
273 CHECK_NULL_VOID(stackNode);
274 auto buttonNode = DynamicCast<FrameNode>(stackNode->GetFirstChild());
275 CHECK_NULL_VOID(buttonNode);
276 auto focusButtonRect = buttonNode->GetGeometryNode()->GetFrameRect();
277 auto focusSpace = pickerTheme->GetFocusPadding().ConvertToPx();
278 auto stackRenderContext = stackNode->GetRenderContext();
279 CHECK_NULL_VOID(stackRenderContext);
280 auto leftPadding = 0.0f;
281 if (geometryNode->GetPadding()) {
282 leftPadding = geometryNode->GetPadding()->left.value_or(0.0f);
283 }
284 focusButtonRect -=
285 OffsetF(focusSpace - leftPadding, focusSpace - stackRenderContext->GetPaintRectWithoutTransform().GetY());
286 focusButtonRect += SizeF(focusSpace + focusSpace, focusSpace + focusSpace);
287 focusButtonRect += OffsetF(focusButtonXOffset, 0);
288
289 paintRect.SetRect(focusButtonRect);
290 paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_LEFT_POS,
291 static_cast<RSScalar>(selectorItemRadius_.ConvertToPx()),
292 static_cast<RSScalar>(selectorItemRadius_.ConvertToPx()));
293 paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_RIGHT_POS,
294 static_cast<RSScalar>(selectorItemRadius_.ConvertToPx()),
295 static_cast<RSScalar>(selectorItemRadius_.ConvertToPx()));
296 paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_LEFT_POS,
297 static_cast<RSScalar>(selectorItemRadius_.ConvertToPx()),
298 static_cast<RSScalar>(selectorItemRadius_.ConvertToPx()));
299 paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_RIGHT_POS,
300 static_cast<RSScalar>(selectorItemRadius_.ConvertToPx()),
301 static_cast<RSScalar>(selectorItemRadius_.ConvertToPx()));
302 }
303
ColumnPatternInitHapticController()304 void DatePickerPattern::ColumnPatternInitHapticController()
305 {
306 if (!isHapticChanged_) {
307 return;
308 }
309 isHapticChanged_ = false;
310 auto frameNodes = GetAllChildNode();
311 for (auto iter : frameNodes) {
312 auto columnNode = iter.second;
313 if (!columnNode) {
314 continue;
315 }
316 auto columnPattern = columnNode->GetPattern<DatePickerColumnPattern>();
317 if (!columnPattern) {
318 continue;
319 }
320 columnPattern->InitHapticController(columnNode);
321 }
322 }
323
ColumnPatternInitHapticController(const RefPtr<FrameNode> & columnNode)324 void DatePickerPattern::ColumnPatternInitHapticController(const RefPtr<FrameNode>& columnNode)
325 {
326 CHECK_NULL_VOID(columnNode);
327 if (!isHapticChanged_) {
328 return;
329 }
330 isHapticChanged_ = false;
331 auto columnPattern = columnNode->GetPattern<DatePickerColumnPattern>();
332 CHECK_NULL_VOID(columnPattern);
333 columnPattern->InitHapticController(columnNode);
334 }
335
ColumnPatternStopHaptic()336 void DatePickerPattern::ColumnPatternStopHaptic()
337 {
338 if (!isEnableHaptic_) {
339 return;
340 }
341 auto host = GetHost();
342 CHECK_NULL_VOID(host);
343 auto children = host->GetChildren();
344 for (const auto& child : children) {
345 auto stackNode = DynamicCast<FrameNode>(child);
346 CHECK_NULL_VOID(stackNode);
347 auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
348 CHECK_NULL_VOID(blendNode);
349 auto childNode = blendNode->GetLastChild();
350 CHECK_NULL_VOID(childNode);
351 auto datePickerColumnPattern = DynamicCast<FrameNode>(childNode)->GetPattern<DatePickerColumnPattern>();
352 CHECK_NULL_VOID(datePickerColumnPattern);
353 datePickerColumnPattern->StopHaptic();
354 }
355 }
356
InitFocusKeyEvent()357 void DatePickerPattern::InitFocusKeyEvent()
358 {
359 auto host = GetHost();
360 CHECK_NULL_VOID(host);
361 auto focusHub = host->GetFocusHub();
362 if (focusHub) {
363 InitOnKeyEvent(focusHub);
364 #ifdef SUPPORT_DIGITAL_CROWN
365 InitOnCrownEvent(focusHub);
366 #endif
367 }
368 }
369
FlushChildNodes()370 void DatePickerPattern::FlushChildNodes()
371 {
372 auto frameNodes = GetAllChildNode();
373 for (auto it : frameNodes) {
374 CHECK_NULL_VOID(it.second);
375 it.second->MarkModifyDone();
376 it.second->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
377 }
378 }
379
OnModifyDone()380 void DatePickerPattern::OnModifyDone()
381 {
382 Pattern::CheckLocalized();
383 auto host = GetHost();
384 CHECK_NULL_VOID(host);
385 auto datePickerRowLayoutProperty = host->GetLayoutProperty<DataPickerRowLayoutProperty>();
386 CHECK_NULL_VOID(datePickerRowLayoutProperty);
387 if (host->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
388 ColumnPatternInitHapticController();
389 isHapticChanged_ = false;
390 }
391 isForceUpdate_ = isForceUpdate_ ||
392 (lunar_ != datePickerRowLayoutProperty->GetLunar().value_or(false)) ||
393 (isLoop_ != datePickerRowLayoutProperty->GetCanLoopValue(true));
394 if (isFiredDateChange_ && !isForceUpdate_ && !isDateOrderChange_) {
395 isFiredDateChange_ = false;
396 return;
397 }
398 ClearFocus();
399 isForceUpdate_ = false;
400 isDateOrderChange_ = false;
401 isLoop_ = datePickerRowLayoutProperty->GetCanLoopValue(true);
402 InitDisabled();
403 if (ShowMonthDays()) {
404 FlushMonthDaysColumn();
405 } else {
406 FlushColumn();
407 }
408 ShowTitle(GetTitleId());
409 SetChangeCallback([weak = WeakClaim(this)](const RefPtr<FrameNode>& tag, bool add, uint32_t index, bool notify) {
410 auto refPtr = weak.Upgrade();
411 CHECK_NULL_VOID(refPtr);
412 refPtr->HandleColumnChange(tag, add, index, notify);
413 });
414 SetEventCallback([weak = WeakClaim(this), titleId = GetTitleId()](bool refresh) {
415 auto refPtr = weak.Upgrade();
416 CHECK_NULL_VOID(refPtr);
417 refPtr->FireChangeEvent(refresh);
418 if (refresh) {
419 refPtr->ShowTitle(titleId);
420 }
421 });
422 InitFocusKeyEvent();
423 SetDefaultFocus();
424 InitFocusEvent();
425 InitSelectorProps();
426 FlushChildNodes();
427 }
428
InitDisabled()429 void DatePickerPattern::InitDisabled()
430 {
431 auto host = GetHost();
432 CHECK_NULL_VOID(host);
433 auto eventHub = host->GetOrCreateEventHub<EventHub>();
434 CHECK_NULL_VOID(eventHub);
435 enabled_ = eventHub->IsEnabled();
436 auto renderContext = host->GetRenderContext();
437 CHECK_NULL_VOID(renderContext);
438 auto opacity = curOpacity_;
439 if (!enabled_) {
440 opacity *= DISABLE_ALPHA;
441 renderContext->UpdateOpacity(opacity);
442 } else if (host->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
443 renderContext->UpdateOpacity(opacity);
444 }
445
446 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
447 for (const auto& child : host->GetChildren()) {
448 auto stackNode = DynamicCast<FrameNode>(child);
449 CHECK_NULL_VOID(stackNode);
450 auto renderContext = stackNode->GetRenderContext();
451 CHECK_NULL_VOID(renderContext);
452 renderContext->UpdateOpacity(opacity);
453 }
454 }
455 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
456 }
457
UpdateButtonMargin(const RefPtr<FrameNode> & buttonNode,const RefPtr<DialogTheme> & dialogTheme,const bool isConfirmOrNextNode)458 void DatePickerPattern::UpdateButtonMargin(
459 const RefPtr<FrameNode>& buttonNode, const RefPtr<DialogTheme>& dialogTheme, const bool isConfirmOrNextNode)
460 {
461 MarginProperty margin;
462 bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
463 isRtl = isConfirmOrNextNode ? isRtl : !isRtl;
464 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
465 DialogTypeMargin::UpdateDialogMargin(isRtl, margin, dialogTheme, true, ModuleDialogType::DATEPICKER_DIALOG);
466 } else {
467 DialogTypeMargin::UpdateDialogMargin(isRtl, margin, dialogTheme, false, ModuleDialogType::DATEPICKER_DIALOG);
468 }
469 buttonNode->GetLayoutProperty()->UpdateMargin(margin);
470 }
471
OnFontConfigurationUpdate()472 void DatePickerPattern::OnFontConfigurationUpdate()
473 {
474 CHECK_NULL_VOID(closeDialogEvent_);
475 closeDialogEvent_();
476 }
477
OnFontScaleConfigurationUpdate()478 void DatePickerPattern::OnFontScaleConfigurationUpdate()
479 {
480 CHECK_NULL_VOID(closeDialogEvent_);
481 closeDialogEvent_();
482 }
483
UpdateButtonNode(const RefPtr<FrameNode> & buttonNode,const bool isConfirmNode)484 void DatePickerPattern::UpdateButtonNode(const RefPtr<FrameNode>& buttonNode, const bool isConfirmNode)
485 {
486 CHECK_NULL_VOID(buttonNode);
487 auto updateNode = AceType::DynamicCast<FrameNode>(buttonNode->GetFirstChild());
488 CHECK_NULL_VOID(updateNode);
489 auto updateNodeLayout = updateNode->GetLayoutProperty<TextLayoutProperty>();
490 CHECK_NULL_VOID(updateNodeLayout);
491
492 auto pipeline = updateNode->GetContextRefPtr();
493 CHECK_NULL_VOID(pipeline);
494 auto dialogTheme = pipeline->GetTheme<DialogTheme>();
495 CHECK_NULL_VOID(dialogTheme);
496 std::string lettersStr = isConfirmNode ? dialogTheme->GetConfirmText() : dialogTheme->GetCancelText();
497 updateNodeLayout->UpdateContent(lettersStr);
498
499 UpdateButtonMargin(buttonNode, dialogTheme, isConfirmNode);
500 updateNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
501 }
502
UpdateLunarSwitch()503 void DatePickerPattern::UpdateLunarSwitch()
504 {
505 auto lunarSwitchNode = weakLunarSwitchText_.Upgrade();
506 CHECK_NULL_VOID(lunarSwitchNode);
507 auto context = lunarSwitchNode->GetContextRefPtr();
508 CHECK_NULL_VOID(context);
509 auto pickerTheme = context->GetTheme<PickerTheme>();
510 CHECK_NULL_VOID(pickerTheme);
511 auto lunarSwitchTextLayoutProperty = lunarSwitchNode->GetLayoutProperty<TextLayoutProperty>();
512 CHECK_NULL_VOID(lunarSwitchTextLayoutProperty);
513 lunarSwitchTextLayoutProperty->UpdateContent(pickerTheme->GetLunarSwitchText());
514 lunarSwitchTextLayoutProperty->UpdateTextColor(pickerTheme->GetLunarSwitchTextColor());
515 lunarSwitchNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
516
517 auto lunarSwitchCheckbox = weakLunarSwitchCheckbox_.Upgrade();
518 CHECK_NULL_VOID(lunarSwitchCheckbox);
519 auto checkboxLayoutProps = lunarSwitchCheckbox->GetLayoutProperty<LayoutProperty>();
520 CHECK_NULL_VOID(checkboxLayoutProps);
521 MarginProperty marginCheckbox;
522 bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
523 marginCheckbox.left = isRtl ? CalcLength(PICKER_MARGIN_FROM_TITLE_AND_BUTTON)
524 : CalcLength(PICKER_DIALOG_MARGIN_FORM_EDGE);
525 marginCheckbox.right = isRtl ? CalcLength(PICKER_DIALOG_MARGIN_FORM_EDGE)
526 : CalcLength(PICKER_MARGIN_FROM_TITLE_AND_BUTTON);
527 checkboxLayoutProps->UpdateMargin(marginCheckbox);
528 lunarSwitchCheckbox->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
529 }
530
UpdateDateOrder()531 void DatePickerPattern::UpdateDateOrder()
532 {
533 auto language = AceApplicationInfo::GetInstance().GetLanguage();
534 std::string dateOrder = "y-d-M";
535 if (language != "ug") {
536 DateTimeSequence sequence;
537 OrderResult orderResult = sequence.GetDateOrder(language);
538 dateOrder = orderResult.dateOrder;
539 }
540 SetDateOrder(dateOrder);
541
542 auto host = GetHost();
543 CHECK_NULL_VOID(host);
544 auto layoutProperty = host->GetLayoutProperty();
545 CHECK_NULL_VOID(layoutProperty);
546 if (language == "ar" && layoutProperty->GetLayoutDirection() != TextDirection::RTL) {
547 layoutProperty->UpdateLayoutDirection(TextDirection::LTR);
548 isDirectionSetByAr = true;
549 } else if (isDirectionSetByAr) {
550 layoutProperty->UpdateLayoutDirection(TextDirection::AUTO);
551 isDirectionSetByAr = false;
552 }
553 }
554
UpdateDialogAgingButton(const RefPtr<FrameNode> & buttonNode,bool isNext)555 void DatePickerPattern::UpdateDialogAgingButton(const RefPtr<FrameNode>& buttonNode, bool isNext)
556 {
557 CHECK_NULL_VOID(buttonNode);
558 auto updateNode = AceType::DynamicCast<FrameNode>(buttonNode->GetFirstChild());
559 CHECK_NULL_VOID(updateNode);
560 auto updateNodeLayout = updateNode->GetLayoutProperty<TextLayoutProperty>();
561 CHECK_NULL_VOID(updateNodeLayout);
562
563 auto pipeline = updateNode->GetContext();
564 CHECK_NULL_VOID(pipeline);
565 auto dialogTheme = pipeline->GetTheme<DialogTheme>();
566 CHECK_NULL_VOID(dialogTheme);
567 auto pickerTheme = pipeline->GetTheme<PickerTheme>();
568 CHECK_NULL_VOID(pickerTheme);
569 std::string lettersStr = isNext ? pickerTheme->GetNextText() : pickerTheme->GetPrevText();
570 updateNodeLayout->UpdateContent(lettersStr);
571
572 UpdateButtonMargin(buttonNode, dialogTheme, isNext);
573 updateNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
574 }
575
OnLanguageConfigurationUpdate()576 void DatePickerPattern::OnLanguageConfigurationUpdate()
577 {
578 auto buttonConfirmNode = weakButtonConfirm_.Upgrade();
579 UpdateButtonNode(buttonConfirmNode, true);
580
581 auto buttonCancelNode = weakButtonCancel_.Upgrade();
582 UpdateButtonNode(buttonCancelNode, false);
583
584 UpdateLunarSwitch();
585 UpdateDateOrder();
586
587 auto nextPrevButton = nextPrevButtonNode_.Upgrade();
588 UpdateDialogAgingButton(nextPrevButton, isNext_);
589 }
590
HandleColumnChange(const RefPtr<FrameNode> & tag,bool isAdd,uint32_t index,bool needNotify)591 void DatePickerPattern::HandleColumnChange(const RefPtr<FrameNode>& tag, bool isAdd, uint32_t index, bool needNotify)
592 {
593 CHECK_NULL_VOID(GetHost());
594 std::vector<RefPtr<FrameNode>> tags;
595 if (ShowMonthDays()) {
596 HandleMonthDaysChange(tag, isAdd, index, tags);
597 } else {
598 OnDataLinking(tag, isAdd, index, tags);
599 }
600 for (const auto& tag : tags) {
601 auto iter = std::find_if(datePickerColumns_.begin(), datePickerColumns_.end(), [&tag](const auto& c) {
602 auto column = c.Upgrade();
603 return column && column->GetId() == tag->GetId();
604 });
605 if (iter != datePickerColumns_.end()) {
606 auto datePickerColumn = (*iter).Upgrade();
607 CHECK_NULL_VOID(datePickerColumn);
608 auto datePickerColumnPattern = datePickerColumn->GetPattern<DatePickerColumnPattern>();
609 CHECK_NULL_VOID(datePickerColumnPattern);
610 datePickerColumnPattern->FlushCurrentOptions(isAdd, true, false);
611 }
612 }
613 }
614
SetEventCallback(EventCallback && value)615 void DatePickerPattern::SetEventCallback(EventCallback&& value)
616 {
617 auto host = GetHost();
618 CHECK_NULL_VOID(host);
619 auto children = host->GetChildren();
620 for (const auto& child : children) {
621 auto stackNode = DynamicCast<FrameNode>(child);
622 CHECK_NULL_VOID(stackNode);
623 auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
624 CHECK_NULL_VOID(blendNode);
625 auto childNode = blendNode->GetLastChild();
626 CHECK_NULL_VOID(childNode);
627 auto datePickerColumnPattern = DynamicCast<FrameNode>(childNode)->GetPattern<DatePickerColumnPattern>();
628 CHECK_NULL_VOID(datePickerColumnPattern);
629 datePickerColumnPattern->SetEventCallback(std::move(value));
630 }
631 }
632
SetChangeCallback(ColumnChangeCallback && value)633 void DatePickerPattern::SetChangeCallback(ColumnChangeCallback&& value)
634 {
635 auto host = GetHost();
636 CHECK_NULL_VOID(host);
637 auto children = host->GetChildren();
638 for (const auto& child : children) {
639 auto stackNode = DynamicCast<FrameNode>(child);
640 CHECK_NULL_VOID(stackNode);
641 auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
642 CHECK_NULL_VOID(blendNode);
643 auto childNode = blendNode->GetLastChild();
644 CHECK_NULL_VOID(childNode);
645 auto datePickerColumnPattern = DynamicCast<FrameNode>(childNode)->GetPattern<DatePickerColumnPattern>();
646 CHECK_NULL_VOID(datePickerColumnPattern);
647 datePickerColumnPattern->SetChangeCallback(std::move(value));
648 }
649 }
650
OnColorConfigurationUpdate()651 void DatePickerPattern::OnColorConfigurationUpdate()
652 {
653 auto host = GetHost();
654 CHECK_NULL_VOID(host);
655 host->SetNeedCallChildrenUpdate(false);
656 auto context = host->GetContext();
657 CHECK_NULL_VOID(context);
658 auto pickerTheme = context->GetTheme<PickerTheme>(host->GetThemeScopeId());
659 CHECK_NULL_VOID(pickerTheme);
660 auto dialogTheme = context->GetTheme<DialogTheme>();
661 CHECK_NULL_VOID(dialogTheme);
662 auto disappearStyle = pickerTheme->GetDisappearOptionStyle();
663 auto normalStyle = pickerTheme->GetOptionStyle(false, false);
664 auto pickerProperty = host->GetLayoutProperty<DataPickerRowLayoutProperty>();
665 CHECK_NULL_VOID(pickerProperty);
666
667 if (!pickerProperty->GetNormalTextColorSetByUser().value_or(false)) {
668 pickerProperty->UpdateColor(
669 GetTextProperties().normalTextStyle_.textColor.value_or(normalStyle.GetTextColor()));
670 }
671
672 if (!pickerProperty->GetDisappearTextColorSetByUser().value_or(false)) {
673 pickerProperty->UpdateDisappearColor(
674 GetTextProperties().disappearTextStyle_.textColor.value_or(disappearStyle.GetTextColor()));
675 }
676
677 if (isPicker_) {
678 if (!SystemProperties::ConfigChangePerform()) {
679 OnModifyDone();
680 }
681 return;
682 }
683 SetBackgroundColor(dialogTheme->GetBackgroundColor());
684 auto buttonTitleNode = buttonTitleNode_.Upgrade();
685 CHECK_NULL_VOID(buttonTitleNode);
686 auto titleLayoutRenderContext = buttonTitleNode->GetRenderContext();
687 CHECK_NULL_VOID(titleLayoutRenderContext);
688 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN) ||
689 !titleLayoutRenderContext->IsUniRenderEnabled()) {
690 titleLayoutRenderContext->UpdateBackgroundColor(dialogTheme->GetButtonBackgroundColor());
691 }
692 UpdateTitleTextColor(buttonTitleNode, pickerTheme);
693 UpdateLunarSwitch();
694 OnModifyDone();
695 }
696
OnThemeScopeUpdate(int32_t themeScopeId)697 bool DatePickerPattern::OnThemeScopeUpdate(int32_t themeScopeId)
698 {
699 bool result = false;
700 auto host = GetHost();
701 CHECK_NULL_RETURN(host, result);
702 host->SetNeedCallChildrenUpdate(false);
703 auto pickerProperty = host->GetLayoutProperty<DataPickerRowLayoutProperty>();
704 CHECK_NULL_RETURN(pickerProperty, result);
705 // The following three attributes will be affected by withTheme.
706 // If they are setted by user, then use the value by user set; Otherwise use the value from withTheme
707 // When the "result" is true, mean to notify the framework to Re-render
708 if ((!pickerProperty->HasColor()) || (!pickerProperty->HasDisappearColor()) ||
709 (!pickerProperty->HasSelectedColor())) {
710 result = true;
711 }
712 OnModifyDone();
713 return result;
714 }
715
UpdateTitleTextColor(const RefPtr<FrameNode> & buttonTitleNode,const RefPtr<PickerTheme> & pickerTheme)716 void DatePickerPattern::UpdateTitleTextColor(
717 const RefPtr<FrameNode>& buttonTitleNode, const RefPtr<PickerTheme>& pickerTheme)
718 {
719 auto childButton = buttonTitleNode->GetFirstChild();
720 CHECK_NULL_VOID(childButton);
721 auto ButtonNode = DynamicCast<FrameNode>(childButton);
722 CHECK_NULL_VOID(ButtonNode);
723 auto buttonTitleRenderContext = ButtonNode->GetRenderContext();
724 CHECK_NULL_VOID(buttonTitleRenderContext);
725 buttonTitleRenderContext->UpdateBackgroundColor(Color::TRANSPARENT);
726 auto childColumn = ButtonNode->GetFirstChild();
727 CHECK_NULL_VOID(childColumn);
728 auto childText = childColumn->GetFirstChild();
729 CHECK_NULL_VOID(childText);
730 auto textTitleNode = DynamicCast<FrameNode>(childText);
731 CHECK_NULL_VOID(textTitleNode);
732 auto textLayoutProperty = textTitleNode->GetLayoutProperty<TextLayoutProperty>();
733 CHECK_NULL_VOID(textLayoutProperty);
734 textLayoutProperty->UpdateTextColor(pickerTheme->GetTitleStyle().GetTextColor());
735 if (childColumn->GetChildren().size() > 1) {
736 auto spinner = childColumn->GetLastChild();
737 CHECK_NULL_VOID(spinner);
738 auto spinnerNode = DynamicCast<FrameNode>(spinner);
739 CHECK_NULL_VOID(spinnerNode);
740 auto spinnerRenderProperty = spinnerNode->GetPaintProperty<ImageRenderProperty>();
741 CHECK_NULL_VOID(spinnerRenderProperty);
742 spinnerRenderProperty->UpdateSvgFillColor(pickerTheme->GetTitleStyle().GetTextColor());
743 }
744 }
745
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)746 void DatePickerPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
747 {
748 auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
749 auto pattern = wp.Upgrade();
750 CHECK_NULL_RETURN(pattern, false);
751 return pattern->OnKeyEvent(event);
752 };
753 focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
754
755 auto getInnerPaintRectCallback = [wp = WeakClaim(this)](RoundRect& paintRect) {
756 auto pattern = wp.Upgrade();
757 if (pattern) {
758 pattern->GetInnerFocusPaintRect(paintRect);
759 }
760 };
761 focusHub->SetInnerFocusPaintRectCallback(getInnerPaintRectCallback);
762 }
763
PaintFocusState()764 void DatePickerPattern::PaintFocusState()
765 {
766 auto host = GetHost();
767 CHECK_NULL_VOID(host);
768
769 RoundRect focusRect;
770 GetInnerFocusPaintRect(focusRect);
771
772 auto focusHub = host->GetFocusHub();
773 CHECK_NULL_VOID(focusHub);
774 focusHub->PaintInnerFocusState(focusRect);
775 UpdateFocusButtonState();
776 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
777 }
778
CalcLeftTotalColumnWidth(const RefPtr<FrameNode> & host,float & leftTotalColumnWidth,float childSize)779 void DatePickerPattern::CalcLeftTotalColumnWidth(
780 const RefPtr<FrameNode>& host, float& leftTotalColumnWidth, float childSize)
781 {
782 bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
783 if (isRtl) {
784 for (int32_t index = childSize - 1; index > focusKeyID_; --index) {
785 auto stackChild = DynamicCast<FrameNode>(host->GetChildAtIndex(index));
786 CHECK_NULL_VOID(stackChild);
787 auto geometryNode = stackChild->GetGeometryNode();
788 CHECK_NULL_VOID(geometryNode);
789 leftTotalColumnWidth += geometryNode->GetFrameSize().Width();
790 }
791 } else {
792 for (int32_t index = 0; index < focusKeyID_; ++index) {
793 auto stackChild = DynamicCast<FrameNode>(host->GetChildAtIndex(index));
794 CHECK_NULL_VOID(stackChild);
795 auto geometryNode = stackChild->GetGeometryNode();
796 CHECK_NULL_VOID(geometryNode);
797 leftTotalColumnWidth += geometryNode->GetFrameSize().Width();
798 }
799 }
800 }
801
GetInnerFocusPaintRect(RoundRect & paintRect)802 void DatePickerPattern::GetInnerFocusPaintRect(RoundRect& paintRect)
803 {
804 auto host = GetHost();
805 CHECK_NULL_VOID(host);
806 auto childSize = 1.0f;
807 if (!ShowMonthDays()) {
808 childSize = static_cast<float>(host->GetChildren().size());
809 }
810 auto leftTotalColumnWidth = 0.0f;
811 CalcLeftTotalColumnWidth(host, leftTotalColumnWidth, childSize);
812 auto stackChild = DynamicCast<FrameNode>(host->GetChildAtIndex(focusKeyID_));
813 CHECK_NULL_VOID(stackChild);
814 auto blendChild = DynamicCast<FrameNode>(stackChild->GetLastChild());
815 CHECK_NULL_VOID(blendChild);
816 auto pickerChild = DynamicCast<FrameNode>(blendChild->GetLastChild());
817 CHECK_NULL_VOID(pickerChild);
818 auto columnWidth = pickerChild->GetGeometryNode()->GetFrameSize().Width();
819 auto pipeline = PipelineBase::GetCurrentContext();
820 CHECK_NULL_VOID(pipeline);
821 auto pickerTheme = pipeline->GetTheme<PickerTheme>();
822 CHECK_NULL_VOID(pickerTheme);
823 if (useButtonFocusArea_) {
824 return GetInnerFocusButtonPaintRect(paintRect, leftTotalColumnWidth);
825 }
826
827 auto dividerSpacing = pickerTheme->GetDividerSpacing().ConvertToPx();
828 float paintRectWidth = columnWidth - FOCUS_INTERVAL.ConvertToPx() * RATE - LINE_WIDTH.ConvertToPx() * RATE;
829 float paintRectHeight = dividerSpacing - FOCUS_INTERVAL.ConvertToPx() * RATE - LINE_WIDTH.ConvertToPx() * RATE;
830 auto centerX = leftTotalColumnWidth + FOCUS_INTERVAL.ConvertToPx() + LINE_WIDTH.ConvertToPx();
831 auto centerY = (host->GetGeometryNode()->GetFrameSize().Height() - dividerSpacing) / RATE +
832 FOCUS_INTERVAL.ConvertToPx() + LINE_WIDTH.ConvertToPx();
833 AdjustFocusBoxOffset(centerX);
834 paintRect.SetRect(RectF(centerX, centerY, paintRectWidth, paintRectHeight));
835 paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_LEFT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
836 static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
837 paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_RIGHT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
838 static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
839 paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_LEFT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
840 static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
841 paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_RIGHT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
842 static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
843 }
844
AdjustFocusBoxOffset(double & centerX)845 void DatePickerPattern::AdjustFocusBoxOffset(double& centerX)
846 {
847 auto host = GetHost();
848 CHECK_NULL_VOID(host);
849 auto geometryNode = host->GetGeometryNode();
850 CHECK_NULL_VOID(geometryNode);
851 if (geometryNode->GetPadding()) {
852 centerX += geometryNode->GetPadding()->left.value_or(0.0);
853 }
854 }
855
OnKeyEvent(const KeyEvent & event)856 bool DatePickerPattern::OnKeyEvent(const KeyEvent& event)
857 {
858 if (event.action != KeyAction::DOWN) {
859 return false;
860 }
861 if (event.code == KeyCode::KEY_DPAD_UP || event.code == KeyCode::KEY_DPAD_DOWN ||
862 event.code == KeyCode::KEY_DPAD_LEFT || event.code == KeyCode::KEY_DPAD_RIGHT ||
863 event.code == KeyCode::KEY_MOVE_HOME || event.code == KeyCode::KEY_MOVE_END) {
864 return HandleDirectionKey(event.code);
865 }
866 return false;
867 }
868
CheckFocusID(int32_t childSize)869 bool DatePickerPattern::CheckFocusID(int32_t childSize)
870 {
871 int32_t startIndex = 0;
872 int32_t endIndex = 0;
873
874 if (showTime_ || datePickerMode_ == DatePickerMode::DATE) {
875 startIndex = INDEX_YEAR;
876 endIndex = INDEX_DAY;
877 } else if (datePickerMode_ == DatePickerMode::YEAR_AND_MONTH) {
878 startIndex = INDEX_YEAR;
879 endIndex = INDEX_MONTH;
880 } else if (datePickerMode_ == DatePickerMode::MONTH_AND_DAY) {
881 startIndex = INDEX_MONTH;
882 endIndex = INDEX_DAY;
883 }
884
885 if (NeedAdaptForAging()) {
886 if (GetCurrentPage() == SECOND_PAGE) {
887 startIndex = INDEX_MONTH;
888 endIndex = INDEX_DAY;
889 } else {
890 if (datePickerMode_ == DatePickerMode::DATE) {
891 startIndex = INDEX_YEAR;
892 endIndex = INDEX_YEAR;
893 }
894 }
895 }
896
897 if (focusKeyID_ < startIndex) {
898 focusKeyID_ = startIndex;
899 return false;
900 } else if (focusKeyID_ > childSize - 1) {
901 focusKeyID_ = childSize - 1;
902 return false;
903 } else if (focusKeyID_ > endIndex) {
904 focusKeyID_ = endIndex;
905 return false;
906 }
907
908 return true;
909 }
910
ParseDirectionKey(RefPtr<DatePickerColumnPattern> & pattern,KeyCode & code,uint32_t totalOptionCount,int32_t childSize)911 bool DatePickerPattern::ParseDirectionKey(
912 RefPtr<DatePickerColumnPattern>& pattern, KeyCode& code, uint32_t totalOptionCount, int32_t childSize)
913 {
914 bool isRtl = AceApplicationInfo::GetInstance().IsRightToLeft();
915 if (code == KeyCode::KEY_DPAD_UP) {
916 pattern->StopHaptic();
917 pattern->InnerHandleScroll(false, false);
918 return true;
919 }
920 if (code == KeyCode::KEY_DPAD_DOWN) {
921 pattern->StopHaptic();
922 pattern->InnerHandleScroll(true, false);
923 return true;
924 }
925 if (code == KeyCode::KEY_MOVE_HOME) {
926 pattern->SetCurrentIndex(1);
927 pattern->InnerHandleScroll(false, false);
928 return true;
929 }
930 if (code == KeyCode::KEY_MOVE_END) {
931 pattern->SetCurrentIndex(totalOptionCount - INVISIBLE_OPTIONS_COUNT);
932 pattern->InnerHandleScroll(true, false);
933 return true;
934 }
935 if (code == KeyCode::KEY_DPAD_LEFT) {
936 focusKeyID_ = isRtl ? (focusKeyID_ + 1) : (focusKeyID_ - 1);
937 if (!CheckFocusID(childSize)) {
938 return false;
939 }
940 PaintFocusState();
941 return true;
942 }
943 if (code == KeyCode::KEY_DPAD_RIGHT) {
944 focusKeyID_ = isRtl ? (focusKeyID_ - 1) : (focusKeyID_ + 1);
945 if (ShowMonthDays()) {
946 childSize = 1;
947 }
948 if (!CheckFocusID(childSize)) {
949 return false;
950 }
951 PaintFocusState();
952 return true;
953 }
954 return false;
955 }
956
HandleDirectionKey(KeyCode code)957 bool DatePickerPattern::HandleDirectionKey(KeyCode code)
958 {
959 auto host = GetHost();
960 CHECK_NULL_RETURN(host, false);
961 auto stackChild = DynamicCast<FrameNode>(host->GetChildAtIndex(focusKeyID_));
962 CHECK_NULL_RETURN(stackChild, false);
963 auto childSize = host->GetChildren().size();
964 auto pickerChild = DynamicCast<FrameNode>(stackChild->GetLastChild()->GetLastChild());
965 CHECK_NULL_RETURN(pickerChild, false);
966 auto pattern = pickerChild->GetPattern<DatePickerColumnPattern>();
967 CHECK_NULL_RETURN(pattern, false);
968 auto totalOptionCount = GetOptionCount(pickerChild);
969 if (totalOptionCount == 0) {
970 return false;
971 }
972 return ParseDirectionKey(pattern, code, totalOptionCount, static_cast<int32_t>(childSize));
973 }
974
GetAllChildNode()975 std::unordered_map<std::string, RefPtr<FrameNode>> DatePickerPattern::GetAllChildNode()
976 {
977 std::unordered_map<std::string, RefPtr<FrameNode>> allChildNode;
978 RefPtr<FrameNode> stackYear;
979 RefPtr<FrameNode> stackMonth;
980 RefPtr<FrameNode> stackDay;
981 OrderAllChildNode(stackYear, stackMonth, stackDay);
982 CHECK_NULL_RETURN(stackYear, allChildNode);
983 CHECK_NULL_RETURN(stackMonth, allChildNode);
984 CHECK_NULL_RETURN(stackDay, allChildNode);
985 auto blendYear = DynamicCast<FrameNode>(stackYear->GetLastChild());
986 CHECK_NULL_RETURN(blendYear, allChildNode);
987 auto blendMonth = DynamicCast<FrameNode>(stackMonth->GetLastChild());
988 CHECK_NULL_RETURN(blendMonth, allChildNode);
989 auto blendDay = DynamicCast<FrameNode>(stackDay->GetLastChild());
990 CHECK_NULL_RETURN(blendDay, allChildNode);
991 auto yearNode = DynamicCast<FrameNode>(blendYear->GetLastChild());
992 CHECK_NULL_RETURN(yearNode, allChildNode);
993 auto monthNode = DynamicCast<FrameNode>(blendMonth->GetLastChild());
994 CHECK_NULL_RETURN(monthNode, allChildNode);
995 auto dayNode = DynamicCast<FrameNode>(blendDay->GetLastChild());
996 CHECK_NULL_RETURN(dayNode, allChildNode);
997 allChildNode["year"] = yearNode;
998 allChildNode["month"] = monthNode;
999 allChildNode["day"] = dayNode;
1000 return allChildNode;
1001 }
1002
OrderAllChildNode(RefPtr<FrameNode> & stackYear,RefPtr<FrameNode> & stackMonth,RefPtr<FrameNode> & stackDay)1003 void DatePickerPattern::OrderAllChildNode(
1004 RefPtr<FrameNode>& stackYear, RefPtr<FrameNode>& stackMonth, RefPtr<FrameNode>& stackDay)
1005 {
1006 auto host = GetHost();
1007 CHECK_NULL_VOID(host);
1008 auto children = host->GetChildren();
1009 if (children.size() != CHILD_SIZE) {
1010 return;
1011 }
1012
1013 auto processDateNode = [&children](RefPtr<UINode>& first, RefPtr<UINode>& second, RefPtr<UINode>& third) {
1014 auto iter = children.begin();
1015 first = *iter++;
1016 CHECK_NULL_VOID(first);
1017 second = *iter++;
1018 CHECK_NULL_VOID(second);
1019 third = *iter;
1020 CHECK_NULL_VOID(third);
1021 };
1022
1023 RefPtr<UINode> year;
1024 RefPtr<UINode> month;
1025 RefPtr<UINode> day;
1026 if (dateOrder_ == "M-d-y") {
1027 processDateNode(month, day, year);
1028 } else if (dateOrder_ == "y-d-M") {
1029 processDateNode(year, day, month);
1030 } else {
1031 processDateNode(year, month, day);
1032 }
1033 stackYear = DynamicCast<FrameNode>(year);
1034 stackMonth = DynamicCast<FrameNode>(month);
1035 stackDay = DynamicCast<FrameNode>(day);
1036 }
1037
FlushColumn()1038 void DatePickerPattern::FlushColumn()
1039 {
1040 auto host = GetHost();
1041 CHECK_NULL_VOID(host);
1042 auto allChildNode = GetAllChildNode();
1043
1044 auto dataPickerRowLayoutProperty = host->GetLayoutProperty<DataPickerRowLayoutProperty>();
1045 CHECK_NULL_VOID(dataPickerRowLayoutProperty);
1046 auto lunarDate = dataPickerRowLayoutProperty->GetSelectedDate().value_or(SolarToLunar(GetSelectedDate()));
1047 AdjustLunarDate(lunarDate);
1048 std::string language = Localization::GetInstance()->GetLanguage();
1049 if (dataPickerRowLayoutProperty->GetLunar().value_or(false) && (strcmp(language.c_str(), "zh") == 0)) {
1050 LunarColumnsBuilding(lunarDate);
1051 } else {
1052 SolarColumnsBuilding(LunarToSolar(lunarDate));
1053 }
1054
1055 auto yearNode = allChildNode["year"];
1056 auto monthNode = allChildNode["month"];
1057 auto dayNode = allChildNode["day"];
1058 CHECK_NULL_VOID(yearNode);
1059 CHECK_NULL_VOID(monthNode);
1060 CHECK_NULL_VOID(dayNode);
1061 auto yearColumnPattern = yearNode->GetPattern<DatePickerColumnPattern>();
1062 CHECK_NULL_VOID(yearColumnPattern);
1063 auto monthColumnPattern = monthNode->GetPattern<DatePickerColumnPattern>();
1064 CHECK_NULL_VOID(monthColumnPattern);
1065 auto dayColumnPattern = dayNode->GetPattern<DatePickerColumnPattern>();
1066 CHECK_NULL_VOID(dayColumnPattern);
1067
1068 yearColumnPattern->SetShowCount(GetShowCount());
1069 monthColumnPattern->SetShowCount(GetShowCount());
1070 dayColumnPattern->SetShowCount(GetShowCount());
1071 yearColumnPattern->FlushCurrentOptions();
1072 monthColumnPattern->FlushCurrentOptions();
1073 dayColumnPattern->FlushCurrentOptions();
1074 yearNode->MarkModifyDone();
1075 monthNode->MarkModifyDone();
1076 dayNode->MarkModifyDone();
1077 yearNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1078 monthNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1079 dayNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1080
1081 ShowColumnByDatePickMode();
1082 }
1083
ShowColumnByDatePickMode()1084 void DatePickerPattern::ShowColumnByDatePickMode()
1085 {
1086 if (GetIsShowInDialog() && (showTime_ || datePickerMode_ == DatePickerMode::DATE)) {
1087 return;
1088 }
1089 RefPtr<FrameNode> stackYear;
1090 RefPtr<FrameNode> stackMonth;
1091 RefPtr<FrameNode> stackDay;
1092 OrderAllChildNode(stackYear, stackMonth, stackDay);
1093 CHECK_NULL_VOID(stackYear);
1094 CHECK_NULL_VOID(stackMonth);
1095 CHECK_NULL_VOID(stackDay);
1096
1097 if (datePickerMode_ == DatePickerMode::DATE) {
1098 UpdateStackPropVisibility(stackYear, VisibleType::VISIBLE, RATIO_ONE);
1099 UpdateStackPropVisibility(stackMonth, VisibleType::VISIBLE, RATIO_ONE);
1100 UpdateStackPropVisibility(stackDay, VisibleType::VISIBLE, RATIO_ONE);
1101 focusKeyID_ = INDEX_YEAR;
1102 } else if (datePickerMode_ == DatePickerMode::YEAR_AND_MONTH) {
1103 UpdateStackPropVisibility(stackYear, VisibleType::VISIBLE, RATIO_ONE);
1104 UpdateStackPropVisibility(stackMonth, VisibleType::VISIBLE, RATIO_ONE);
1105 UpdateStackPropVisibility(stackDay, VisibleType::GONE, RATIO_ZERO);
1106 focusKeyID_ = INDEX_YEAR;
1107 } else if (datePickerMode_ == DatePickerMode::MONTH_AND_DAY) {
1108 UpdateStackPropVisibility(stackYear, VisibleType::GONE, RATIO_ZERO);
1109 UpdateStackPropVisibility(stackMonth, VisibleType::VISIBLE, RATIO_ONE);
1110 UpdateStackPropVisibility(stackDay, VisibleType::VISIBLE, RATIO_ONE);
1111 focusKeyID_ = INDEX_MONTH;
1112 }
1113 }
1114
UpdateStackPropVisibility(const RefPtr<FrameNode> & stackNode,const VisibleType visibleType,const int32_t weight)1115 void DatePickerPattern::UpdateStackPropVisibility(const RefPtr<FrameNode>& stackNode,
1116 const VisibleType visibleType, const int32_t weight)
1117 {
1118 for (const auto& child : stackNode->GetChildren()) {
1119 auto frameNodeChild = AceType::DynamicCast<NG::FrameNode>(child);
1120 CHECK_NULL_VOID(frameNodeChild);
1121 auto layoutProperty = frameNodeChild->GetLayoutProperty();
1122 layoutProperty->UpdateVisibility(visibleType);
1123 }
1124 auto stackNodeLayoutProperty = stackNode->GetLayoutProperty<LayoutProperty>();
1125 CHECK_NULL_VOID(stackNodeLayoutProperty);
1126 if ((datePickerMode_ != DatePickerMode::DATE) || !GetIsShowInDialog()) {
1127 stackNodeLayoutProperty->UpdateLayoutWeight(weight);
1128 }
1129 }
1130
FlushMonthDaysColumn()1131 void DatePickerPattern::FlushMonthDaysColumn()
1132 {
1133 auto host = GetHost();
1134 CHECK_NULL_VOID(host);
1135
1136 auto children = host->GetChildren();
1137 if (children.size() <= SINGLE_CHILD_SIZE) {
1138 return;
1139 }
1140 auto iter = children.begin();
1141 auto monthDays = (*iter);
1142 CHECK_NULL_VOID(monthDays);
1143 iter++;
1144 auto year = *iter;
1145 CHECK_NULL_VOID(year);
1146 auto stackMonthDays = DynamicCast<FrameNode>(monthDays);
1147 auto blendMonthDays = DynamicCast<FrameNode>(stackMonthDays->GetLastChild());
1148 CHECK_NULL_VOID(blendMonthDays);
1149 auto monthDaysNode = DynamicCast<FrameNode>(blendMonthDays->GetLastChild());
1150 auto stackYear = DynamicCast<FrameNode>(year);
1151 auto blendYear = DynamicCast<FrameNode>(stackYear->GetLastChild());
1152 CHECK_NULL_VOID(blendYear);
1153 auto yearDaysNode = DynamicCast<FrameNode>(blendYear->GetLastChild());
1154 CHECK_NULL_VOID(monthDaysNode);
1155 CHECK_NULL_VOID(yearDaysNode);
1156 auto dataPickerRowLayoutProperty = host->GetLayoutProperty<DataPickerRowLayoutProperty>();
1157 CHECK_NULL_VOID(dataPickerRowLayoutProperty);
1158 std::string language = Localization::GetInstance()->GetLanguage();
1159 if (dataPickerRowLayoutProperty->GetLunar().value_or(false) && (strcmp(language.c_str(), "zh") == 0)) {
1160 LunarMonthDaysColumnBuilding(
1161 dataPickerRowLayoutProperty->GetSelectedDate().value_or(SolarToLunar(GetSelectedDate())));
1162 } else {
1163 SolarMonthDaysColumnsBuilding(
1164 LunarToSolar(dataPickerRowLayoutProperty->GetSelectedDate().value_or(SolarToLunar(GetSelectedDate()))));
1165 }
1166
1167 auto monthDaysColumnPattern = monthDaysNode->GetPattern<DatePickerColumnPattern>();
1168 auto yearColumnPattern = yearDaysNode->GetPattern<DatePickerColumnPattern>();
1169 CHECK_NULL_VOID(monthDaysColumnPattern);
1170 CHECK_NULL_VOID(yearColumnPattern);
1171
1172 monthDaysColumnPattern->SetShowCount(GetShowCount());
1173 yearColumnPattern->SetShowCount(GetShowCount());
1174 monthDaysColumnPattern->FlushCurrentOptions();
1175 yearColumnPattern->FlushCurrentOptions();
1176 monthDaysNode->MarkModifyDone();
1177 yearDaysNode->MarkModifyDone();
1178 monthDaysNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1179 yearDaysNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1180 }
1181
ReportDateChangeEvent(int32_t nodeId,const std::string & compName,const std::string & eventName,const std::string & eventData)1182 bool DatePickerPattern::ReportDateChangeEvent(int32_t nodeId, const std::string& compName,
1183 const std::string& eventName, const std::string& eventData)
1184 {
1185 auto dataJson = JsonUtil::ParseJsonString(eventData);
1186 CHECK_NULL_RETURN(dataJson, false);
1187 auto params = JsonUtil::Create();
1188 CHECK_NULL_RETURN(params, false);
1189 params->Put("year", static_cast<int32_t>(dataJson->GetUInt("year")));
1190 params->Put("month", static_cast<int32_t>(dataJson->GetUInt("month") + 1)); // month: 1-12
1191 params->Put("day", static_cast<int32_t>(dataJson->GetUInt("day")));
1192 params->Put("hour", static_cast<int32_t>(dataJson->GetUInt("hour")));
1193 params->Put("minute", static_cast<int32_t>(dataJson->GetUInt("minute")));
1194 auto value = JsonUtil::Create();
1195 CHECK_NULL_RETURN(value, false);
1196 value->Put("nodeId", nodeId);
1197 value->Put(compName.c_str(), eventName.c_str());
1198 value->Put("params", params);
1199 UiSessionManager::GetInstance()->ReportComponentChangeEvent("event", value->ToString());
1200 return true;
1201 }
1202
ReportDateChangeEvent(const std::string & compName,const std::string & eventName,const std::string & eventData)1203 bool DatePickerPattern::ReportDateChangeEvent(const std::string& compName,
1204 const std::string& eventName, const std::string& eventData)
1205 {
1206 if (GetIsShowInDialog()) {
1207 return false;
1208 }
1209 auto host = GetHost();
1210 CHECK_NULL_RETURN(host, false);
1211 return ReportDateChangeEvent(host->GetId(), compName, eventName, eventData);
1212 }
1213
FireChangeEvent(bool refresh)1214 void DatePickerPattern::FireChangeEvent(bool refresh)
1215 {
1216 if (refresh) {
1217 ReportDateChangeEvent("DatePicker", "onDateChange", GetSelectedObject(true));
1218 auto datePickerEventHub = GetOrCreateEventHub<DatePickerEventHub>();
1219 CHECK_NULL_VOID(datePickerEventHub);
1220 auto str = GetSelectedObject(true);
1221 auto info = std::make_shared<DatePickerChangeEvent>(str);
1222 datePickerEventHub->FireChangeEvent(info.get());
1223 datePickerEventHub->FireDialogChangeEvent(str);
1224 firedDateStr_ = str;
1225 }
1226 }
1227
ShowTitle(int32_t titleId)1228 void DatePickerPattern::ShowTitle(int32_t titleId)
1229 {
1230 if (HasTitleNode() && isFocus_) {
1231 auto textTitleNode = FrameNode::GetOrCreateFrameNode(
1232 V2::TEXT_ETS_TAG, titleId, []() { return AceType::MakeRefPtr<TextPattern>(); });
1233 CHECK_NULL_VOID(textTitleNode);
1234 auto textLayoutProperty = textTitleNode->GetLayoutProperty<TextLayoutProperty>();
1235 CHECK_NULL_VOID(textLayoutProperty);
1236
1237 if (!showTime_ && (datePickerMode_ != DatePickerMode::DATE)) {
1238 auto dateStr = GetVisibleColumnsText();
1239 textLayoutProperty->UpdateContent(dateStr);
1240 } else {
1241 auto dateStr = GetCurrentDate();
1242 textLayoutProperty->UpdateContent(dateStr.ToString(false));
1243 }
1244 textTitleNode->MarkModifyDone();
1245 textTitleNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1246 }
1247 }
1248
GetVisibleColumnsText()1249 std::string DatePickerPattern::GetVisibleColumnsText()
1250 {
1251 std::string result = "";
1252 auto allChildNode = GetAllChildNode();
1253 auto yearNode = allChildNode["year"];
1254 auto monthNode = allChildNode["month"];
1255 auto dayNode = allChildNode["day"];
1256 CHECK_NULL_RETURN(yearNode, "");
1257 CHECK_NULL_RETURN(monthNode, "");
1258 CHECK_NULL_RETURN(dayNode, "");
1259 if (datePickerMode_ == DatePickerMode::YEAR_AND_MONTH) {
1260 GetColumnText(yearNode, result);
1261 }
1262 GetColumnText(monthNode, result);
1263 if (datePickerMode_ == DatePickerMode::MONTH_AND_DAY) {
1264 GetColumnText(dayNode, result);
1265 }
1266 return result;
1267 }
1268
GetColumnText(const RefPtr<FrameNode> & columnNode,std::string & result)1269 void DatePickerPattern::GetColumnText(const RefPtr<FrameNode>& columnNode, std::string& result)
1270 {
1271 auto columnPattern = columnNode->GetPattern<DatePickerColumnPattern>();
1272 CHECK_NULL_VOID(columnPattern);
1273 auto index = columnPattern->GetCurrentIndex();
1274 auto options = columnPattern->GetOptions();
1275 auto it = options.find(columnNode);
1276 if (it != options.end() && index >= 0 && index < it->second.size()) {
1277 auto date = it->second.at(index);
1278 result.append(GetFormatString(date));
1279 }
1280 }
1281
OnDataLinking(const RefPtr<FrameNode> & tag,bool isAdd,uint32_t index,std::vector<RefPtr<FrameNode>> & resultTags)1282 void DatePickerPattern::OnDataLinking(
1283 const RefPtr<FrameNode>& tag, bool isAdd, uint32_t index, std::vector<RefPtr<FrameNode>>& resultTags)
1284 {
1285 auto allChildNode = GetAllChildNode();
1286 auto yearNode = allChildNode["year"];
1287 auto monthNode = allChildNode["month"];
1288 auto dayNode = allChildNode["day"];
1289 CHECK_NULL_VOID(yearNode);
1290 CHECK_NULL_VOID(monthNode);
1291 CHECK_NULL_VOID(dayNode);
1292 if (tag == yearNode) {
1293 HandleYearChange(isAdd, index, resultTags);
1294 return;
1295 }
1296
1297 if (tag == monthNode) {
1298 HandleMonthChange(isAdd, index, resultTags);
1299 return;
1300 }
1301
1302 if (tag == dayNode) {
1303 HandleDayChange(isAdd, index, resultTags);
1304 return;
1305 }
1306 }
1307
HandleMonthDaysChange(const RefPtr<FrameNode> & tag,bool isAdd,uint32_t index,std::vector<RefPtr<FrameNode>> & resultTags)1308 void DatePickerPattern::HandleMonthDaysChange(
1309 const RefPtr<FrameNode>& tag, bool isAdd, uint32_t index, std::vector<RefPtr<FrameNode>>& resultTags)
1310 {
1311 auto host = GetHost();
1312 CHECK_NULL_VOID(host);
1313
1314 auto children = host->GetChildren();
1315 if (children.size() <= SINGLE_CHILD_SIZE) {
1316 return;
1317 }
1318 auto iter = children.begin();
1319 auto monthDays = (*iter);
1320 CHECK_NULL_VOID(monthDays);
1321
1322 auto stackMonthDays = DynamicCast<FrameNode>(monthDays);
1323 auto blendMonthDays = DynamicCast<FrameNode>(stackMonthDays->GetLastChild());
1324 CHECK_NULL_VOID(blendMonthDays);
1325 auto monthDaysNode = DynamicCast<FrameNode>(blendMonthDays->GetLastChild());
1326 if (tag != monthDaysNode) {
1327 return;
1328 }
1329
1330 if (IsShowLunar()) {
1331 HandleLunarMonthDaysChange(isAdd, index);
1332 } else {
1333 HandleSolarMonthDaysChange(isAdd, index);
1334 }
1335
1336 resultTags.emplace_back(monthDaysNode);
1337 }
1338
GetSelectedObject(bool isColumnChange,int status) const1339 std::string DatePickerPattern::GetSelectedObject(bool isColumnChange, int status) const
1340 {
1341 auto date = selectedDate_;
1342 if (isColumnChange) {
1343 date = GetCurrentDate();
1344 }
1345 // W3C's month is between 0 to 11, need to reduce one.
1346 auto getMonth = date.GetMonth();
1347 getMonth = getMonth > 0 ? getMonth - 1 : 0;
1348 date.SetMonth(getMonth);
1349
1350 auto dateTimeString = std::string("{\"year\":") + std::to_string(date.GetYear()) +
1351 ",\"month\":" + std::to_string(date.GetMonth()) + ",\"day\":" + std::to_string(date.GetDay());
1352 auto pickTime = PickerTime::Current();
1353 if (showTime_) {
1354 auto host = GetHost();
1355 CHECK_NULL_RETURN(host, date.ToString(true, status));
1356 if (showMonthDays_) {
1357 auto pickerRow = host->GetParent();
1358 CHECK_NULL_RETURN(pickerRow, date.ToString(true, status));
1359 auto timeNode = AceType::DynamicCast<FrameNode>(pickerRow->GetChildAtIndex(1));
1360 CHECK_NULL_RETURN(timeNode, date.ToString(true, status));
1361 auto timePickerPattern = timeNode->GetPattern<TimePickerRowPattern>();
1362 CHECK_NULL_RETURN(timePickerPattern, date.ToString(true, status));
1363 pickTime = timePickerPattern->GetCurrentTime();
1364 } else {
1365 auto pickerStack = host->GetParent();
1366 CHECK_NULL_RETURN(pickerStack, date.ToString(true, status));
1367 auto pickerRow = pickerStack->GetLastChild();
1368 CHECK_NULL_RETURN(pickerRow, date.ToString(true, status));
1369 auto timeNode = AceType::DynamicCast<FrameNode>(pickerRow->GetChildAtIndex(1));
1370 CHECK_NULL_RETURN(timeNode, date.ToString(true, status));
1371 auto timePickerPattern = timeNode->GetPattern<TimePickerRowPattern>();
1372 CHECK_NULL_RETURN(timePickerPattern, date.ToString(true, status));
1373 pickTime = timePickerPattern->GetCurrentTime();
1374 }
1375 }
1376 dateTimeString += std::string(",\"hour\":") + std::to_string(pickTime.GetHour()) +
1377 ",\"minute\":" + std::to_string(pickTime.GetMinute()) + ",\"status\":" + std::to_string(status) +
1378 "}";
1379 return dateTimeString;
1380 }
1381
HandleDayChange(bool isAdd,uint32_t index,std::vector<RefPtr<FrameNode>> & resultTags)1382 void DatePickerPattern::HandleDayChange(bool isAdd, uint32_t index, std::vector<RefPtr<FrameNode>>& resultTags)
1383 {
1384 auto allChildNode = GetAllChildNode();
1385 auto yearNode = allChildNode["year"];
1386 auto monthNode = allChildNode["month"];
1387 auto dayNode = allChildNode["day"];
1388 CHECK_NULL_VOID(yearNode);
1389 CHECK_NULL_VOID(monthNode);
1390 CHECK_NULL_VOID(dayNode);
1391 if (IsShowLunar()) {
1392 HandleLunarDayChange(isAdd, index);
1393 } else {
1394 HandleSolarDayChange(isAdd, index);
1395 }
1396 resultTags.emplace_back(yearNode);
1397 resultTags.emplace_back(monthNode);
1398 resultTags.emplace_back(dayNode);
1399 }
1400
HandleSolarDayChange(bool isAdd,uint32_t index)1401 void DatePickerPattern::HandleSolarDayChange(bool isAdd, uint32_t index)
1402 {
1403 auto allChildNode = GetAllChildNode();
1404 auto yearNode = allChildNode["year"];
1405 auto monthNode = allChildNode["month"];
1406 auto dayNode = allChildNode["day"];
1407
1408 CHECK_NULL_VOID(yearNode);
1409 CHECK_NULL_VOID(monthNode);
1410 CHECK_NULL_VOID(dayNode);
1411 auto yearDatePickerColumnPattern = yearNode->GetPattern<DatePickerColumnPattern>();
1412 auto monthDatePickerColumnPattern = monthNode->GetPattern<DatePickerColumnPattern>();
1413 auto dayDatePickerColumnPattern = dayNode->GetPattern<DatePickerColumnPattern>();
1414 CHECK_NULL_VOID(yearDatePickerColumnPattern);
1415 CHECK_NULL_VOID(monthDatePickerColumnPattern);
1416 CHECK_NULL_VOID(dayDatePickerColumnPattern);
1417
1418 auto date = GetCurrentDate();
1419 if (isAdd && index == 0) {
1420 IncreaseLinkageYearMonth(date);
1421 }
1422 auto getOptionCount = GetOptionCount(dayNode);
1423 getOptionCount = getOptionCount > 0 ? getOptionCount - 1 : 0;
1424 if (!isAdd &&
1425 dayDatePickerColumnPattern->GetCurrentIndex() == getOptionCount) { // last index is count - 1
1426 ReduceLinkageYearMonth(date);
1427 }
1428 uint32_t maxDay = PickerDate::GetMaxDay(date.GetYear(), date.GetMonth());
1429 if (date.GetDay() > maxDay) {
1430 date.SetDay(maxDay);
1431 }
1432 AdjustSolarDate(date);
1433 SolarColumnsBuilding(date);
1434 }
1435
HandleLunarDayChange(bool isAdd,uint32_t index)1436 void DatePickerPattern::HandleLunarDayChange(bool isAdd, uint32_t index)
1437 {
1438 if (isAdd) {
1439 HandleAddLunarDayChange(index);
1440 } else {
1441 HandleReduceLunarDayChange(index);
1442 }
1443 }
1444
IncreaseLinkageYearMonth(PickerDate & date)1445 void DatePickerPattern::IncreaseLinkageYearMonth(PickerDate& date)
1446 {
1447 date.SetMonth(date.GetMonth() + 1); // add to next month
1448 if (date.GetMonth() > 12) { // invalidate month, max month is 12
1449 date.SetMonth(1); // first month is 1
1450 if (datePickerMode_ != DatePickerMode::MONTH_AND_DAY) {
1451 date.SetYear(date.GetYear() + 1); // add to next year
1452 if (date.GetYear() > endDateSolar_.GetYear()) {
1453 date.SetYear(startDateSolar_.GetYear());
1454 }
1455 }
1456 }
1457 }
1458
ReduceLinkageYearMonth(PickerDate & date)1459 void DatePickerPattern::ReduceLinkageYearMonth(PickerDate& date)
1460 {
1461 auto getMonth = date.GetMonth();
1462 getMonth = getMonth > 0 ? getMonth - 1 : 0;
1463 date.SetMonth(getMonth); // reduce to previous month
1464 if (date.GetMonth() == 0) { // min month is 1, invalidate
1465 date.SetMonth(MONTH_DECEMBER); // set to be the last month
1466 if (datePickerMode_ != DatePickerMode::MONTH_AND_DAY) {
1467 auto getYear = date.GetYear();
1468 getYear = getYear > 0 ? getYear - 1 : 0;
1469 date.SetYear(getYear); // reduce to previous year
1470 if (date.GetYear() < startDateSolar_.GetYear()) {
1471 date.SetYear(endDateSolar_.GetYear());
1472 }
1473 }
1474 }
1475 date.SetDay(PickerDate::GetMaxDay(date.GetYear(), date.GetMonth())); // reduce to previous month's last day
1476 }
1477
HandleReduceLunarDayChange(uint32_t index)1478 void DatePickerPattern::HandleReduceLunarDayChange(uint32_t index)
1479 {
1480 auto allChildNode = GetAllChildNode();
1481 auto yearNode = allChildNode["year"];
1482 auto monthNode = allChildNode["month"];
1483 auto dayNode = allChildNode["day"];
1484
1485 CHECK_NULL_VOID(yearNode);
1486 CHECK_NULL_VOID(monthNode);
1487 CHECK_NULL_VOID(dayNode);
1488
1489 auto yearDatePickerColumnPattern = yearNode->GetPattern<DatePickerColumnPattern>();
1490 auto monthDatePickerColumnPattern = monthNode->GetPattern<DatePickerColumnPattern>();
1491 auto dayDatePickerColumnPattern = dayNode->GetPattern<DatePickerColumnPattern>();
1492
1493 uint32_t nowLunarYear = startDateLunar_.year + yearDatePickerColumnPattern->GetCurrentIndex();
1494 auto lunarDate = GetCurrentLunarDate(nowLunarYear);
1495 uint32_t lunarLeapMonth = 0;
1496 bool hasLeapMonth = GetLunarLeapMonth(lunarDate.year, lunarLeapMonth);
1497 auto getOptionCount = GetOptionCount(dayNode);
1498 getOptionCount = getOptionCount > 0 ? getOptionCount - 1 : 0;
1499 if (dayDatePickerColumnPattern->GetCurrentIndex() == getOptionCount) { // max index is count - 1
1500 if (monthDatePickerColumnPattern->GetCurrentIndex() == 0) {
1501 lunarDate.year = lunarDate.year > 0 ? lunarDate.year - 1 : 0; // reduce to previous year
1502 if (lunarDate.year < startDateLunar_.year) {
1503 lunarDate.year = endDateLunar_.year;
1504 }
1505 lunarDate.month = 12; // set to be previous year's max month
1506 lunarDate.isLeapMonth = false;
1507 if (LunarCalculator::GetLunarLeapMonth(lunarDate.year) == 12) { // leap 12th month
1508 lunarDate.isLeapMonth = true;
1509 }
1510 lunarDate.day = GetLunarMaxDay(lunarDate.year, lunarDate.month, lunarDate.isLeapMonth);
1511 } else {
1512 if (lunarDate.isLeapMonth) {
1513 lunarDate.isLeapMonth = false;
1514 } else if (!hasLeapMonth) {
1515 lunarDate.month = lunarDate.month - 1; // reduce to previous month
1516 } else if (lunarLeapMonth == lunarDate.month - 1) { // leap month is previous month
1517 lunarDate.isLeapMonth = true;
1518 lunarDate.month = lunarLeapMonth;
1519 } else {
1520 lunarDate.month = lunarDate.month - 1; // reduce to previous month
1521 }
1522 lunarDate.day = GetLunarMaxDay(lunarDate.year, lunarDate.month, lunarDate.isLeapMonth);
1523 }
1524 }
1525
1526 AdjustLunarDate(lunarDate);
1527 LunarColumnsBuilding(lunarDate);
1528 }
1529
HandleAddLunarDayChange(uint32_t index)1530 void DatePickerPattern::HandleAddLunarDayChange(uint32_t index)
1531 {
1532 auto allChildNode = GetAllChildNode();
1533 auto yearNode = allChildNode["year"];
1534 auto monthNode = allChildNode["month"];
1535 auto dayNode = allChildNode["day"];
1536
1537 CHECK_NULL_VOID(yearNode);
1538 CHECK_NULL_VOID(monthNode);
1539 CHECK_NULL_VOID(dayNode);
1540
1541 auto yearDatePickerColumnPattern = yearNode->GetPattern<DatePickerColumnPattern>();
1542 auto monthDatePickerColumnPattern = monthNode->GetPattern<DatePickerColumnPattern>();
1543 auto dayDatePickerColumnPattern = dayNode->GetPattern<DatePickerColumnPattern>();
1544
1545 uint32_t nowLunarYear = startDateLunar_.year + yearDatePickerColumnPattern->GetCurrentIndex();
1546 auto lunarDate = GetCurrentLunarDate(nowLunarYear);
1547 uint32_t lunarLeapMonth = 0;
1548 bool hasLeapMonth = GetLunarLeapMonth(lunarDate.year, lunarLeapMonth);
1549 if (index == 0) {
1550 auto getOptionCount = GetOptionCount(monthNode);
1551 getOptionCount = getOptionCount > 0 ? getOptionCount - 1 : 0;
1552 if (monthDatePickerColumnPattern->GetCurrentIndex() == getOptionCount) { // max index is count - 1
1553 lunarDate.year = lunarDate.year + 1; // add to next year
1554 if (lunarDate.year > endDateLunar_.year) {
1555 lunarDate.year = startDateLunar_.year;
1556 }
1557 lunarDate.month = 1; // first month
1558 lunarDate.isLeapMonth = false;
1559 } else {
1560 if (lunarDate.isLeapMonth) {
1561 lunarDate.month = lunarDate.month + 1; // add to next month
1562 lunarDate.isLeapMonth = false;
1563 } else if (!hasLeapMonth) {
1564 lunarDate.month = lunarDate.month + 1; // add to next month
1565 } else if (lunarLeapMonth == lunarDate.month) {
1566 lunarDate.isLeapMonth = true;
1567 } else {
1568 lunarDate.month = lunarDate.month + 1; // add to next month
1569 }
1570 }
1571 }
1572
1573 AdjustLunarDate(lunarDate);
1574 LunarColumnsBuilding(lunarDate);
1575 }
1576
HandleSolarMonthDaysChange(bool isAdd,uint32_t index)1577 void DatePickerPattern::HandleSolarMonthDaysChange(bool isAdd, uint32_t index)
1578 {
1579 auto host = GetHost();
1580 CHECK_NULL_VOID(host);
1581
1582 auto children = host->GetChildren();
1583 if (children.size() <= SINGLE_CHILD_SIZE) {
1584 return;
1585 }
1586 auto iter = children.begin();
1587 auto monthDays = (*iter);
1588 CHECK_NULL_VOID(monthDays);
1589 auto stackMonthDays = DynamicCast<FrameNode>(monthDays);
1590 CHECK_NULL_VOID(stackMonthDays);
1591 auto blendMonthDays = DynamicCast<FrameNode>(stackMonthDays->GetLastChild());
1592 CHECK_NULL_VOID(blendMonthDays);
1593 auto monthDaysNode = DynamicCast<FrameNode>(blendMonthDays->GetLastChild());
1594 CHECK_NULL_VOID(monthDaysNode);
1595 auto monthDaysDatePickerColumnPattern = monthDaysNode->GetPattern<DatePickerColumnPattern>();
1596 CHECK_NULL_VOID(monthDaysDatePickerColumnPattern);
1597
1598 auto date = GetCurrentDate();
1599
1600 if (isAdd && index == 0) {
1601 // add to next year
1602 date.SetYear(date.GetYear() + 1); // add to next year
1603 if (date.GetYear() > endDateSolar_.GetYear()) {
1604 date.SetYear(startDateSolar_.GetYear());
1605 }
1606 }
1607 auto getOptionCount = GetOptionCount(monthDaysNode);
1608 getOptionCount = getOptionCount > 0 ? getOptionCount - 1 : 0;
1609 if (!isAdd && monthDaysDatePickerColumnPattern->GetCurrentIndex() == getOptionCount) {
1610 // reduce to previous year
1611 auto getYear = date.GetYear();
1612 getYear = getYear > 0 ? getYear - 1 : 0;
1613 date.SetYear(getYear);
1614 if (date.GetYear() < startDateSolar_.GetYear()) {
1615 date.SetYear(endDateSolar_.GetYear());
1616 }
1617 // reduce to previous year's last day
1618 date.SetMonth(MAX_MONTH);
1619 date.SetDay(PickerDate::GetMaxDay(date.GetYear(), date.GetMonth()));
1620 }
1621 uint32_t maxDay = PickerDate::GetMaxDay(date.GetYear(), date.GetMonth());
1622 if (date.GetDay() > maxDay) {
1623 date.SetDay(maxDay);
1624 }
1625 AdjustSolarDate(date);
1626 SolarMonthDaysColumnsBuilding(date);
1627 }
1628
HandleLunarMonthDaysChange(bool isAdd,uint32_t index)1629 void DatePickerPattern::HandleLunarMonthDaysChange(bool isAdd, uint32_t index)
1630 {
1631 if (isAdd) {
1632 HandleAddLunarMonthDaysChange(index);
1633 } else {
1634 HandleReduceLunarMonthDaysChange(index);
1635 }
1636 }
1637
HandleAddLunarMonthDaysChange(uint32_t index)1638 void DatePickerPattern::HandleAddLunarMonthDaysChange(uint32_t index)
1639 {
1640 auto host = GetHost();
1641 CHECK_NULL_VOID(host);
1642
1643 auto children = host->GetChildren();
1644 if (children.size() <= SINGLE_CHILD_SIZE) {
1645 return;
1646 }
1647 auto iter = children.begin();
1648 auto monthDays = (*iter);
1649 CHECK_NULL_VOID(monthDays);
1650 iter++;
1651 auto year = *iter;
1652 CHECK_NULL_VOID(year);
1653 auto stackMonthDays = DynamicCast<FrameNode>(monthDays);
1654 auto blendMonthDays = DynamicCast<FrameNode>(stackMonthDays->GetLastChild());
1655 CHECK_NULL_VOID(blendMonthDays);
1656 auto monthDaysNode = DynamicCast<FrameNode>(blendMonthDays->GetLastChild());
1657 auto stackYear = DynamicCast<FrameNode>(year);
1658 auto blendYear = DynamicCast<FrameNode>(stackYear->GetLastChild());
1659 CHECK_NULL_VOID(blendYear);
1660 auto yearDaysNode = DynamicCast<FrameNode>(blendYear->GetLastChild());
1661 CHECK_NULL_VOID(monthDaysNode);
1662 CHECK_NULL_VOID(yearDaysNode);
1663
1664 auto monthDaysDatePickerColumnPattern = monthDaysNode->GetPattern<DatePickerColumnPattern>();
1665 auto yearDatePickerColumnPattern = yearDaysNode->GetPattern<DatePickerColumnPattern>();
1666
1667 uint32_t nowLunarYear = startDateLunar_.year + yearDatePickerColumnPattern->GetCurrentIndex();
1668 auto lunarDate = GetCurrentLunarDateByMonthDaysColumn(nowLunarYear);
1669 if (index == 0) {
1670 lunarDate.year = lunarDate.year + 1; // add to next year
1671 if (lunarDate.year > endDateLunar_.year) {
1672 lunarDate.year = startDateLunar_.year;
1673 }
1674 lunarDate.month = 1;
1675 lunarDate.isLeapMonth = false;
1676 }
1677
1678 AdjustLunarDate(lunarDate);
1679 LunarMonthDaysColumnBuilding(lunarDate);
1680 }
1681
HandleReduceLunarMonthDaysChange(uint32_t index)1682 void DatePickerPattern::HandleReduceLunarMonthDaysChange(uint32_t index)
1683 {
1684 auto host = GetHost();
1685 CHECK_NULL_VOID(host);
1686
1687 auto children = host->GetChildren();
1688 if (children.size() <= SINGLE_CHILD_SIZE) {
1689 return;
1690 }
1691 auto iter = children.begin();
1692 auto monthDays = (*iter);
1693 CHECK_NULL_VOID(monthDays);
1694 iter++;
1695 auto year = *iter;
1696 CHECK_NULL_VOID(year);
1697 auto stackMonthDays = DynamicCast<FrameNode>(monthDays);
1698 auto blendMonthDays = DynamicCast<FrameNode>(stackMonthDays->GetLastChild());
1699 CHECK_NULL_VOID(blendMonthDays);
1700 auto monthDaysNode = DynamicCast<FrameNode>(blendMonthDays->GetLastChild());
1701 auto stackYear = DynamicCast<FrameNode>(year);
1702 auto blendYear = DynamicCast<FrameNode>(stackYear->GetLastChild());
1703 CHECK_NULL_VOID(blendYear);
1704 auto yearDaysNode = DynamicCast<FrameNode>(blendYear->GetLastChild());
1705 CHECK_NULL_VOID(monthDaysNode);
1706 CHECK_NULL_VOID(yearDaysNode);
1707
1708 auto monthDaysDatePickerColumnPattern = monthDaysNode->GetPattern<DatePickerColumnPattern>();
1709 auto yearDatePickerColumnPattern = yearDaysNode->GetPattern<DatePickerColumnPattern>();
1710 CHECK_NULL_VOID(monthDaysDatePickerColumnPattern);
1711 CHECK_NULL_VOID(yearDatePickerColumnPattern);
1712
1713 uint32_t nowLunarYear = startDateLunar_.year + yearDatePickerColumnPattern->GetCurrentIndex();
1714 auto lunarDate = GetCurrentLunarDateByMonthDaysColumn(nowLunarYear);
1715 auto getOptionCount = GetOptionCount(monthDaysNode);
1716 getOptionCount = getOptionCount > 0 ? getOptionCount - 1 : 0;
1717 if (monthDaysDatePickerColumnPattern->GetCurrentIndex() == getOptionCount) {
1718 lunarDate.year = lunarDate.year > 0 ? lunarDate.year - 1 : 0; // reduce to previous year
1719 if (lunarDate.year < startDateLunar_.year) {
1720 lunarDate.year = endDateLunar_.year;
1721 }
1722 lunarDate.month = MAX_MONTH; // set to be previous year's max month
1723 lunarDate.isLeapMonth = false;
1724 if (LunarCalculator::GetLunarLeapMonth(lunarDate.year) == 12) { // leap 12th month
1725 lunarDate.isLeapMonth = true;
1726 }
1727 lunarDate.day = GetLunarMaxDay(lunarDate.year, lunarDate.month, lunarDate.isLeapMonth);
1728 }
1729
1730 AdjustLunarDate(lunarDate);
1731 LunarMonthDaysColumnBuilding(lunarDate);
1732 }
1733
HandleYearChange(bool isAdd,uint32_t index,std::vector<RefPtr<FrameNode>> & resultTags)1734 void DatePickerPattern::HandleYearChange(bool isAdd, uint32_t index, std::vector<RefPtr<FrameNode>>& resultTags)
1735 {
1736 auto allChildNode = GetAllChildNode();
1737 auto yearNode = allChildNode["year"];
1738 auto monthNode = allChildNode["month"];
1739 auto dayNode = allChildNode["day"];
1740
1741 CHECK_NULL_VOID(yearNode);
1742 CHECK_NULL_VOID(monthNode);
1743 CHECK_NULL_VOID(dayNode);
1744 if (IsShowLunar()) {
1745 HandleLunarYearChange(isAdd, index);
1746 } else {
1747 HandleSolarYearChange(isAdd, index);
1748 }
1749 resultTags.emplace_back(yearNode);
1750 resultTags.emplace_back(monthNode);
1751 resultTags.emplace_back(dayNode);
1752 }
1753
HandleMonthChange(bool isAdd,uint32_t index,std::vector<RefPtr<FrameNode>> & resultTags)1754 void DatePickerPattern::HandleMonthChange(bool isAdd, uint32_t index, std::vector<RefPtr<FrameNode>>& resultTags)
1755 {
1756 auto allChildNode = GetAllChildNode();
1757 auto yearNode = allChildNode["year"];
1758 auto monthNode = allChildNode["month"];
1759 auto dayNode = allChildNode["day"];
1760
1761 CHECK_NULL_VOID(yearNode);
1762 CHECK_NULL_VOID(monthNode);
1763 CHECK_NULL_VOID(dayNode);
1764 if (IsShowLunar()) {
1765 HandleLunarMonthChange(isAdd, index);
1766 } else {
1767 HandleSolarMonthChange(isAdd, index);
1768 }
1769 resultTags.emplace_back(yearNode);
1770 resultTags.emplace_back(monthNode);
1771 resultTags.emplace_back(dayNode);
1772 }
1773
HandleSolarMonthChange(bool isAdd,uint32_t index)1774 void DatePickerPattern::HandleSolarMonthChange(bool isAdd, uint32_t index)
1775 {
1776 auto date = GetCurrentDate();
1777 if (datePickerMode_ != DatePickerMode::MONTH_AND_DAY) {
1778 if (isAdd && date.GetMonth() == 1) { // first month is 1
1779 date.SetYear(date.GetYear() + 1); // add 1 year, the next year
1780 if (date.GetYear() > endDateSolar_.GetYear()) {
1781 date.SetYear(startDateSolar_.GetYear());
1782 }
1783 }
1784 if (!isAdd && date.GetMonth() == 12) { // the last month is 12
1785 auto getYear = date.GetYear();
1786 getYear = getYear > 0 ? getYear - 1 : 0;
1787 date.SetYear(getYear); // reduce 1 year, the previous year
1788 if (date.GetYear() < startDateSolar_.GetYear()) {
1789 date.SetYear(endDateSolar_.GetYear());
1790 }
1791 }
1792 }
1793 uint32_t maxDay = PickerDate::GetMaxDay(date.GetYear(), date.GetMonth());
1794 if (date.GetDay() > maxDay) {
1795 date.SetDay(maxDay);
1796 }
1797 AdjustSolarDate(date);
1798 SolarColumnsBuilding(date);
1799 }
1800
HandleLunarMonthChange(bool isAdd,uint32_t index)1801 void DatePickerPattern::HandleLunarMonthChange(bool isAdd, uint32_t index)
1802 {
1803 auto allChildNode = GetAllChildNode();
1804 auto yearNode = allChildNode["year"];
1805 auto monthNode = allChildNode["month"];
1806 auto dayNode = allChildNode["day"];
1807
1808 CHECK_NULL_VOID(yearNode);
1809 CHECK_NULL_VOID(monthNode);
1810 CHECK_NULL_VOID(dayNode);
1811
1812 auto yearColumn = yearNode->GetPattern<DatePickerColumnPattern>();
1813 CHECK_NULL_VOID(yearColumn);
1814 uint32_t nowLunarYear = startDateLunar_.year + yearColumn->GetCurrentIndex();
1815 auto lunarDate = GetCurrentLunarDate(nowLunarYear);
1816 if (isAdd && index == 0) {
1817 lunarDate.year = lunarDate.year + 1; // add to next year
1818 if (lunarDate.year > endDateLunar_.year) {
1819 lunarDate.year = startDateLunar_.year;
1820 }
1821 }
1822 auto getOptionCount = GetOptionCount(monthNode);
1823 getOptionCount = getOptionCount > 0 ? getOptionCount - 1 : 0;
1824 if (!isAdd && index == getOptionCount) {
1825 lunarDate.year = lunarDate.year > 0 ? lunarDate.year - 1 : 0; // reduce to previous year
1826 if (lunarDate.year < startDateLunar_.year) {
1827 lunarDate.year = endDateLunar_.year;
1828 }
1829 }
1830 uint32_t lunarLeapMonth = 0;
1831 bool hasLeapMonth = GetLunarLeapMonth(lunarDate.year, lunarLeapMonth);
1832 if (!hasLeapMonth && lunarDate.isLeapMonth) {
1833 lunarDate.isLeapMonth = false;
1834 }
1835 uint32_t maxDay = GetLunarMaxDay(lunarDate.year, lunarDate.month, lunarDate.isLeapMonth);
1836 if (lunarDate.day > maxDay) {
1837 lunarDate.day = maxDay;
1838 }
1839
1840 AdjustLunarDate(lunarDate);
1841 LunarColumnsBuilding(lunarDate);
1842 }
1843
HandleLunarYearChange(bool isAdd,uint32_t index)1844 void DatePickerPattern::HandleLunarYearChange(bool isAdd, uint32_t index)
1845 {
1846 auto allChildNode = GetAllChildNode();
1847 auto yearNode = allChildNode["year"];
1848 CHECK_NULL_VOID(yearNode);
1849 auto yearColumn = DynamicCast<FrameNode>(yearNode);
1850 uint32_t lastYearIndex = index;
1851 auto optionCount = GetOptionCount(yearColumn);
1852 if (isAdd) { // need reduce one index
1853 auto countAndIndex = optionCount + lastYearIndex;
1854 countAndIndex = countAndIndex > 0 ? countAndIndex - 1 : 0;
1855 lastYearIndex = optionCount != 0 ? countAndIndex % optionCount : 0;
1856 } else { // need add one index
1857 lastYearIndex = optionCount != 0 ? (GetOptionCount(yearColumn) + lastYearIndex + 1) % optionCount : 0;
1858 }
1859 uint32_t lastLunarYear = startDateLunar_.year + lastYearIndex;
1860 auto lunarDate = GetCurrentLunarDate(lastLunarYear);
1861 uint32_t nowLeapMonth = 0;
1862 bool hasLeapMonth = GetLunarLeapMonth(lunarDate.year, nowLeapMonth);
1863 if (!hasLeapMonth && lunarDate.isLeapMonth) {
1864 lunarDate.isLeapMonth = false;
1865 }
1866 uint32_t nowMaxDay = GetLunarMaxDay(lunarDate.year, lunarDate.month, lunarDate.isLeapMonth);
1867 if (lunarDate.day > nowMaxDay) {
1868 lunarDate.day = nowMaxDay;
1869 }
1870
1871 AdjustLunarDate(lunarDate);
1872 LunarColumnsBuilding(lunarDate);
1873 }
1874
GetCurrentLunarDate(uint32_t lunarYear) const1875 LunarDate DatePickerPattern::GetCurrentLunarDate(uint32_t lunarYear) const
1876 {
1877 LunarDate lunarResult;
1878 RefPtr<FrameNode> stackYear;
1879 RefPtr<FrameNode> stackMonth;
1880 RefPtr<FrameNode> stackDay;
1881 OrderCurrentLunarDate(stackYear, stackMonth, stackDay);
1882 CHECK_NULL_RETURN(stackYear, lunarResult);
1883 CHECK_NULL_RETURN(stackMonth, lunarResult);
1884 CHECK_NULL_RETURN(stackDay, lunarResult);
1885 auto yearColumn = DynamicCast<FrameNode>(stackYear->GetLastChild()->GetLastChild());
1886 CHECK_NULL_RETURN(yearColumn, lunarResult);
1887 auto monthColumn = DynamicCast<FrameNode>(stackMonth->GetLastChild()->GetLastChild());
1888 CHECK_NULL_RETURN(monthColumn, lunarResult);
1889 auto dayColumn = DynamicCast<FrameNode>(stackDay->GetLastChild()->GetLastChild());
1890 CHECK_NULL_RETURN(dayColumn, lunarResult);
1891 auto yearDatePickerColumnPattern = yearColumn->GetPattern<DatePickerColumnPattern>();
1892 CHECK_NULL_RETURN(yearDatePickerColumnPattern, lunarResult);
1893 auto monthDatePickerColumnPattern = monthColumn->GetPattern<DatePickerColumnPattern>();
1894 CHECK_NULL_RETURN(monthDatePickerColumnPattern, lunarResult);
1895 auto dayDatePickerColumnPattern = dayColumn->GetPattern<DatePickerColumnPattern>();
1896 CHECK_NULL_RETURN(dayDatePickerColumnPattern, lunarResult);
1897 uint32_t lunarLeapMonth = 0;
1898 bool hasLeapMonth = GetLunarLeapMonth(lunarYear, lunarLeapMonth);
1899 lunarResult.isLeapMonth = false;
1900 if (!hasLeapMonth) {
1901 lunarResult.month =
1902 monthDatePickerColumnPattern->GetCurrentIndex() + 1; // month from 1 to 12, index from 0 to 11
1903 } else {
1904 if (monthDatePickerColumnPattern->GetCurrentIndex() == lunarLeapMonth) {
1905 lunarResult.isLeapMonth = true;
1906 lunarResult.month = lunarLeapMonth;
1907 } else if (monthDatePickerColumnPattern->GetCurrentIndex() < lunarLeapMonth) {
1908 lunarResult.month =
1909 monthDatePickerColumnPattern->GetCurrentIndex() + 1; // month start from 1, index start from 0
1910 } else {
1911 lunarResult.month = monthDatePickerColumnPattern->GetCurrentIndex();
1912 }
1913 }
1914 lunarResult.year = startDateLunar_.year + yearDatePickerColumnPattern->GetCurrentIndex();
1915 lunarResult.day = dayDatePickerColumnPattern->GetCurrentIndex() + 1; // day start form 1, index start from 0
1916 return lunarResult;
1917 }
1918
OrderCurrentLunarDate(RefPtr<FrameNode> & stackYear,RefPtr<FrameNode> & stackMonth,RefPtr<FrameNode> & stackDay) const1919 void DatePickerPattern::OrderCurrentLunarDate(
1920 RefPtr<FrameNode>& stackYear, RefPtr<FrameNode>& stackMonth, RefPtr<FrameNode>& stackDay) const
1921 {
1922 auto host = GetHost();
1923 CHECK_NULL_VOID(host);
1924 auto children = host->GetChildren();
1925 auto processDateNode = [&children](RefPtr<UINode>& first, RefPtr<UINode>& second, RefPtr<UINode>& third) {
1926 auto iter = children.begin();
1927 first = *iter++;
1928 CHECK_NULL_VOID(first);
1929 second = *iter++;
1930 CHECK_NULL_VOID(second);
1931 third = *iter;
1932 CHECK_NULL_VOID(third);
1933 };
1934 RefPtr<UINode> year;
1935 RefPtr<UINode> month;
1936 RefPtr<UINode> day;
1937 if (dateOrder_ == "M-d-y") {
1938 processDateNode(month, day, year);
1939 } else if (dateOrder_ == "y-d-M") {
1940 processDateNode(year, day, month);
1941 } else {
1942 processDateNode(year, month, day);
1943 }
1944 stackYear = DynamicCast<FrameNode>(year);
1945 stackMonth = DynamicCast<FrameNode>(month);
1946 stackDay = DynamicCast<FrameNode>(day);
1947 }
1948
HandleSolarYearChange(bool isAdd,uint32_t index)1949 void DatePickerPattern::HandleSolarYearChange(bool isAdd, uint32_t index)
1950 {
1951 auto date = GetCurrentDate();
1952 bool leapYear = PickerDate::IsLeapYear(date.GetYear());
1953 if (date.GetMonth() == 2 && !leapYear && date.GetDay() > 28) { // invalidate of 2th month
1954 date.SetDay(28); // the max day of the 2th month of none leap year is 28
1955 }
1956
1957 AdjustSolarDate(date);
1958 SolarColumnsBuilding(date);
1959 }
1960
GetCurrentDate() const1961 PickerDate DatePickerPattern::GetCurrentDate() const
1962 {
1963 if (ShowMonthDays()) {
1964 return GetCurrentDateByMonthDaysColumn();
1965 } else {
1966 return GetCurrentDateByYearMonthDayColumn();
1967 }
1968 }
1969
GetCurrentDateByYearMonthDayColumn() const1970 PickerDate DatePickerPattern::GetCurrentDateByYearMonthDayColumn() const
1971 {
1972 PickerDate currentDate;
1973 RefPtr<FrameNode> stackYear;
1974 RefPtr<FrameNode> stackMonth;
1975 RefPtr<FrameNode> stackDay;
1976 OrderCurrentDateByYearMonthDayColumn(stackYear, stackMonth, stackDay);
1977 CHECK_NULL_RETURN(stackYear, currentDate);
1978 CHECK_NULL_RETURN(stackMonth, currentDate);
1979 CHECK_NULL_RETURN(stackDay, currentDate);
1980 auto blendYear = DynamicCast<FrameNode>(stackYear->GetLastChild());
1981 CHECK_NULL_RETURN(blendYear, currentDate);
1982 auto yearColumn = DynamicCast<FrameNode>(blendYear->GetLastChild());
1983 CHECK_NULL_RETURN(yearColumn, currentDate);
1984 auto blendMonth = DynamicCast<FrameNode>(stackMonth->GetLastChild());
1985 CHECK_NULL_RETURN(blendMonth, currentDate);
1986 auto monthColumn = DynamicCast<FrameNode>(blendMonth->GetLastChild());
1987 CHECK_NULL_RETURN(monthColumn, currentDate);
1988 auto blendDay = DynamicCast<FrameNode>(stackDay->GetLastChild());
1989 CHECK_NULL_RETURN(blendDay, currentDate);
1990 auto dayColumn = DynamicCast<FrameNode>(blendDay->GetLastChild());
1991 CHECK_NULL_RETURN(dayColumn, currentDate);
1992 auto yearDatePickerColumnPattern = yearColumn->GetPattern<DatePickerColumnPattern>();
1993 auto monthDatePickerColumnPattern = monthColumn->GetPattern<DatePickerColumnPattern>();
1994 auto dayDatePickerColumnPattern = dayColumn->GetPattern<DatePickerColumnPattern>();
1995 CHECK_NULL_RETURN(yearDatePickerColumnPattern, currentDate);
1996 CHECK_NULL_RETURN(monthDatePickerColumnPattern, currentDate);
1997 CHECK_NULL_RETURN(dayDatePickerColumnPattern, currentDate);
1998 if (!IsShowLunar()) {
1999 currentDate.SetYear(startDateSolar_.GetYear() + yearDatePickerColumnPattern->GetCurrentIndex());
2000 currentDate.SetMonth(
2001 monthDatePickerColumnPattern->GetCurrentIndex() + 1); // month from 1 to 12, index from 0 to 11.
2002 currentDate.SetDay(dayDatePickerColumnPattern->GetCurrentIndex() + 1); // day from 1 to 31, index from 0 to 30.
2003 return currentDate;
2004 }
2005 uint32_t lunarYear = startDateLunar_.year + yearDatePickerColumnPattern->GetCurrentIndex();
2006 return LunarToSolar(GetCurrentLunarDate(lunarYear));
2007 }
2008
OrderCurrentDateByYearMonthDayColumn(RefPtr<FrameNode> & stackYear,RefPtr<FrameNode> & stackMonth,RefPtr<FrameNode> & stackDay) const2009 void DatePickerPattern::OrderCurrentDateByYearMonthDayColumn(
2010 RefPtr<FrameNode>& stackYear, RefPtr<FrameNode>& stackMonth, RefPtr<FrameNode>& stackDay) const
2011 {
2012 auto host = GetHost();
2013 CHECK_NULL_VOID(host);
2014 auto children = host->GetChildren();
2015 if (children.size() != CHILD_SIZE) {
2016 return;
2017 }
2018 auto processDateNode = [&children](RefPtr<UINode>& first, RefPtr<UINode>& second, RefPtr<UINode>& third) {
2019 auto iter = children.begin();
2020 first = *iter++;
2021 CHECK_NULL_VOID(first);
2022 second = *iter++;
2023 CHECK_NULL_VOID(second);
2024 third = *iter;
2025 CHECK_NULL_VOID(third);
2026 };
2027 RefPtr<UINode> year;
2028 RefPtr<UINode> month;
2029 RefPtr<UINode> day;
2030 if (dateOrder_ == "M-d-y") {
2031 processDateNode(month, day, year);
2032 } else if (dateOrder_ == "y-d-M") {
2033 processDateNode(year, day, month);
2034 } else {
2035 processDateNode(year, month, day);
2036 }
2037 stackYear = DynamicCast<FrameNode>(year);
2038 stackMonth = DynamicCast<FrameNode>(month);
2039 stackDay = DynamicCast<FrameNode>(day);
2040 }
2041
GetCurrentDateByMonthDaysColumn() const2042 PickerDate DatePickerPattern::GetCurrentDateByMonthDaysColumn() const
2043 {
2044 PickerDate currentDate;
2045 auto host = GetHost();
2046 CHECK_NULL_RETURN(host, currentDate);
2047
2048 auto children = host->GetChildren();
2049 if (children.size() <= SINGLE_CHILD_SIZE) {
2050 return currentDate;
2051 }
2052 auto iter = children.begin();
2053 auto monthDays = (*iter);
2054 CHECK_NULL_RETURN(monthDays, currentDate);
2055 iter++;
2056 auto year = *iter;
2057 CHECK_NULL_RETURN(year, currentDate);
2058 auto stackMonthDays = DynamicCast<FrameNode>(monthDays);
2059 auto blendMonthDays = DynamicCast<FrameNode>(stackMonthDays->GetLastChild());
2060 CHECK_NULL_RETURN(blendMonthDays, currentDate);
2061 auto monthDaysNode = DynamicCast<FrameNode>(blendMonthDays->GetLastChild());
2062 auto stackYear = DynamicCast<FrameNode>(year);
2063 auto blendYear = DynamicCast<FrameNode>(stackYear->GetLastChild());
2064 CHECK_NULL_RETURN(blendYear, currentDate);
2065 auto yearDaysNode = DynamicCast<FrameNode>(blendYear->GetLastChild());
2066 CHECK_NULL_RETURN(monthDaysNode, currentDate);
2067 CHECK_NULL_RETURN(yearDaysNode, currentDate);
2068
2069 auto monthDaysDatePickerColumnPattern = monthDaysNode->GetPattern<DatePickerColumnPattern>();
2070 auto yearDatePickerColumnPattern = yearDaysNode->GetPattern<DatePickerColumnPattern>();
2071 CHECK_NULL_RETURN(yearDatePickerColumnPattern, currentDate);
2072 CHECK_NULL_RETURN(monthDaysDatePickerColumnPattern, currentDate);
2073
2074 if (!IsShowLunar()) {
2075 currentDate.SetYear(startDateSolar_.GetYear() + yearDatePickerColumnPattern->GetCurrentIndex());
2076 auto monthDaysIndex = monthDaysDatePickerColumnPattern->GetCurrentIndex();
2077
2078 uint32_t month = 1;
2079 for (; month <= 12; ++month) { // month start from 1 to 12
2080 uint32_t daysInMonth = PickerDate::GetMaxDay(currentDate.GetYear(), month);
2081 if (monthDaysIndex < daysInMonth) {
2082 break;
2083 } else {
2084 monthDaysIndex -= daysInMonth;
2085 }
2086 }
2087 currentDate.SetMonth(month);
2088 currentDate.SetDay(monthDaysIndex + 1); // days is index start form 0 and day start form 1.
2089 return currentDate;
2090 }
2091
2092 uint32_t lunarYear = startDateLunar_.year + yearDatePickerColumnPattern->GetCurrentIndex();
2093 return LunarToSolar(GetCurrentLunarDateByMonthDaysColumn(lunarYear));
2094 }
2095
GetCurrentLunarDateByMonthDaysColumn(uint32_t lunarYear) const2096 LunarDate DatePickerPattern::GetCurrentLunarDateByMonthDaysColumn(uint32_t lunarYear) const
2097 {
2098 LunarDate lunarResult;
2099 auto host = GetHost();
2100 CHECK_NULL_RETURN(host, lunarResult);
2101
2102 auto children = host->GetChildren();
2103 if (children.size() <= SINGLE_CHILD_SIZE) {
2104 return lunarResult;
2105 }
2106 auto iter = children.begin();
2107 auto monthDays = (*iter);
2108 CHECK_NULL_RETURN(monthDays, lunarResult);
2109 auto stackMonthDays = DynamicCast<FrameNode>(monthDays);
2110 auto monthDaysNode = DynamicCast<FrameNode>(stackMonthDays->GetLastChild()->GetLastChild());
2111 CHECK_NULL_RETURN(monthDaysNode, lunarResult);
2112
2113 auto monthDaysDatePickerColumnPattern = monthDaysNode->GetPattern<DatePickerColumnPattern>();
2114 CHECK_NULL_RETURN(monthDaysDatePickerColumnPattern, lunarResult);
2115
2116 uint32_t lunarLeapMonth = 0;
2117 bool hasLeapMonth = GetLunarLeapMonth(lunarYear, lunarLeapMonth);
2118 uint32_t remainingDays = monthDaysDatePickerColumnPattern->GetCurrentIndex();
2119
2120 // common function for processing a month
2121 auto processMonth = [&](uint32_t month, bool isLeap) -> bool {
2122 uint32_t daysInMonth = GetLunarMaxDay(lunarYear, month, isLeap);
2123 if (remainingDays < daysInMonth) {
2124 lunarResult.month = month;
2125 lunarResult.isLeapMonth = isLeap;
2126 lunarResult.day = remainingDays + 1;
2127 return true; // target month is found
2128 }
2129 remainingDays -= daysInMonth;
2130 return false; // continue to process next month
2131 };
2132
2133 lunarResult.year = lunarYear;
2134 for (uint32_t month = MIN_MONTH; month <= MAX_MONTH; ++month) {
2135 // process regular month
2136 if (processMonth(month, false)) {
2137 break;
2138 }
2139
2140 // process leap month if exists
2141 if (hasLeapMonth && lunarLeapMonth == month) {
2142 if (processMonth(month, true)) {
2143 break;
2144 }
2145 }
2146 }
2147 return lunarResult;
2148 }
2149
AdjustLunarDate(LunarDate & date)2150 void DatePickerPattern::AdjustLunarDate(LunarDate& date)
2151 {
2152 auto host = GetHost();
2153 CHECK_NULL_VOID(host);
2154
2155 auto dataPickerRowLayoutProperty = host->GetLayoutProperty<DataPickerRowLayoutProperty>();
2156 CHECK_NULL_VOID(dataPickerRowLayoutProperty);
2157 startDateLunar_ = dataPickerRowLayoutProperty->GetStartDate().value_or(SolarToLunar(startDateSolar_));
2158 endDateLunar_ = dataPickerRowLayoutProperty->GetEndDate().value_or(SolarToLunar(endDateSolar_));
2159
2160 if (LunarDateCompare(date, startDateLunar_) < 0) {
2161 date = startDateLunar_;
2162 return;
2163 }
2164 if (LunarDateCompare(date, endDateLunar_) > 0) {
2165 date = endDateLunar_;
2166 }
2167 }
2168
LunarDateCompare(const LunarDate & left,const LunarDate & right) const2169 int DatePickerPattern::LunarDateCompare(const LunarDate& left, const LunarDate& right) const
2170 {
2171 static const int leftEqualRight = 0; // means left = right
2172 static const int leftGreatRight = 1; // means left > right
2173 static const int leftLessRight = -1; // means left < right
2174 static const double addingValue = 0.5; // adding value for leap month.
2175 if (left.year > right.year) {
2176 return leftGreatRight;
2177 }
2178 if (left.year < right.year) {
2179 return leftLessRight;
2180 }
2181 double leftMonth = (left.isLeapMonth ? left.month + addingValue : left.month);
2182 double rightMonth = (right.isLeapMonth ? right.month + addingValue : right.month);
2183 if (GreatNotEqual(leftMonth, rightMonth)) {
2184 return leftGreatRight;
2185 }
2186 if (LessNotEqual(leftMonth, rightMonth)) {
2187 return leftLessRight;
2188 }
2189 if (left.day > right.day) {
2190 return leftGreatRight;
2191 }
2192 if (left.day < right.day) {
2193 return leftLessRight;
2194 }
2195 return leftEqualRight;
2196 }
2197
LunarColumnsBuilding(const LunarDate & current)2198 void DatePickerPattern::LunarColumnsBuilding(const LunarDate& current)
2199 {
2200 RefPtr<FrameNode> yearColumn;
2201 RefPtr<FrameNode> monthColumn;
2202 RefPtr<FrameNode> dayColumn;
2203 RefPtr<FrameNode> columns[COLUMNS_SIZE];
2204 auto host = GetHost();
2205 CHECK_NULL_VOID(host);
2206 int index = 0;
2207 int order[COLUMNS_SIZE];
2208 if (dateOrder_ == "M-d-y") {
2209 order[COLUMNS_ZERO] = INDEX_MONTH;
2210 order[COLUMNS_ONE] = INDEX_DAY;
2211 order[COLUMNS_TWO] = INDEX_YEAR;
2212 } else if (dateOrder_ == "y-d-M") {
2213 order[COLUMNS_ZERO] = INDEX_YEAR;
2214 order[COLUMNS_ONE] = INDEX_DAY;
2215 order[COLUMNS_TWO] = INDEX_MONTH;
2216 } else {
2217 order[COLUMNS_ZERO] = INDEX_YEAR;
2218 order[COLUMNS_ONE] = INDEX_MONTH;
2219 order[COLUMNS_TWO] = INDEX_DAY;
2220 }
2221 for (const auto& stackChild : host->GetChildren()) {
2222 CHECK_NULL_VOID(stackChild);
2223 auto blendChild = stackChild->GetLastChild();
2224 CHECK_NULL_VOID(blendChild);
2225 auto child = blendChild->GetLastChild();
2226 columns[order[index]] = GetColumn(child->GetId());
2227 index++;
2228 }
2229 yearColumn = columns[COLUMNS_ZERO];
2230 monthColumn = columns[COLUMNS_ONE];
2231 dayColumn = columns[COLUMNS_TWO];
2232 CHECK_NULL_VOID(yearColumn);
2233 CHECK_NULL_VOID(monthColumn);
2234 CHECK_NULL_VOID(dayColumn);
2235
2236 AdjustLunarStartEndDate();
2237 auto startYear = startDateLunar_.year;
2238 auto endYear = endDateLunar_.year;
2239 auto startMonth = startDateLunar_.month;
2240 auto endMonth = endDateLunar_.month;
2241 auto startDay = startDateLunar_.day;
2242 auto endDay = endDateLunar_.day;
2243 uint32_t maxDay = GetLunarMaxDay(current.year, current.month, current.isLeapMonth);
2244 if (startYear < endYear) {
2245 startMonth = 1;
2246 endMonth = 12;
2247 startDay = 1;
2248 endDay = maxDay;
2249 }
2250 if (startYear == endYear && startMonth < endMonth) {
2251 startDay = 1;
2252 endDay = maxDay;
2253 }
2254
2255 options_[yearColumn].clear();
2256 for (uint32_t index = startYear; index <= endYear; ++index) {
2257 if (current.year == index) {
2258 auto datePickerColumnPattern = yearColumn->GetPattern<DatePickerColumnPattern>();
2259 CHECK_NULL_VOID(datePickerColumnPattern);
2260 datePickerColumnPattern->SetCurrentIndex(options_[yearColumn].size());
2261 datePickerColumnPattern->HandleAccessibilityTextChange();
2262 }
2263 options_[yearColumn].emplace_back(PickerDateF::CreateYear(index));
2264 }
2265
2266 uint32_t lunarLeapMonth = 0;
2267 bool hasLeapMonth = GetLunarLeapMonth(current.year, lunarLeapMonth);
2268 options_[monthColumn].clear();
2269 if (startYear == endYear) {
2270 options_[monthColumn].resize(startMonth > 0 ? startMonth - 1 : 0, emptyPickerDate_);
2271 }
2272 // lunar's month start form startMonth to endMonth
2273 for (uint32_t index = startMonth; index <= endMonth; ++index) {
2274 if (!current.isLeapMonth && current.month == index) {
2275 auto datePickerColumnPattern = monthColumn->GetPattern<DatePickerColumnPattern>();
2276 CHECK_NULL_VOID(datePickerColumnPattern);
2277 datePickerColumnPattern->SetCurrentIndex(options_[monthColumn].size());
2278 datePickerColumnPattern->HandleAccessibilityTextChange();
2279 }
2280 options_[monthColumn].emplace_back(PickerDateF::CreateMonth(index, true, false));
2281
2282 if (hasLeapMonth && lunarLeapMonth == index) {
2283 if (current.isLeapMonth && current.month == index) {
2284 auto datePickerColumnPattern = monthColumn->GetPattern<DatePickerColumnPattern>();
2285 CHECK_NULL_VOID(datePickerColumnPattern);
2286 datePickerColumnPattern->SetCurrentIndex(options_[monthColumn].size());
2287 datePickerColumnPattern->HandleAccessibilityTextChange();
2288 }
2289 options_[monthColumn].emplace_back(PickerDateF::CreateMonth(index, true, true));
2290 }
2291 }
2292
2293 options_[dayColumn].clear();
2294 if (startYear == endYear && startMonth == endMonth) {
2295 options_[dayColumn].resize(startDay > 0 ? startDay - 1 : 0, emptyPickerDate_);
2296 }
2297 // lunar's day start from startDay
2298 for (uint32_t index = startDay; index <= endDay; ++index) {
2299 if (current.day == index) {
2300 auto datePickerColumnPattern = dayColumn->GetPattern<DatePickerColumnPattern>();
2301 CHECK_NULL_VOID(datePickerColumnPattern);
2302 datePickerColumnPattern->SetCurrentIndex(options_[dayColumn].size());
2303 datePickerColumnPattern->HandleAccessibilityTextChange();
2304 }
2305 options_[dayColumn].emplace_back(PickerDateF::CreateDay(index, true));
2306 }
2307 auto yearColumnPattern = yearColumn->GetPattern<DatePickerColumnPattern>();
2308 CHECK_NULL_VOID(yearColumnPattern);
2309 auto monthColumnPattern = monthColumn->GetPattern<DatePickerColumnPattern>();
2310 CHECK_NULL_VOID(monthColumnPattern);
2311 auto dayColumnPattern = dayColumn->GetPattern<DatePickerColumnPattern>();
2312 CHECK_NULL_VOID(dayColumnPattern);
2313 yearColumnPattern->SetOptions(GetOptions());
2314 monthColumnPattern->SetOptions(GetOptions());
2315 dayColumnPattern->SetOptions(GetOptions());
2316
2317 SetShowLunar(true);
2318 }
2319
SolarColumnsBuilding(const PickerDate & current)2320 void DatePickerPattern::SolarColumnsBuilding(const PickerDate& current)
2321 {
2322 RefPtr<FrameNode> yearColumn;
2323 RefPtr<FrameNode> monthColumn;
2324 RefPtr<FrameNode> dayColumn;
2325
2326 RefPtr<FrameNode> columns[COLUMNS_SIZE];
2327 auto host = GetHost();
2328 CHECK_NULL_VOID(host);
2329 int index = 0;
2330 int order[COLUMNS_SIZE];
2331 if (dateOrder_ == "M-d-y") {
2332 order[COLUMNS_ZERO] = INDEX_MONTH;
2333 order[COLUMNS_ONE] = INDEX_DAY;
2334 order[COLUMNS_TWO] = INDEX_YEAR;
2335 } else if (dateOrder_ == "y-d-M") {
2336 order[COLUMNS_ZERO] = INDEX_YEAR;
2337 order[COLUMNS_ONE] = INDEX_DAY;
2338 order[COLUMNS_TWO] = INDEX_MONTH;
2339 } else {
2340 order[COLUMNS_ZERO] = INDEX_YEAR;
2341 order[COLUMNS_ONE] = INDEX_MONTH;
2342 order[COLUMNS_TWO] = INDEX_DAY;
2343 }
2344 for (const auto& stackChild : host->GetChildren()) {
2345 CHECK_NULL_VOID(stackChild);
2346 auto blendChild = stackChild->GetLastChild();
2347 CHECK_NULL_VOID(blendChild);
2348 auto child = blendChild->GetLastChild();
2349 columns[order[index]] = GetColumn(child->GetId());
2350 index++;
2351 }
2352 yearColumn = columns[COLUMNS_ZERO];
2353 monthColumn = columns[COLUMNS_ONE];
2354 dayColumn = columns[COLUMNS_TWO];
2355
2356 CHECK_NULL_VOID(yearColumn);
2357 CHECK_NULL_VOID(monthColumn);
2358 CHECK_NULL_VOID(dayColumn);
2359
2360 AdjustSolarStartEndDate();
2361 auto startYear = startDateSolar_.GetYear();
2362 auto endYear = endDateSolar_.GetYear();
2363 auto startMonth = startDateSolar_.GetMonth();
2364 auto endMonth = endDateSolar_.GetMonth();
2365 auto startDay = startDateSolar_.GetDay();
2366 auto endDay = endDateSolar_.GetDay();
2367
2368 uint32_t maxDay = PickerDate::GetMaxDay(current.GetYear(), current.GetMonth());
2369 if (startYear < endYear) {
2370 startMonth = 1;
2371 endMonth = 12;
2372 startDay = 1;
2373 endDay = maxDay;
2374 }
2375 if (startYear == endYear && startMonth < endMonth) {
2376 startDay = 1;
2377 endDay = maxDay;
2378 }
2379
2380 options_[yearColumn].clear();
2381 for (uint32_t year = startYear; year <= endYear; ++year) {
2382 if (year == current.GetYear()) {
2383 auto datePickerColumnPattern = yearColumn->GetPattern<DatePickerColumnPattern>();
2384 CHECK_NULL_VOID(datePickerColumnPattern);
2385 datePickerColumnPattern->SetCurrentIndex(options_[yearColumn].size());
2386 datePickerColumnPattern->HandleAccessibilityTextChange();
2387 }
2388 options_[yearColumn].emplace_back(PickerDateF::CreateYear(year));
2389 }
2390
2391 options_[monthColumn].clear();
2392 if (startYear == endYear) {
2393 options_[monthColumn].resize(startMonth > 0 ? startMonth - 1 : 0, emptyPickerDate_);
2394 }
2395 // solar's month start form 1 to 12
2396 for (uint32_t month = startMonth; month <= endMonth; month++) {
2397 if (month == current.GetMonth()) {
2398 auto datePickerColumnPattern = monthColumn->GetPattern<DatePickerColumnPattern>();
2399 CHECK_NULL_VOID(datePickerColumnPattern);
2400 // back index = size - 1
2401 datePickerColumnPattern->SetCurrentIndex(options_[monthColumn].size());
2402 datePickerColumnPattern->HandleAccessibilityTextChange();
2403 }
2404
2405 options_[monthColumn].emplace_back(PickerDateF::CreateMonth(month, false, false));
2406 }
2407
2408 options_[dayColumn].clear();
2409 if (startYear == endYear && startMonth == endMonth) {
2410 options_[dayColumn].resize(startDay - 1, emptyPickerDate_);
2411 }
2412 // solar's day start from 1
2413 for (uint32_t day = startDay; day <= endDay; day++) {
2414 if (day == current.GetDay()) {
2415 auto datePickerColumnPattern = dayColumn->GetPattern<DatePickerColumnPattern>();
2416 CHECK_NULL_VOID(datePickerColumnPattern);
2417 datePickerColumnPattern->SetCurrentIndex(options_[dayColumn].size());
2418 datePickerColumnPattern->HandleAccessibilityTextChange();
2419 }
2420 options_[dayColumn].emplace_back(PickerDateF::CreateDay(day, false));
2421 }
2422
2423 auto yearColumnPattern = yearColumn->GetPattern<DatePickerColumnPattern>();
2424 CHECK_NULL_VOID(yearColumnPattern);
2425 auto monthColumnPattern = monthColumn->GetPattern<DatePickerColumnPattern>();
2426 CHECK_NULL_VOID(monthColumnPattern);
2427 auto dayColumnPattern = dayColumn->GetPattern<DatePickerColumnPattern>();
2428 CHECK_NULL_VOID(dayColumnPattern);
2429 yearColumnPattern->SetOptions(GetOptions());
2430 monthColumnPattern->SetOptions(GetOptions());
2431 dayColumnPattern->SetOptions(GetOptions());
2432
2433 SetShowLunar(false);
2434 }
2435
LunarMonthDaysColumnBuilding(const LunarDate & current)2436 void DatePickerPattern::LunarMonthDaysColumnBuilding(const LunarDate& current)
2437 {
2438 RefPtr<FrameNode> monthDaysColumn;
2439 RefPtr<FrameNode> yearColumn;
2440 auto host = GetHost();
2441 CHECK_NULL_VOID(host);
2442
2443 auto children = host->GetChildren();
2444 if (children.size() <= SINGLE_CHILD_SIZE) {
2445 return;
2446 }
2447
2448 auto iter = children.begin();
2449 auto monthDays = (*iter);
2450 CHECK_NULL_VOID(monthDays);
2451 iter++;
2452 auto year = *iter;
2453 CHECK_NULL_VOID(year);
2454 auto stackMonthDays = DynamicCast<FrameNode>(monthDays);
2455 auto blendMonthDays = DynamicCast<FrameNode>(stackMonthDays->GetLastChild());
2456 CHECK_NULL_VOID(blendMonthDays);
2457 auto monthDaysNode = DynamicCast<FrameNode>(blendMonthDays->GetLastChild());
2458 auto stackYear = DynamicCast<FrameNode>(year);
2459 auto blendYear = DynamicCast<FrameNode>(stackYear->GetLastChild());
2460 CHECK_NULL_VOID(blendYear);
2461 auto yearDaysNode = DynamicCast<FrameNode>(blendYear->GetLastChild());
2462 CHECK_NULL_VOID(monthDaysNode);
2463 CHECK_NULL_VOID(yearDaysNode);
2464
2465 monthDaysColumn = GetColumn(monthDaysNode->GetId());
2466 yearColumn = GetColumn(yearDaysNode->GetId());
2467 CHECK_NULL_VOID(monthDaysColumn);
2468 CHECK_NULL_VOID(yearColumn);
2469
2470 AdjustLunarStartEndDate();
2471
2472 auto startYear = startDateLunar_.year;
2473 auto endYear = endDateLunar_.year;
2474
2475 options_[yearColumn].clear();
2476 for (uint32_t index = startYear; index <= endYear; ++index) {
2477 if (current.year == index) {
2478 auto datePickerColumnPattern = yearColumn->GetPattern<DatePickerColumnPattern>();
2479 CHECK_NULL_VOID(datePickerColumnPattern);
2480 datePickerColumnPattern->SetCurrentIndex(options_[yearColumn].size());
2481 datePickerColumnPattern->HandleAccessibilityTextChange();
2482 }
2483 options_[yearColumn].emplace_back(PickerDateF::CreateYear(index));
2484 }
2485
2486 FillLunarMonthDaysOptions(current, monthDaysColumn);
2487
2488 auto yearColumnPattern = yearColumn->GetPattern<DatePickerColumnPattern>();
2489 auto monthDaysColumnPattern = monthDaysColumn->GetPattern<DatePickerColumnPattern>();
2490 CHECK_NULL_VOID(yearColumnPattern);
2491 CHECK_NULL_VOID(monthDaysColumnPattern);
2492 yearColumnPattern->SetOptions(GetOptions());
2493 monthDaysColumnPattern->SetOptions(GetOptions());
2494
2495 SetShowLunar(true);
2496 }
2497
SolarMonthDaysColumnsBuilding(const PickerDate & current)2498 void DatePickerPattern::SolarMonthDaysColumnsBuilding(const PickerDate& current)
2499 {
2500 RefPtr<FrameNode> monthDaysColumn;
2501 RefPtr<FrameNode> yearColumn;
2502 auto host = GetHost();
2503 CHECK_NULL_VOID(host);
2504
2505 auto children = host->GetChildren();
2506 if (children.size() <= SINGLE_CHILD_SIZE) {
2507 return;
2508 }
2509 auto iter = children.begin();
2510 auto monthDays = (*iter);
2511 CHECK_NULL_VOID(monthDays);
2512 iter++;
2513 auto year = *iter;
2514 CHECK_NULL_VOID(year);
2515 auto stackMonthDays = DynamicCast<FrameNode>(monthDays);
2516 auto blendMonthDays = DynamicCast<FrameNode>(stackMonthDays->GetLastChild());
2517 CHECK_NULL_VOID(blendMonthDays);
2518 auto monthDaysNode = DynamicCast<FrameNode>(blendMonthDays->GetLastChild());
2519 auto stackYear = DynamicCast<FrameNode>(year);
2520 auto blendYear = DynamicCast<FrameNode>(stackYear->GetLastChild());
2521 CHECK_NULL_VOID(blendYear);
2522 auto yearDaysNode = DynamicCast<FrameNode>(blendYear->GetLastChild());
2523 monthDaysColumn = GetColumn(monthDaysNode->GetId());
2524 yearColumn = GetColumn(yearDaysNode->GetId());
2525 CHECK_NULL_VOID(monthDaysColumn);
2526 CHECK_NULL_VOID(yearColumn);
2527
2528 AdjustSolarStartEndDate();
2529 FillSolarYearOptions(current, yearColumn);
2530
2531 options_[monthDaysColumn].clear();
2532 for (uint32_t index = MIN_MONTH; index <= MAX_MONTH; ++index) {
2533 uint32_t maxDay = PickerDate::GetMaxDay(current.GetYear(), index);
2534 for (uint32_t dayIndex = MIN_DAY; dayIndex <= maxDay; ++dayIndex) {
2535 if (index == current.GetMonth() && dayIndex == current.GetDay()) {
2536 auto datePickerColumnPattern = monthDaysColumn->GetPattern<DatePickerColumnPattern>();
2537 CHECK_NULL_VOID(datePickerColumnPattern);
2538 datePickerColumnPattern->SetCurrentIndex(options_[monthDaysColumn].size());
2539 datePickerColumnPattern->HandleAccessibilityTextChange();
2540 }
2541 options_[monthDaysColumn].emplace_back(PickerDateF::CreateMonthDay(index, dayIndex, false, false));
2542 }
2543 }
2544
2545 auto yearColumnPattern = yearColumn->GetPattern<DatePickerColumnPattern>();
2546 auto monthDaysColumnPattern = monthDaysColumn->GetPattern<DatePickerColumnPattern>();
2547 CHECK_NULL_VOID(yearColumnPattern);
2548 CHECK_NULL_VOID(monthDaysColumnPattern);
2549 yearColumnPattern->SetOptions(GetOptions());
2550 monthDaysColumnPattern->SetOptions(GetOptions());
2551
2552 SetShowLunar(false);
2553 }
2554
FillSolarYearOptions(const PickerDate & current,RefPtr<FrameNode> & yearColumn)2555 void DatePickerPattern::FillSolarYearOptions(const PickerDate& current, RefPtr<FrameNode>& yearColumn)
2556 {
2557 options_[yearColumn].clear();
2558 for (uint32_t year = startDateSolar_.GetYear(); year <= endDateSolar_.GetYear(); ++year) {
2559 if (year == current.GetYear()) {
2560 auto datePickerColumnPattern = yearColumn->GetPattern<DatePickerColumnPattern>();
2561 CHECK_NULL_VOID(datePickerColumnPattern);
2562 datePickerColumnPattern->SetCurrentIndex(options_[yearColumn].size());
2563 datePickerColumnPattern->HandleAccessibilityTextChange();
2564 }
2565 options_[yearColumn].emplace_back(PickerDateF::CreateYear(year));
2566 }
2567 }
2568
FillLunarMonthDaysOptions(const LunarDate & current,RefPtr<FrameNode> & monthDaysColumn)2569 void DatePickerPattern::FillLunarMonthDaysOptions(const LunarDate& current, RefPtr<FrameNode>& monthDaysColumn)
2570 {
2571 uint32_t startMonth = 1;
2572 uint32_t endMonth = 12;
2573 uint32_t startDay = 1;
2574
2575 uint32_t lunarLeapMonth = 0;
2576 bool hasLeapMonth = GetLunarLeapMonth(current.year, lunarLeapMonth);
2577 options_[monthDaysColumn].clear();
2578
2579 for (uint32_t index = startMonth; index <= endMonth; ++index) {
2580 uint32_t maxDay = GetLunarMaxDay(current.year, index, false);
2581 for (uint32_t dayIndex = startDay; dayIndex <= maxDay; ++dayIndex) {
2582 if (!current.isLeapMonth && current.month == index && current.day == dayIndex) {
2583 auto datePickerColumnPattern = monthDaysColumn->GetPattern<DatePickerColumnPattern>();
2584 CHECK_NULL_VOID(datePickerColumnPattern);
2585 datePickerColumnPattern->SetCurrentIndex(options_[monthDaysColumn].size());
2586 datePickerColumnPattern->HandleAccessibilityTextChange();
2587 }
2588 options_[monthDaysColumn].emplace_back(PickerDateF::CreateMonthDay(index, dayIndex, true, false));
2589 }
2590
2591 if (!hasLeapMonth || lunarLeapMonth != index) {
2592 continue;
2593 }
2594
2595 maxDay = GetLunarMaxDay(current.year, index, true);
2596 for (uint32_t dayIndex = startDay; dayIndex <= maxDay; ++dayIndex) {
2597 if (current.isLeapMonth && current.month == index && current.day == dayIndex) {
2598 auto datePickerColumnPattern = monthDaysColumn->GetPattern<DatePickerColumnPattern>();
2599 CHECK_NULL_VOID(datePickerColumnPattern);
2600 datePickerColumnPattern->SetCurrentIndex(options_[monthDaysColumn].size());
2601 datePickerColumnPattern->HandleAccessibilityTextChange();
2602 }
2603 options_[monthDaysColumn].emplace_back(PickerDateF::CreateMonthDay(index, dayIndex, true, true));
2604 }
2605 }
2606 }
2607
AdjustSolarStartEndDate()2608 void DatePickerPattern::AdjustSolarStartEndDate()
2609 {
2610 auto host = GetHost();
2611 CHECK_NULL_VOID(host);
2612
2613 auto dataPickerRowLayoutProperty = host->GetLayoutProperty<DataPickerRowLayoutProperty>();
2614 CHECK_NULL_VOID(dataPickerRowLayoutProperty);
2615 startDateSolar_ = LunarToSolar(dataPickerRowLayoutProperty->GetStartDate().value_or(SolarToLunar(startDateSolar_)));
2616 endDateSolar_ = LunarToSolar(dataPickerRowLayoutProperty->GetEndDate().value_or(SolarToLunar(endDateSolar_)));
2617
2618 if (startDateSolar_.GetYear() > endDateSolar_.GetYear()) {
2619 startDateSolar_ = startDefaultDateSolar_;
2620 endDateSolar_ = endDefaultDateSolar_;
2621 }
2622 if (startDateSolar_.GetYear() == endDateSolar_.GetYear() && startDateSolar_.GetMonth() > endDateSolar_.GetMonth()) {
2623 startDateSolar_ = startDefaultDateSolar_;
2624 endDateSolar_ = endDefaultDateSolar_;
2625 }
2626 if (startDateSolar_.GetYear() == endDateSolar_.GetYear() &&
2627 startDateSolar_.GetMonth() == endDateSolar_.GetMonth() && startDateSolar_.GetDay() > endDateSolar_.GetDay()) {
2628 startDateSolar_ = startDefaultDateSolar_;
2629 endDateSolar_ = endDefaultDateSolar_;
2630 }
2631 }
2632
AdjustLunarStartEndDate()2633 void DatePickerPattern::AdjustLunarStartEndDate()
2634 {
2635 auto host = GetHost();
2636 CHECK_NULL_VOID(host);
2637
2638 auto dataPickerRowLayoutProperty = host->GetLayoutProperty<DataPickerRowLayoutProperty>();
2639 CHECK_NULL_VOID(dataPickerRowLayoutProperty);
2640 startDateLunar_ = dataPickerRowLayoutProperty->GetStartDate().value_or(SolarToLunar(startDateSolar_));
2641 endDateLunar_ = dataPickerRowLayoutProperty->GetEndDate().value_or(SolarToLunar(endDateSolar_));
2642
2643 if (GetStartDateLunar().year > GetEndDateLunar().year) {
2644 startDateLunar_ = SolarToLunar(startDefaultDateSolar_);
2645 endDateLunar_ = SolarToLunar(endDefaultDateSolar_);
2646 }
2647 if (GetStartDateLunar().year == GetEndDateLunar().year && GetStartDateLunar().month > GetEndDateLunar().month) {
2648 startDateLunar_ = SolarToLunar(startDefaultDateSolar_);
2649 endDateLunar_ = SolarToLunar(endDefaultDateSolar_);
2650 }
2651 if (GetStartDateLunar().year == GetEndDateLunar().year && GetStartDateLunar().month == GetEndDateLunar().month &&
2652 GetStartDateLunar().day > GetEndDateLunar().day) {
2653 startDateLunar_ = SolarToLunar(startDefaultDateSolar_);
2654 endDateLunar_ = SolarToLunar(endDefaultDateSolar_);
2655 }
2656 }
2657
GetLunarLeapMonth(uint32_t year,uint32_t & outLeapMonth) const2658 bool DatePickerPattern::GetLunarLeapMonth(uint32_t year, uint32_t& outLeapMonth) const
2659 {
2660 auto leapMonth = LunarCalculator::GetLunarLeapMonth(year);
2661 if (leapMonth <= 0) {
2662 return false;
2663 }
2664
2665 outLeapMonth = static_cast<uint32_t>(leapMonth);
2666 return true;
2667 }
2668
GetLunarMaxDay(uint32_t year,uint32_t month,bool isLeap) const2669 uint32_t DatePickerPattern::GetLunarMaxDay(uint32_t year, uint32_t month, bool isLeap) const
2670 {
2671 if (isLeap) {
2672 return static_cast<uint32_t>(LunarCalculator::GetLunarLeapDays(year));
2673 } else {
2674 return static_cast<uint32_t>(LunarCalculator::GetLunarMonthDays(year, month));
2675 }
2676 }
2677
SolarToLunar(const PickerDate & date) const2678 LunarDate DatePickerPattern::SolarToLunar(const PickerDate& date) const
2679 {
2680 Date result;
2681 result.year = date.GetYear();
2682 result.month = date.GetMonth();
2683 result.day = date.GetDay();
2684 return Localization::GetInstance()->GetLunarDate(result);
2685 }
2686
LunarToSolar(const LunarDate & date) const2687 PickerDate DatePickerPattern::LunarToSolar(const LunarDate& date) const
2688 {
2689 uint32_t days = date.day > 0 ? date.day - 1 : 0; // calculate days from 1900.1.1 to this date
2690 if (date.isLeapMonth) {
2691 days += LunarCalculator::GetLunarMonthDays(date.year, date.month);
2692 } else {
2693 uint32_t leapMonth = LunarCalculator::GetLunarLeapMonth(date.year);
2694 if (leapMonth < date.month) {
2695 days += LunarCalculator::GetLunarLeapDays(date.year);
2696 }
2697 }
2698 for (uint32_t month = 1; month < date.month; ++month) { // month start from 1
2699 days += LunarCalculator::GetLunarMonthDays(date.year, month);
2700 }
2701 for (uint32_t year = 1900; year < date.year; ++year) { // year start from 1900
2702 days += LunarCalculator::GetLunarYearDays(year);
2703 }
2704 days += 30; // days from solar's 1900.1.1 to lunar's 1900.1.1 is 30
2705 PickerDate result;
2706 result.FromDays(days);
2707 return result;
2708 }
2709
Init()2710 void DatePickerPattern::Init()
2711 {
2712 if (inited_) {
2713 return;
2714 }
2715 years_.clear();
2716 solarMonths_.clear();
2717 solarDays_.clear();
2718 lunarMonths_.clear();
2719 lunarDays_.clear();
2720 localizedMonths_ = Localization::GetInstance()->GetMonths(true);
2721
2722 inited_ = true;
2723 Localization::GetInstance()->SetOnChange([]() { inited_ = false; });
2724 }
2725
GetYear(uint32_t year)2726 const std::string& DatePickerPattern::GetYear(uint32_t year)
2727 {
2728 Init();
2729 if (!(1900 <= year && year <= 2100)) { // year in [1900,2100]
2730 return empty_;
2731 }
2732 auto index = year - 1900;
2733 auto it = years_.find(index);
2734 if (it == years_.end()) {
2735 DateTime date;
2736 date.year = year;
2737 auto& dateYear = years_[index];
2738 dateYear = Localization::GetInstance()->FormatDateTime(date, "y");
2739 return dateYear;
2740 }
2741 return it->second; // index in [0, 200]
2742 }
2743
GetSolarMonth(uint32_t month)2744 const std::string& DatePickerPattern::GetSolarMonth(uint32_t month)
2745 {
2746 Init();
2747 if (!(1 <= month && month <= 12)) { // solar month in [1,12]
2748 return empty_;
2749 }
2750 auto index = month - 1;
2751 auto it = solarMonths_.find(index);
2752 if (it == solarMonths_.end()) {
2753 auto& dateMonth = solarMonths_[index];
2754 if (index < localizedMonths_.size()) {
2755 dateMonth = localizedMonths_[index];
2756 } else {
2757 DateTime date;
2758 date.month = month - 1; // W3C's month start from 0 to 11
2759 dateMonth = Localization::GetInstance()->FormatDateTime(date, "M");
2760 }
2761 return dateMonth;
2762 }
2763 return it->second; // index in [0,11]
2764 }
2765
GetSolarDay(uint32_t day)2766 const std::string& DatePickerPattern::GetSolarDay(uint32_t day)
2767 {
2768 Init();
2769 if (!(1 <= day && day <= 31)) { // solar day in [1,31]
2770 return empty_;
2771 }
2772 auto index = day - 1;
2773 auto it = solarDays_.find(index);
2774 if (it == solarDays_.end()) {
2775 auto& dateDay = solarDays_[index];
2776 DateTime date;
2777 date.day = day;
2778 dateDay = Localization::GetInstance()->FormatDateTime(date, "d");
2779 return dateDay;
2780 }
2781 return it->second; // index in [0,30]
2782 }
2783
GetLunarMonth(uint32_t month,bool isLeap)2784 const std::string& DatePickerPattern::GetLunarMonth(uint32_t month, bool isLeap)
2785 {
2786 Init();
2787 uint32_t index = (isLeap ? month + 12 : month); // leap month is behind 12 index
2788 if (!(1 <= index && index <= 24)) { // lunar month need in [1,24]
2789 return empty_;
2790 }
2791 auto it = lunarMonths_.find(index - 1);
2792 if (it == lunarMonths_.end()) {
2793 auto& dateMonth = lunarMonths_[index - 1];
2794 dateMonth = Localization::GetInstance()->GetLunarMonth(month, isLeap);
2795 return dateMonth;
2796 }
2797 return it->second; // index in [0,23]
2798 }
2799
GetLunarDay(uint32_t day)2800 const std::string& DatePickerPattern::GetLunarDay(uint32_t day)
2801 {
2802 Init();
2803 if (!(1 <= day && day <= 30)) { // lunar day need in [1,30]
2804 return empty_;
2805 }
2806 auto index = day - 1;
2807 auto it = lunarDays_.find(index);
2808 if (it == lunarDays_.end()) {
2809 auto& dateDay = lunarDays_[index];
2810 dateDay = Localization::GetInstance()->GetLunarDay(day);
2811 return dateDay;
2812 }
2813 return it->second; // index in [0,29]
2814 }
2815
GetText()2816 const std::string DatePickerPattern::GetText()
2817 {
2818 auto pickerDate = GetCurrentDate();
2819 std::string result = std::to_string(pickerDate.GetYear()) + "-" + std::to_string(pickerDate.GetMonth()) + "-" +
2820 std::to_string(pickerDate.GetDay());
2821 return result;
2822 }
2823
GetFormatString(PickerDateF date)2824 const std::string DatePickerPattern::GetFormatString(PickerDateF date)
2825 {
2826 if (date.year.has_value()) {
2827 return GetYear(date.year.value());
2828 }
2829
2830 std::string monthStr;
2831 if (date.month.has_value()) {
2832 monthStr = date.lunar ? GetLunarMonth(date.month.value(), date.leap) : GetSolarMonth(date.month.value());
2833 if (!date.day.has_value()) {
2834 return monthStr;
2835 }
2836 }
2837
2838 std::string dayStr;
2839 if (date.day.has_value()) {
2840 dayStr = date.lunar ? GetLunarDay(date.day.value()) : GetSolarDay(date.day.value());
2841 DateTimeSequence sequence;
2842 auto language = AceApplicationInfo::GetInstance().GetLanguage();
2843 OrderResult orderResult = sequence.GetDateOrder(language);
2844 if (language == "ug") {
2845 return date.month.has_value() ? (dayStr + "-" + monthStr) : dayStr;
2846 } else if (language == "en") {
2847 return date.month.has_value() ? (monthStr + " " + dayStr) : dayStr;
2848 } else {
2849 return date.month.has_value() ? (monthStr + dayStr) : dayStr;
2850 }
2851 }
2852
2853 return "";
2854 }
2855
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const2856 void DatePickerPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
2857 {
2858 /* no fixed attr below, just return */
2859 if (filter.IsFastFilter()) {
2860 return;
2861 }
2862 auto GetDateString = [](const PickerDate& pickerDate) {
2863 std::string ret;
2864 ret += std::to_string(pickerDate.GetYear());
2865 ret += "-";
2866 ret += std::to_string(pickerDate.GetMonth());
2867 ret += "-";
2868 ret += std::to_string(pickerDate.GetDay());
2869 return ret;
2870 };
2871 auto GetModeString = [](const DatePickerMode& datePickerMode) {
2872 std::string ret;
2873 if (datePickerMode == DatePickerMode::DATE) {
2874 ret = "DatePickerMode.DATE";
2875 } else if (datePickerMode == DatePickerMode::YEAR_AND_MONTH) {
2876 ret = "DatePickerMode.YEAR_AND_MONTH";
2877 } else if (datePickerMode == DatePickerMode::MONTH_AND_DAY) {
2878 ret = "DatePickerMode.MONTH_AND_DAY";
2879 }
2880 return ret;
2881 };
2882 auto rowLayoutProperty = GetLayoutProperty<DataPickerRowLayoutProperty>();
2883 CHECK_NULL_VOID(rowLayoutProperty);
2884 auto jsonConstructor = JsonUtil::Create(true);
2885 auto isLunar = rowLayoutProperty->GetLunarValue(false);
2886 if (isLunar) {
2887 jsonConstructor->Put("start", rowLayoutProperty->GetDateStart().c_str());
2888 jsonConstructor->Put("end", rowLayoutProperty->GetDateEnd().c_str());
2889 jsonConstructor->Put("selected", rowLayoutProperty->GetDateSelected().c_str());
2890 jsonConstructor->Put("mode", rowLayoutProperty->GetDatePickerMode().c_str());
2891 } else {
2892 jsonConstructor->Put("start", GetDateString(startDateSolar_).c_str());
2893 jsonConstructor->Put("end", GetDateString(endDateSolar_).c_str());
2894 jsonConstructor->Put("selected", GetDateString(selectedDate_).c_str());
2895 jsonConstructor->Put("mode", GetModeString(datePickerMode_).c_str());
2896 }
2897 json->PutExtAttr("constructor", jsonConstructor, filter);
2898 json->PutExtAttr("enableHapticFeedback", isEnableHaptic_, filter);
2899 }
2900
SetFocusDisable()2901 void DatePickerPattern::SetFocusDisable()
2902 {
2903 auto host = GetHost();
2904 CHECK_NULL_VOID(host);
2905
2906 auto focusHub = host->GetFocusHub();
2907 CHECK_NULL_VOID(focusHub);
2908
2909 isFocus_ = false;
2910 focusHub->SetFocusable(false);
2911 }
2912
SetFocusEnable()2913 void DatePickerPattern::SetFocusEnable()
2914 {
2915 auto host = GetHost();
2916 CHECK_NULL_VOID(host);
2917
2918 auto focusHub = host->GetFocusHub();
2919 CHECK_NULL_VOID(focusHub);
2920
2921 isFocus_ = true;
2922 focusHub->SetFocusable(true);
2923 }
2924
NeedAdaptForAging()2925 bool DatePickerPattern::NeedAdaptForAging()
2926 {
2927 auto host = GetHost();
2928 CHECK_NULL_RETURN(host, false);
2929 auto pipeline = host->GetContext();
2930 CHECK_NULL_RETURN(pipeline, false);
2931 auto pickerTheme = pipeline->GetTheme<PickerTheme>();
2932 CHECK_NULL_RETURN(pickerTheme, false);
2933
2934 if (GreatOrEqual(pipeline->GetFontScale(), pickerTheme->GetMaxOneFontScale()) &&
2935 GreatOrEqual(Dimension(pipeline->GetRootHeight()).ConvertToVp(), pickerTheme->GetDeviceHeightLimit())) {
2936 return true;
2937 }
2938 return false;
2939 }
2940
2941 #ifdef SUPPORT_DIGITAL_CROWN
InitOnCrownEvent(const RefPtr<FocusHub> & focusHub)2942 void DatePickerPattern::InitOnCrownEvent(const RefPtr<FocusHub>& focusHub)
2943 {
2944 CHECK_NULL_VOID(focusHub);
2945 auto onCrowEvent = [wp = WeakClaim(this)](const CrownEvent& event)->bool {
2946 auto pattern = wp.Upgrade();
2947 if (pattern) {
2948 return pattern->OnCrownEvent(event);
2949 }
2950 return false;
2951 };
2952
2953 focusHub->SetOnCrownEventInternal(std::move(onCrowEvent));
2954 }
2955
OnCrownEvent(const CrownEvent & event)2956 bool DatePickerPattern::OnCrownEvent(const CrownEvent& event)
2957 {
2958 if (event.action == OHOS::Ace::CrownAction::BEGIN ||
2959 event.action == OHOS::Ace::CrownAction::UPDATE ||
2960 event.action == OHOS::Ace::CrownAction::END) {
2961 RefPtr<DatePickerColumnPattern> crownPickerColumnPattern;
2962 for (auto& iter : datePickerColumns_) {
2963 auto column = iter.Upgrade();
2964 if (!column) {
2965 continue;
2966 }
2967 auto pickerColumnPattern = column->GetPattern<DatePickerColumnPattern>();
2968 if (!pickerColumnPattern) {
2969 continue;
2970 }
2971 auto columnID = pickerColumnPattern->GetSelectedColumnId();
2972 if (!pickerColumnPattern->IsCrownEventEnded()) {
2973 crownPickerColumnPattern = pickerColumnPattern;
2974 break;
2975 } else if (columnID == selectedColumnId_) {
2976 crownPickerColumnPattern = pickerColumnPattern;
2977 }
2978 }
2979 if (crownPickerColumnPattern) {
2980 return crownPickerColumnPattern->OnCrownEvent(event);
2981 }
2982 }
2983
2984 return false;
2985 }
2986 #endif
2987
IsCircle()2988 bool DatePickerPattern::IsCircle()
2989 {
2990 auto host = GetHost();
2991 CHECK_NULL_RETURN(host, false);
2992 auto context = host->GetContext();
2993 CHECK_NULL_RETURN(context, false);
2994 auto pickerTheme = context->GetTheme<PickerTheme>();
2995 CHECK_NULL_RETURN(pickerTheme, false);
2996
2997 return pickerTheme->IsCircleDial();
2998 }
2999
ClearFocus()3000 void DatePickerPattern::ClearFocus()
3001 {
3002 CHECK_EQUAL_VOID(IsCircle(), false);
3003 CHECK_EQUAL_VOID(isFirstTimeSetFocus_, true);
3004 CHECK_EQUAL_VOID(lastTimeIsLuanar_, CurrentIsLunar());
3005 if (!selectedColumnId_.empty()) {
3006 const auto& allChildNode = GetAllChildNode();
3007 auto it = allChildNode.find(selectedColumnId_);
3008 if (it != allChildNode.end()) {
3009 auto tmpPattern = it->second->GetPattern<DatePickerColumnPattern>();
3010 if (tmpPattern) {
3011 tmpPattern->SetSelectedMark(false, false);
3012 }
3013 }
3014 selectedColumnId_ = "";
3015 }
3016 }
3017
SetDefaultFocus()3018 void DatePickerPattern::SetDefaultFocus()
3019 {
3020 CHECK_EQUAL_VOID(IsCircle(), false);
3021 if (!isFirstTimeSetFocus_ && (lastTimeIsLuanar_ == CurrentIsLunar())) {
3022 return;
3023 }
3024 isFirstTimeSetFocus_ = false;
3025 lastTimeIsLuanar_ = CurrentIsLunar();
3026 std::function<void(std::string& focusId)> call = [weak = WeakClaim(this)](std::string& focusId) {
3027 auto pattern = weak.Upgrade();
3028 CHECK_NULL_VOID(pattern);
3029 if (pattern->selectedColumnId_.empty()) {
3030 pattern->selectedColumnId_ = focusId;
3031 return;
3032 }
3033 const auto& allChildNode = pattern->GetAllChildNode();
3034 auto it = allChildNode.find(pattern->selectedColumnId_);
3035 if (it != allChildNode.end()) {
3036 auto tmpPattern = it->second->GetPattern<DatePickerColumnPattern>();
3037 tmpPattern->SetSelectedMark(false, false);
3038 }
3039
3040 pattern->selectedColumnId_ = focusId;
3041 };
3042
3043 const auto& allChildNode = GetAllChildNode();
3044 static const std::string columnName[] = {"year", "month", "day"};
3045 bool setFocus = true;
3046 for (size_t i = 0; i < sizeof(columnName) / sizeof(columnName[0]); i++) {
3047 auto it = allChildNode.find(columnName[i]);
3048 if (it != allChildNode.end()) {
3049 auto tmpPattern = it->second->GetPattern<DatePickerColumnPattern>();
3050 CHECK_NULL_VOID(tmpPattern);
3051 tmpPattern->SetSelectedMarkId(columnName[i]);
3052 tmpPattern->SetSelectedMarkListener(call);
3053 if (setFocus) {
3054 selectedColumnId_ = columnName[i];
3055 }
3056 tmpPattern->SetSelectedMark(setFocus, false);
3057 setFocus = false;
3058 }
3059 }
3060 }
3061
SetDigitalCrownSensitivity(int32_t crownSensitivity)3062 void DatePickerPattern::SetDigitalCrownSensitivity(int32_t crownSensitivity)
3063 {
3064 #ifdef SUPPORT_DIGITAL_CROWN
3065 auto host = GetHost();
3066 CHECK_NULL_VOID(host);
3067 auto&& children = host->GetChildren();
3068 for (const auto& child : children) {
3069 auto stackNode = DynamicCast<FrameNode>(child);
3070 CHECK_NULL_VOID(stackNode);
3071 auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
3072 CHECK_NULL_VOID(blendNode);
3073 auto childNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
3074 CHECK_NULL_VOID(childNode);
3075 auto pickerColumnPattern = childNode->GetPattern<DatePickerColumnPattern>();
3076 CHECK_NULL_VOID(pickerColumnPattern);
3077 pickerColumnPattern->SetDigitalCrownSensitivity(crownSensitivity);
3078 }
3079 #endif
3080 }
3081
UpdateUserSetSelectColor()3082 void DatePickerPattern::UpdateUserSetSelectColor()
3083 {
3084 CHECK_EQUAL_VOID(IsCircle(), false);
3085 auto host = GetHost();
3086 CHECK_NULL_VOID(host);
3087 auto&& children = host->GetChildren();
3088 for (const auto& child : children) {
3089 auto stackNode = DynamicCast<FrameNode>(child);
3090 CHECK_NULL_VOID(stackNode);
3091 auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
3092 CHECK_NULL_VOID(blendNode);
3093 auto childNode = DynamicCast<FrameNode>(blendNode->GetLastChild());
3094 CHECK_NULL_VOID(childNode);
3095 auto pickerColumnPattern = childNode->GetPattern<DatePickerColumnPattern>();
3096 CHECK_NULL_VOID(pickerColumnPattern);
3097 pickerColumnPattern->UpdateUserSetSelectColor();
3098 }
3099 }
3100
CurrentIsLunar()3101 bool DatePickerPattern::CurrentIsLunar()
3102 {
3103 auto rowLayoutProperty = GetLayoutProperty<DataPickerRowLayoutProperty>();
3104 CHECK_NULL_RETURN(rowLayoutProperty, true);
3105 return rowLayoutProperty->GetLunarValue(false);
3106 }
3107
ConvertFontScaleValue(const Dimension & fontSizeValue)3108 Dimension DatePickerPattern::ConvertFontScaleValue(const Dimension& fontSizeValue)
3109 {
3110 auto host = GetHost();
3111 CHECK_NULL_RETURN(host, fontSizeValue);
3112 auto pipeline = host->GetContext();
3113 CHECK_NULL_RETURN(pipeline, fontSizeValue);
3114
3115 auto maxAppFontScale = pipeline->GetMaxAppFontScale();
3116 auto follow = pipeline->IsFollowSystem();
3117 float fontScale = pipeline->GetFontScale();
3118 if (NearZero(fontScale) || (fontSizeValue.Unit() == DimensionUnit::VP)) {
3119 return fontSizeValue;
3120 }
3121 if (GreatOrEqualCustomPrecision(fontScale, PICKER_MAXFONTSCALE) && follow) {
3122 fontScale = std::clamp(fontScale, 0.0f, maxAppFontScale);
3123 if (!NearZero(fontScale)) {
3124 return Dimension(fontSizeValue / fontScale);
3125 }
3126 }
3127 return fontSizeValue;
3128 }
3129
UpdateTextStyleCommon(const PickerTextStyle & textStyle,const TextStyle & defaultTextStyle,std::function<void (const Color &)> updateTextColorFunc,std::function<void (const Dimension &)> updateFontSizeFunc,std::function<void (const std::vector<std::string> &)> updateFontFamilyFunc)3130 void DatePickerPattern::UpdateTextStyleCommon(
3131 const PickerTextStyle& textStyle,
3132 const TextStyle& defaultTextStyle,
3133 std::function<void(const Color&)> updateTextColorFunc,
3134 std::function<void(const Dimension&)> updateFontSizeFunc,
3135 std::function<void(const std::vector<std::string>&)> updateFontFamilyFunc
3136 )
3137 {
3138 auto host = GetHost();
3139 CHECK_NULL_VOID(host);
3140 auto pickerProperty = GetLayoutProperty<DataPickerRowLayoutProperty>();
3141 CHECK_NULL_VOID(pickerProperty);
3142
3143 auto pipelineContext = host->GetContext();
3144 CHECK_NULL_VOID(pipelineContext);
3145
3146 if (pipelineContext->IsSystmColorChange()) {
3147 updateTextColorFunc(textStyle.textColor.value_or(defaultTextStyle.GetTextColor()));
3148
3149 Dimension fontSize = defaultTextStyle.GetFontSize();
3150 if (textStyle.fontSize.has_value() && textStyle.fontSize->IsValid()) {
3151 fontSize = textStyle.fontSize.value();
3152 }
3153 updateFontSizeFunc(ConvertFontScaleValue(fontSize));
3154
3155 updateFontFamilyFunc(textStyle.fontFamily.value_or(defaultTextStyle.GetFontFamilies()));
3156 }
3157
3158 if (host->GetRerenderable()) {
3159 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
3160 }
3161 }
3162
UpdateDisappearTextStyle(const PickerTextStyle & textStyle)3163 void DatePickerPattern::UpdateDisappearTextStyle(const PickerTextStyle& textStyle)
3164 {
3165 auto host = GetHost();
3166 CHECK_NULL_VOID(host);
3167 auto context = host->GetContext();
3168 CHECK_NULL_VOID(context);
3169 auto pickerTheme = context->GetTheme<PickerTheme>(host->GetThemeScopeId());
3170 CHECK_NULL_VOID(pickerTheme);
3171 auto defaultTextStyle = pickerTheme->GetDisappearOptionStyle();
3172 auto pickerProperty = GetLayoutProperty<DataPickerRowLayoutProperty>();
3173 CHECK_NULL_VOID(pickerProperty);
3174
3175 if (pickerProperty->GetDisappearColor().has_value()) {
3176 defaultTextStyle.SetTextColor(pickerProperty->GetDisappearColor().value());
3177 }
3178
3179 UpdateTextStyleCommon(
3180 textStyle,
3181 defaultTextStyle,
3182 [&](const Color& color) { pickerProperty->UpdateDisappearColor(color); },
3183 [&](const Dimension& fontSize) { pickerProperty->UpdateDisappearFontSize(fontSize); },
3184 [&](const std::vector<std::string>& fontFamily) { pickerProperty->UpdateDisappearFontFamily(fontFamily); }
3185 );
3186 }
3187
UpdateNormalTextStyle(const PickerTextStyle & textStyle)3188 void DatePickerPattern::UpdateNormalTextStyle(const PickerTextStyle& textStyle)
3189 {
3190 auto host = GetHost();
3191 CHECK_NULL_VOID(host);
3192 auto context = host->GetContext();
3193 CHECK_NULL_VOID(context);
3194 auto pickerTheme = context->GetTheme<PickerTheme>(host->GetThemeScopeId());
3195 CHECK_NULL_VOID(pickerTheme);
3196 auto defaultTextStyle = pickerTheme->GetOptionStyle(false, false);
3197 auto pickerProperty = GetLayoutProperty<DataPickerRowLayoutProperty>();
3198 CHECK_NULL_VOID(pickerProperty);
3199
3200 if (pickerProperty->GetColor().has_value()) {
3201 defaultTextStyle.SetTextColor(pickerProperty->GetColor().value());
3202 }
3203
3204 UpdateTextStyleCommon(
3205 textStyle,
3206 defaultTextStyle,
3207 [&](const Color& color) { pickerProperty->UpdateColor(color); },
3208 [&](const Dimension& fontSize) { pickerProperty->UpdateFontSize(fontSize); },
3209 [&](const std::vector<std::string>& fontFamily) { pickerProperty->UpdateFontFamily(fontFamily); }
3210 );
3211 }
3212
UpdateSelectedTextStyle(const PickerTextStyle & textStyle)3213 void DatePickerPattern::UpdateSelectedTextStyle(const PickerTextStyle& textStyle)
3214 {
3215 auto host = GetHost();
3216 CHECK_NULL_VOID(host);
3217 auto context = host->GetContext();
3218 CHECK_NULL_VOID(context);
3219 auto pickerTheme = context->GetTheme<PickerTheme>(host->GetThemeScopeId());
3220 CHECK_NULL_VOID(pickerTheme);
3221 auto defaultTextStyle = pickerTheme->GetOptionStyle(true, false);
3222 auto pickerProperty = GetLayoutProperty<DataPickerRowLayoutProperty>();
3223 CHECK_NULL_VOID(pickerProperty);
3224
3225 if (pickerProperty->GetSelectedColor().has_value()) {
3226 defaultTextStyle.SetTextColor(pickerProperty->GetSelectedColor().value());
3227 }
3228
3229 UpdateTextStyleCommon(
3230 textStyle,
3231 defaultTextStyle,
3232 [&](const Color& color) { pickerProperty->UpdateSelectedColor(color); },
3233 [&](const Dimension& fontSize) { pickerProperty->UpdateSelectedFontSize(fontSize); },
3234 [&](const std::vector<std::string>& fontFamily) { pickerProperty->UpdateSelectedFontFamily(fontFamily); }
3235 );
3236 }
3237
BeforeCreateLayoutWrapper()3238 void DatePickerPattern::BeforeCreateLayoutWrapper()
3239 {
3240 auto host = GetHost();
3241 CHECK_NULL_VOID(host);
3242 auto layoutProperty = host->GetLayoutProperty<DataPickerRowLayoutProperty>();
3243 CHECK_NULL_VOID(layoutProperty);
3244 auto layoutPolicy = layoutProperty->GetLayoutPolicyProperty();
3245 if (layoutPolicy.has_value() && (layoutPolicy->IsWrap() || layoutPolicy->IsFix())) {
3246 layoutProperty->UpdateUserDefinedIdealSize(
3247 CalcSize(CalcLength(DEFAULT_SIZE_ZERO), CalcLength(DEFAULT_SIZE_ZERO)));
3248 }
3249 }
3250
3251 } // namespace OHOS::Ace::NG
3252