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