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 <stdint.h>
19 #include <string>
20 #include <utility>
21 #include <vector>
22 
23 #include "base/i18n/date_time_sequence.h"
24 #include "base/memory/ace_type.h"
25 #include "base/utils/utils.h"
26 #include "core/components/picker/picker_base_component.h"
27 #include "core/components/theme/icon_theme.h"
28 #include "core/components_ng/base/frame_node.h"
29 #include "core/components_ng/base/inspector_filter.h"
30 #include "core/components_ng/event/click_event.h"
31 #include "core/components_ng/pattern/button/button_pattern.h"
32 #include "core/components_ng/pattern/image/image_layout_property.h"
33 #include "core/components_ng/pattern/picker/datepicker_column_pattern.h"
34 #include "core/components_v2/inspector/inspector_constants.h"
35 #include "core/pipeline/pipeline_base.h"
36 #include "core/pipeline_ng/ui_task_scheduler.h"
37 
38 namespace OHOS::Ace::NG {
39 namespace {
40 constexpr int32_t SINGLE_CHILD_SIZE = 1;
41 constexpr int32_t CHILD_SIZE = 3;
42 constexpr uint32_t MIN_MONTH = 1;
43 constexpr uint32_t MAX_MONTH = 12;
44 constexpr uint32_t MIN_DAY = 1;
45 const Dimension PRESS_INTERVAL = 4.0_vp;
46 const Dimension PRESS_RADIUS = 8.0_vp;
47 const int32_t UNOPTION_COUNT = 2;
48 const int32_t COLUMNS_SIZE = 3;
49 const int32_t COLUMNS_ZERO = 0;
50 const int32_t COLUMNS_ONE = 1;
51 const int32_t COLUMNS_TWO = 2;
52 const int32_t INDEX_YEAR = 0;
53 const int32_t INDEX_MONTH = 1;
54 const int32_t INDEX_DAY = 2;
55 constexpr float DISABLE_ALPHA = 0.6f;
56 const Dimension FOCUS_OFFSET = 2.0_vp;
57 const int32_t RATE = 2;
58 } // namespace
59 bool DatePickerPattern::inited_ = false;
60 const std::string DatePickerPattern::empty_;
61 const PickerDateF DatePickerPattern::emptyPickerDate_;
62 std::unordered_map<uint32_t, std::string> DatePickerPattern::years_;       // year from 1900 to 2100,count is 201
63 std::unordered_map<uint32_t, std::string> DatePickerPattern::solarMonths_; // solar month from 1 to 12,count is 12
64 std::unordered_map<uint32_t, std::string> DatePickerPattern::solarDays_;   // solar day from 1 to 31, count is 31
65 std::unordered_map<uint32_t, std::string> DatePickerPattern::lunarMonths_; // lunar month from 1 to 24, count is 24
66 std::unordered_map<uint32_t, std::string> DatePickerPattern::lunarDays_;   // lunar day from 1 to 30, count is 30
67 std::vector<std::string> DatePickerPattern::tagOrder_;    // order of year month day
68 std::vector<std::string> DatePickerPattern::localizedMonths_;
69 
OnAttachToFrameNode()70 void DatePickerPattern::OnAttachToFrameNode()
71 {
72     auto host = GetHost();
73     CHECK_NULL_VOID(host);
74     host->GetRenderContext()->SetClipToFrame(true);
75     host->GetRenderContext()->UpdateClipEdge(true);
76 }
77 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,const DirtySwapConfig & config)78 bool DatePickerPattern::OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config)
79 {
80     CHECK_NULL_RETURN(dirty, false);
81     auto host = GetHost();
82     CHECK_NULL_RETURN(host, false);
83     auto context = host->GetContext();
84     CHECK_NULL_RETURN(context, false);
85     auto pickerTheme = context->GetTheme<PickerTheme>();
86     CHECK_NULL_RETURN(pickerTheme, false);
87     auto children = host->GetChildren();
88     auto heigth = pickerTheme->GetDividerSpacing();
89     for (const auto& child : children) {
90         auto columnNode = DynamicCast<FrameNode>(child->GetLastChild()->GetLastChild());
91         auto width = columnNode->GetGeometryNode()->GetFrameSize().Width();
92         auto buttonNode = DynamicCast<FrameNode>(child->GetFirstChild());
93         auto buttonConfirmLayoutProperty = buttonNode->GetLayoutProperty<ButtonLayoutProperty>();
94         buttonConfirmLayoutProperty->UpdateMeasureType(MeasureType::MATCH_PARENT_MAIN_AXIS);
95         buttonConfirmLayoutProperty->UpdateType(ButtonType::NORMAL);
96         buttonConfirmLayoutProperty->UpdateBorderRadius(BorderRadiusProperty(PRESS_RADIUS));
97         buttonConfirmLayoutProperty->UpdateUserDefinedIdealSize(
98             CalcSize(CalcLength(width - PRESS_INTERVAL.ConvertToPx()), CalcLength(heigth - PRESS_INTERVAL)));
99         auto buttonConfirmRenderContext = buttonNode->GetRenderContext();
100         buttonConfirmRenderContext->UpdateBackgroundColor(Color::TRANSPARENT);
101         buttonNode->MarkModifyDone();
102         buttonNode->MarkDirtyNode();
103     }
104     return true;
105 }
106 
OnModifyDone()107 void DatePickerPattern::OnModifyDone()
108 {
109     auto host = GetHost();
110     CHECK_NULL_VOID(host);
111     auto datePickerRowLayoutProperty = host->GetLayoutProperty<DataPickerRowLayoutProperty>();
112     CHECK_NULL_VOID(datePickerRowLayoutProperty);
113     if (isFiredDateChange_ && !isForceUpdate_ && (lunar_ == datePickerRowLayoutProperty->GetLunar().value_or(false))) {
114         isFiredDateChange_ = false;
115         return;
116     }
117 
118     isForceUpdate_ = false;
119     InitDisabled();
120     if (ShowMonthDays()) {
121         FlushMonthDaysColumn();
122     } else {
123         FlushColumn();
124     }
125     ShowTitle(GetTitleId());
126     SetChangeCallback([weak = WeakClaim(this)](const RefPtr<FrameNode>& tag, bool add, uint32_t index, bool notify) {
127         auto refPtr = weak.Upgrade();
128         CHECK_NULL_VOID(refPtr);
129         refPtr->HandleColumnChange(tag, add, index, notify);
130     });
131     SetEventCallback([weak = WeakClaim(this), titleId = GetTitleId()](bool refresh) {
132         auto refPtr = weak.Upgrade();
133         CHECK_NULL_VOID(refPtr);
134         refPtr->FireChangeEvent(refresh);
135         if (refresh) {
136             refPtr->ShowTitle(titleId);
137         }
138     });
139     auto focusHub = host->GetFocusHub();
140     if (focusHub) {
141         InitOnKeyEvent(focusHub);
142     }
143 }
144 
InitDisabled()145 void DatePickerPattern::InitDisabled()
146 {
147     auto host = GetHost();
148     CHECK_NULL_VOID(host);
149     auto eventHub = host->GetEventHub<EventHub>();
150     CHECK_NULL_VOID(eventHub);
151     enabled_ = eventHub->IsEnabled();
152     auto renderContext = host->GetRenderContext();
153     CHECK_NULL_VOID(renderContext);
154     if (!enabled_) {
155         renderContext->UpdateOpacity(curOpacity_ * DISABLE_ALPHA);
156     }
157     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
158 }
159 
OnLanguageConfigurationUpdate()160 void DatePickerPattern::OnLanguageConfigurationUpdate()
161 {
162     auto buttonConfirmNode = weakButtonConfirm_.Upgrade();
163     CHECK_NULL_VOID(buttonConfirmNode);
164     auto confirmNode = AceType::DynamicCast<FrameNode>(buttonConfirmNode->GetFirstChild());
165     CHECK_NULL_VOID(confirmNode);
166     auto confirmNodeLayout = confirmNode->GetLayoutProperty<TextLayoutProperty>();
167     CHECK_NULL_VOID(confirmNodeLayout);
168     confirmNodeLayout->UpdateContent(Localization::GetInstance()->GetEntryLetters("common.ok"));
169     confirmNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
170 
171     auto buttonCancelNode = weakButtonCancel_.Upgrade();
172     CHECK_NULL_VOID(buttonCancelNode);
173     auto cancelNode = AceType::DynamicCast<FrameNode>(buttonCancelNode->GetFirstChild());
174     CHECK_NULL_VOID(cancelNode);
175     auto cancelNodeLayout = cancelNode->GetLayoutProperty<TextLayoutProperty>();
176     CHECK_NULL_VOID(cancelNodeLayout);
177     cancelNodeLayout->UpdateContent(Localization::GetInstance()->GetEntryLetters("common.cancel"));
178     cancelNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
179 
180     auto lunarSwitchNode = weakLunarSwitchText_.Upgrade();
181     CHECK_NULL_VOID(lunarSwitchNode);
182     auto lunarSwitchTextLayoutProperty = lunarSwitchNode->GetLayoutProperty<TextLayoutProperty>();
183     CHECK_NULL_VOID(lunarSwitchTextLayoutProperty);
184     lunarSwitchTextLayoutProperty->UpdateContent(
185         Localization::GetInstance()->GetEntryLetters("datepicker.lunarSwitch"));
186     lunarSwitchNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
187 }
188 
HandleColumnChange(const RefPtr<FrameNode> & tag,bool isAdd,uint32_t index,bool needNotify)189 void DatePickerPattern::HandleColumnChange(const RefPtr<FrameNode>& tag, bool isAdd, uint32_t index, bool needNotify)
190 {
191     CHECK_NULL_VOID(GetHost());
192     std::vector<RefPtr<FrameNode>> tags;
193     if (ShowMonthDays()) {
194         HandleMonthDaysChange(tag, isAdd, index, tags);
195     } else {
196         OnDataLinking(tag, isAdd, index, tags);
197     }
198     for (const auto& tag : tags) {
199         auto iter = std::find_if(datePickerColumns_.begin(), datePickerColumns_.end(), [&tag](const auto& c) {
200             auto column = c.Upgrade();
201             return column && column->GetId() == tag->GetId();
202         });
203         if (iter != datePickerColumns_.end()) {
204             auto datePickerColumn = (*iter).Upgrade();
205             CHECK_NULL_VOID(datePickerColumn);
206             auto datePickerColumnPattern = datePickerColumn->GetPattern<DatePickerColumnPattern>();
207             CHECK_NULL_VOID(datePickerColumnPattern);
208             datePickerColumnPattern->FlushCurrentOptions(isAdd, true, false);
209         }
210     }
211 }
212 
SetEventCallback(EventCallback && value)213 void DatePickerPattern::SetEventCallback(EventCallback&& value)
214 {
215     auto host = GetHost();
216     CHECK_NULL_VOID(host);
217     auto children = host->GetChildren();
218     for (const auto& child : children) {
219         auto stackNode = DynamicCast<FrameNode>(child);
220         CHECK_NULL_VOID(stackNode);
221         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
222         CHECK_NULL_VOID(blendNode);
223         auto childNode = blendNode->GetLastChild();
224         CHECK_NULL_VOID(childNode);
225         auto datePickerColumnPattern = DynamicCast<FrameNode>(childNode)->GetPattern<DatePickerColumnPattern>();
226         CHECK_NULL_VOID(datePickerColumnPattern);
227         datePickerColumnPattern->SetEventCallback(std::move(value));
228     }
229 }
230 
SetChangeCallback(ColumnChangeCallback && value)231 void DatePickerPattern::SetChangeCallback(ColumnChangeCallback&& value)
232 {
233     auto host = GetHost();
234     CHECK_NULL_VOID(host);
235     auto children = host->GetChildren();
236     for (const auto& child : children) {
237         auto stackNode = DynamicCast<FrameNode>(child);
238         CHECK_NULL_VOID(stackNode);
239         auto blendNode = DynamicCast<FrameNode>(stackNode->GetLastChild());
240         CHECK_NULL_VOID(blendNode);
241         auto childNode = blendNode->GetLastChild();
242         CHECK_NULL_VOID(childNode);
243         auto datePickerColumnPattern = DynamicCast<FrameNode>(childNode)->GetPattern<DatePickerColumnPattern>();
244         CHECK_NULL_VOID(datePickerColumnPattern);
245         datePickerColumnPattern->SetChangeCallback(std::move(value));
246     }
247 }
248 
OnColorConfigurationUpdate()249 void DatePickerPattern::OnColorConfigurationUpdate()
250 {
251     auto host = GetHost();
252     CHECK_NULL_VOID(host);
253     host->SetNeedCallChildrenUpdate(false);
254     auto context = host->GetContext();
255     CHECK_NULL_VOID(context);
256     auto pickerTheme = context->GetTheme<PickerTheme>();
257     CHECK_NULL_VOID(pickerTheme);
258     auto dialogTheme = context->GetTheme<DialogTheme>();
259     CHECK_NULL_VOID(dialogTheme);
260     auto disappearStyle = pickerTheme->GetDisappearOptionStyle();
261     auto normalStyle = pickerTheme->GetOptionStyle(false, false);
262     auto pickerProperty = host->GetLayoutProperty<DataPickerRowLayoutProperty>();
263     CHECK_NULL_VOID(pickerProperty);
264     pickerProperty->UpdateColor(GetTextProperties().normalTextStyle_.textColor.value_or(normalStyle.GetTextColor()));
265     pickerProperty->UpdateDisappearColor(
266         GetTextProperties().disappearTextStyle_.textColor.value_or(disappearStyle.GetTextColor()));
267     if (isPicker_) {
268         return;
269     }
270     SetBackgroundColor(dialogTheme->GetBackgroundColor());
271     auto buttonTitleNode = buttonTitleNode_.Upgrade();
272     CHECK_NULL_VOID(buttonTitleNode);
273     auto titleLayoutRenderContext = buttonTitleNode->GetRenderContext();
274     CHECK_NULL_VOID(titleLayoutRenderContext);
275     if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN) ||
276         !titleLayoutRenderContext->IsUniRenderEnabled()) {
277         titleLayoutRenderContext->UpdateBackgroundColor(dialogTheme->GetButtonBackgroundColor());
278     }
279     UpdateTitleTextColor(buttonTitleNode, pickerTheme);
280     OnModifyDone();
281 }
282 
UpdateTitleTextColor(const RefPtr<FrameNode> & buttonTitleNode,const RefPtr<PickerTheme> & pickerTheme)283 void DatePickerPattern::UpdateTitleTextColor(
284     const RefPtr<FrameNode>& buttonTitleNode, const RefPtr<PickerTheme>& pickerTheme)
285 {
286     auto childButton = buttonTitleNode->GetFirstChild();
287     CHECK_NULL_VOID(childButton);
288     auto ButtonNode = DynamicCast<FrameNode>(childButton);
289     CHECK_NULL_VOID(ButtonNode);
290     auto buttonTitleRenderContext = ButtonNode->GetRenderContext();
291     CHECK_NULL_VOID(buttonTitleRenderContext);
292     buttonTitleRenderContext->UpdateBackgroundColor(Color::TRANSPARENT);
293     auto childColumn = ButtonNode->GetFirstChild();
294     CHECK_NULL_VOID(childColumn);
295     auto childText = childColumn->GetFirstChild();
296     CHECK_NULL_VOID(childText);
297     auto textTitleNode = DynamicCast<FrameNode>(childText);
298     CHECK_NULL_VOID(textTitleNode);
299     auto textLayoutProperty = textTitleNode->GetLayoutProperty<TextLayoutProperty>();
300     CHECK_NULL_VOID(textLayoutProperty);
301     textLayoutProperty->UpdateTextColor(pickerTheme->GetTitleStyle().GetTextColor());
302     if (childColumn->GetChildren().size() > 1) {
303         auto spinner = childColumn->GetLastChild();
304         CHECK_NULL_VOID(spinner);
305         auto spinnerNode = DynamicCast<FrameNode>(spinner);
306         CHECK_NULL_VOID(spinnerNode);
307         auto spinnerRenderProperty = spinnerNode->GetPaintProperty<ImageRenderProperty>();
308         CHECK_NULL_VOID(spinnerRenderProperty);
309         spinnerRenderProperty->UpdateSvgFillColor(pickerTheme->GetTitleStyle().GetTextColor());
310     }
311 }
312 
InitOnKeyEvent(const RefPtr<FocusHub> & focusHub)313 void DatePickerPattern::InitOnKeyEvent(const RefPtr<FocusHub>& focusHub)
314 {
315     auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
316         auto pattern = wp.Upgrade();
317         CHECK_NULL_RETURN(pattern, false);
318         return pattern->OnKeyEvent(event);
319     };
320     focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
321 
322     auto getInnerPaintRectCallback = [wp = WeakClaim(this)](RoundRect& paintRect) {
323         auto pattern = wp.Upgrade();
324         if (pattern) {
325             pattern->GetInnerFocusPaintRect(paintRect);
326         }
327     };
328     focusHub->SetInnerFocusPaintRectCallback(getInnerPaintRectCallback);
329 }
330 
PaintFocusState()331 void DatePickerPattern::PaintFocusState()
332 {
333     auto host = GetHost();
334     CHECK_NULL_VOID(host);
335 
336     RoundRect focusRect;
337     GetInnerFocusPaintRect(focusRect);
338 
339     auto focusHub = host->GetFocusHub();
340     CHECK_NULL_VOID(focusHub);
341     focusHub->PaintInnerFocusState(focusRect);
342 
343     host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
344 }
345 
GetInnerFocusPaintRect(RoundRect & paintRect)346 void DatePickerPattern::GetInnerFocusPaintRect(RoundRect& paintRect)
347 {
348     auto host = GetHost();
349     CHECK_NULL_VOID(host);
350     auto childSize = 1.0f;
351     if (!ShowMonthDays()) {
352         childSize = static_cast<float>(host->GetChildren().size());
353     }
354     auto stackChild = DynamicCast<FrameNode>(host->GetChildAtIndex(focusKeyID_));
355     CHECK_NULL_VOID(stackChild);
356     auto blendChild = DynamicCast<FrameNode>(stackChild->GetLastChild());
357     CHECK_NULL_VOID(blendChild);
358     auto pickerChild = DynamicCast<FrameNode>(blendChild->GetLastChild());
359     CHECK_NULL_VOID(pickerChild);
360     auto columnWidth = pickerChild->GetGeometryNode()->GetFrameSize().Width();
361     auto pipeline = PipelineBase::GetCurrentContext();
362     CHECK_NULL_VOID(pipeline);
363     auto pickerTheme = pipeline->GetTheme<PickerTheme>();
364     CHECK_NULL_VOID(pickerTheme);
365     auto frameWidth = host->GetGeometryNode()->GetFrameSize().Width();
366     auto dividerSpacing = pickerTheme->GetDividerSpacing().ConvertToPx();
367     auto pickerThemeWidth = dividerSpacing * RATE;
368 
369     auto centerX = (frameWidth / childSize - pickerThemeWidth) / RATE +
370                    pickerChild->GetGeometryNode()->GetFrameRect().Width() * focusKeyID_ +
371                    PRESS_INTERVAL.ConvertToPx() * RATE;
372     CHECK_NULL_VOID(host->GetGeometryNode());
373     auto centerY =
374         (host->GetGeometryNode()->GetFrameSize().Height() - dividerSpacing) / RATE + PRESS_INTERVAL.ConvertToPx();
375     float piantRectWidth = (dividerSpacing - PRESS_INTERVAL.ConvertToPx()) * RATE;
376     float piantRectHeight = dividerSpacing - PRESS_INTERVAL.ConvertToPx() * RATE;
377     if (piantRectWidth > columnWidth) {
378         piantRectWidth = columnWidth - FOCUS_OFFSET.ConvertToPx() * RATE;
379         centerX = focusKeyID_ * columnWidth + FOCUS_OFFSET.ConvertToPx();
380     }
381     paintRect.SetRect(RectF(centerX, centerY, piantRectWidth, piantRectHeight));
382     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_LEFT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
383         static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
384     paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_RIGHT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
385         static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
386     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_LEFT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
387         static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
388     paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_RIGHT_POS, static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()),
389         static_cast<RSScalar>(PRESS_RADIUS.ConvertToPx()));
390 }
391 
OnKeyEvent(const KeyEvent & event)392 bool DatePickerPattern::OnKeyEvent(const KeyEvent& event)
393 {
394     if (event.action != KeyAction::DOWN) {
395         return false;
396     }
397     if (event.code == KeyCode::KEY_DPAD_UP || event.code == KeyCode::KEY_DPAD_DOWN ||
398         event.code == KeyCode::KEY_DPAD_LEFT || event.code == KeyCode::KEY_DPAD_RIGHT ||
399         event.code == KeyCode::KEY_MOVE_HOME || event.code == KeyCode::KEY_MOVE_END) {
400         return HandleDirectionKey(event.code);
401     }
402     return false;
403 }
404 
HandleDirectionKey(KeyCode code)405 bool DatePickerPattern::HandleDirectionKey(KeyCode code)
406 {
407     auto host = GetHost();
408     CHECK_NULL_RETURN(host, false);
409 
410     auto stackChild = DynamicCast<FrameNode>(host->GetChildAtIndex(focusKeyID_));
411     auto pickerChild = DynamicCast<FrameNode>(stackChild->GetLastChild()->GetLastChild());
412     auto pattern = pickerChild->GetPattern<DatePickerColumnPattern>();
413     auto totalOptionCount = GetOptionCount(pickerChild);
414     if (totalOptionCount == 0) {
415         return false;
416     }
417     if (code == KeyCode::KEY_DPAD_UP) {
418         pattern->InnerHandleScroll(false, false);
419         return true;
420     }
421     if (code == KeyCode::KEY_DPAD_DOWN) {
422         pattern->InnerHandleScroll(true, false);
423         return true;
424     }
425     if (code == KeyCode::KEY_MOVE_HOME) {
426         pattern->SetCurrentIndex(1);
427         pattern->InnerHandleScroll(false, false);
428         return true;
429     }
430     if (code == KeyCode::KEY_MOVE_END) {
431         pattern->SetCurrentIndex(totalOptionCount - UNOPTION_COUNT);
432         pattern->InnerHandleScroll(true, false);
433         return true;
434     }
435     if (code == KeyCode::KEY_DPAD_LEFT) {
436         focusKeyID_ -= 1;
437         if (focusKeyID_ < 0) {
438             focusKeyID_ = 0;
439             return false;
440         }
441         PaintFocusState();
442         return true;
443     }
444     if (code == KeyCode::KEY_DPAD_RIGHT) {
445         focusKeyID_ += 1;
446         auto childSize = 1.0f;
447         if (!ShowMonthDays()) {
448             childSize = static_cast<float>(host->GetChildren().size());
449         }
450         if (focusKeyID_ > childSize - 1) {
451             focusKeyID_ = childSize - 1;
452             return false;
453         }
454         PaintFocusState();
455         return true;
456     }
457     return false;
458 }
459 
GetAllChildNode()460 std::unordered_map<std::string, RefPtr<FrameNode>> DatePickerPattern::GetAllChildNode()
461 {
462     std::unordered_map<std::string, RefPtr<FrameNode>> allChildNode;
463     RefPtr<FrameNode> stackYear;
464     RefPtr<FrameNode> stackMonth;
465     RefPtr<FrameNode> stackDay;
466     OrderAllChildNode(stackYear, stackMonth, stackDay);
467     CHECK_NULL_RETURN(stackYear, allChildNode);
468     CHECK_NULL_RETURN(stackMonth, allChildNode);
469     CHECK_NULL_RETURN(stackDay, allChildNode);
470     auto blendYear = DynamicCast<FrameNode>(stackYear->GetLastChild());
471     CHECK_NULL_RETURN(blendYear, allChildNode);
472     auto blendMonth = DynamicCast<FrameNode>(stackMonth->GetLastChild());
473     CHECK_NULL_RETURN(blendMonth, allChildNode);
474     auto blendDay = DynamicCast<FrameNode>(stackDay->GetLastChild());
475     CHECK_NULL_RETURN(blendDay, allChildNode);
476     auto yearNode = DynamicCast<FrameNode>(blendYear->GetLastChild());
477     CHECK_NULL_RETURN(yearNode, allChildNode);
478     auto monthNode = DynamicCast<FrameNode>(blendMonth->GetLastChild());
479     CHECK_NULL_RETURN(monthNode, allChildNode);
480     auto dayNode = DynamicCast<FrameNode>(blendDay->GetLastChild());
481     CHECK_NULL_RETURN(dayNode, allChildNode);
482     allChildNode["year"] = yearNode;
483     allChildNode["month"] = monthNode;
484     allChildNode["day"] = dayNode;
485     return allChildNode;
486 }
487 
OrderAllChildNode(RefPtr<FrameNode> & stackYear,RefPtr<FrameNode> & stackMonth,RefPtr<FrameNode> & stackDay)488 void DatePickerPattern::OrderAllChildNode(
489     RefPtr<FrameNode>& stackYear, RefPtr<FrameNode>& stackMonth, RefPtr<FrameNode>& stackDay)
490 {
491     auto host = GetHost();
492     CHECK_NULL_VOID(host);
493     auto children = host->GetChildren();
494     if (children.size() != CHILD_SIZE) {
495         return;
496     }
497 
498     auto processDateNode = [&children](RefPtr<UINode>& first, RefPtr<UINode>& second, RefPtr<UINode>& third) {
499         auto iter = children.begin();
500         first = *iter++;
501         CHECK_NULL_VOID(first);
502         second = *iter++;
503         CHECK_NULL_VOID(second);
504         third = *iter;
505         CHECK_NULL_VOID(third);
506     };
507 
508     RefPtr<UINode> year;
509     RefPtr<UINode> month;
510     RefPtr<UINode> day;
511     if (dateOrder_ == "M-d-y") {
512         processDateNode(month, day, year);
513     } else if (dateOrder_ == "y-d-M") {
514         processDateNode(year, day, month);
515     } else {
516         processDateNode(year, month, day);
517     }
518     stackYear = DynamicCast<FrameNode>(year);
519     stackMonth = DynamicCast<FrameNode>(month);
520     stackDay = DynamicCast<FrameNode>(day);
521 }
522 
FlushColumn()523 void DatePickerPattern::FlushColumn()
524 {
525     auto host = GetHost();
526     CHECK_NULL_VOID(host);
527     auto allChildNode = GetAllChildNode();
528 
529     auto dataPickerRowLayoutProperty = host->GetLayoutProperty<DataPickerRowLayoutProperty>();
530     CHECK_NULL_VOID(dataPickerRowLayoutProperty);
531     auto lunarDate = dataPickerRowLayoutProperty->GetSelectedDate().value_or(SolarToLunar(GetSelectedDate()));
532     AdjustLunarDate(lunarDate);
533     std::string language = Localization::GetInstance()->GetLanguage();
534     if (dataPickerRowLayoutProperty->GetLunar().value_or(false) && (strcmp(language.c_str(), "zh") == 0)) {
535         LunarColumnsBuilding(lunarDate);
536     } else {
537         SolarColumnsBuilding(LunarToSolar(lunarDate));
538     }
539 
540     auto yearNode = allChildNode["year"];
541     auto monthNode = allChildNode["month"];
542     auto dayNode = allChildNode["day"];
543     CHECK_NULL_VOID(yearNode);
544     CHECK_NULL_VOID(monthNode);
545     CHECK_NULL_VOID(dayNode);
546     auto yearColumnPattern = yearNode->GetPattern<DatePickerColumnPattern>();
547     CHECK_NULL_VOID(yearColumnPattern);
548     auto monthColumnPattern = monthNode->GetPattern<DatePickerColumnPattern>();
549     CHECK_NULL_VOID(monthColumnPattern);
550     auto dayColumnPattern = dayNode->GetPattern<DatePickerColumnPattern>();
551     CHECK_NULL_VOID(dayColumnPattern);
552 
553     yearColumnPattern->SetShowCount(GetShowCount());
554     monthColumnPattern->SetShowCount(GetShowCount());
555     dayColumnPattern->SetShowCount(GetShowCount());
556     yearColumnPattern->FlushCurrentOptions();
557     monthColumnPattern->FlushCurrentOptions();
558     dayColumnPattern->FlushCurrentOptions();
559 }
560 
FlushMonthDaysColumn()561 void DatePickerPattern::FlushMonthDaysColumn()
562 {
563     auto host = GetHost();
564     CHECK_NULL_VOID(host);
565 
566     auto children = host->GetChildren();
567     if (children.size() <= SINGLE_CHILD_SIZE) {
568         return;
569     }
570     auto iter = children.begin();
571     auto monthDays = (*iter);
572     CHECK_NULL_VOID(monthDays);
573     iter++;
574     auto year = *iter;
575     CHECK_NULL_VOID(year);
576     auto stackMonthDays = DynamicCast<FrameNode>(monthDays);
577     auto blendMonthDays = DynamicCast<FrameNode>(stackMonthDays->GetLastChild());
578     CHECK_NULL_VOID(blendMonthDays);
579     auto monthDaysNode = DynamicCast<FrameNode>(blendMonthDays->GetLastChild());
580     auto stackYear = DynamicCast<FrameNode>(year);
581     auto blendYear = DynamicCast<FrameNode>(stackYear->GetLastChild());
582     CHECK_NULL_VOID(blendYear);
583     auto yearDaysNode = DynamicCast<FrameNode>(blendYear->GetLastChild());
584     CHECK_NULL_VOID(monthDaysNode);
585     CHECK_NULL_VOID(yearDaysNode);
586     auto dataPickerRowLayoutProperty = host->GetLayoutProperty<DataPickerRowLayoutProperty>();
587     CHECK_NULL_VOID(dataPickerRowLayoutProperty);
588     std::string language = Localization::GetInstance()->GetLanguage();
589     if (dataPickerRowLayoutProperty->GetLunar().value_or(false) && (strcmp(language.c_str(), "zh") == 0)) {
590         LunarMonthDaysColumnBuilding(
591             dataPickerRowLayoutProperty->GetSelectedDate().value_or(SolarToLunar(GetSelectedDate())));
592     } else {
593         SolarMonthDaysColumnsBuilding(
594             LunarToSolar(dataPickerRowLayoutProperty->GetSelectedDate().value_or(SolarToLunar(GetSelectedDate()))));
595     }
596 
597     auto monthDaysColumnPattern = monthDaysNode->GetPattern<DatePickerColumnPattern>();
598     auto yearColumnPattern = yearDaysNode->GetPattern<DatePickerColumnPattern>();
599     CHECK_NULL_VOID(monthDaysColumnPattern);
600     CHECK_NULL_VOID(yearColumnPattern);
601 
602     monthDaysColumnPattern->SetShowCount(GetShowCount());
603     yearColumnPattern->SetShowCount(GetShowCount());
604     monthDaysColumnPattern->FlushCurrentOptions();
605     yearColumnPattern->FlushCurrentOptions();
606 }
607 
FireChangeEvent(bool refresh)608 void DatePickerPattern::FireChangeEvent(bool refresh)
609 {
610     if (refresh) {
611         auto datePickerEventHub = GetEventHub<DatePickerEventHub>();
612         CHECK_NULL_VOID(datePickerEventHub);
613         auto str = GetSelectedObject(true);
614         auto info = std::make_shared<DatePickerChangeEvent>(str);
615         datePickerEventHub->FireChangeEvent(info.get());
616         datePickerEventHub->FireDialogChangeEvent(str);
617         firedDateStr_ = str;
618     }
619 }
620 
ShowTitle(int32_t titleId)621 void DatePickerPattern::ShowTitle(int32_t titleId)
622 {
623     if (HasTitleNode()) {
624         auto textTitleNode = FrameNode::GetOrCreateFrameNode(
625             V2::TEXT_ETS_TAG, titleId, []() { return AceType::MakeRefPtr<TextPattern>(); });
626         auto dateStr = GetCurrentDate();
627         CHECK_NULL_VOID(textTitleNode);
628         auto textLayoutProperty = textTitleNode->GetLayoutProperty<TextLayoutProperty>();
629         CHECK_NULL_VOID(textLayoutProperty);
630         textLayoutProperty->UpdateContent(dateStr.ToString(false));
631         textTitleNode->MarkModifyDone();
632         textTitleNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
633     }
634 }
635 
OnDataLinking(const RefPtr<FrameNode> & tag,bool isAdd,uint32_t index,std::vector<RefPtr<FrameNode>> & resultTags)636 void DatePickerPattern::OnDataLinking(
637     const RefPtr<FrameNode>& tag, bool isAdd, uint32_t index, std::vector<RefPtr<FrameNode>>& resultTags)
638 {
639     auto allChildNode = GetAllChildNode();
640     auto yearNode = allChildNode["year"];
641     auto monthNode = allChildNode["month"];
642     auto dayNode = allChildNode["day"];
643     CHECK_NULL_VOID(yearNode);
644     CHECK_NULL_VOID(monthNode);
645     CHECK_NULL_VOID(dayNode);
646     if (tag == yearNode) {
647         HandleYearChange(isAdd, index, resultTags);
648         return;
649     }
650 
651     if (tag == monthNode) {
652         HandleMonthChange(isAdd, index, resultTags);
653         return;
654     }
655 
656     if (tag == dayNode) {
657         HandleDayChange(isAdd, index, resultTags);
658         return;
659     }
660 }
661 
HandleMonthDaysChange(const RefPtr<FrameNode> & tag,bool isAdd,uint32_t index,std::vector<RefPtr<FrameNode>> & resultTags)662 void DatePickerPattern::HandleMonthDaysChange(
663     const RefPtr<FrameNode>& tag, bool isAdd, uint32_t index, std::vector<RefPtr<FrameNode>>& resultTags)
664 {
665     auto host = GetHost();
666     CHECK_NULL_VOID(host);
667 
668     auto children = host->GetChildren();
669     if (children.size() <= SINGLE_CHILD_SIZE) {
670         return;
671     }
672     auto iter = children.begin();
673     auto monthDays = (*iter);
674     CHECK_NULL_VOID(monthDays);
675 
676     auto stackMonthDays = DynamicCast<FrameNode>(monthDays);
677     auto blendMonthDays = DynamicCast<FrameNode>(stackMonthDays->GetLastChild());
678     CHECK_NULL_VOID(blendMonthDays);
679     auto monthDaysNode = DynamicCast<FrameNode>(blendMonthDays->GetLastChild());
680     if (tag != monthDaysNode) {
681         return;
682     }
683 
684     if (IsShowLunar()) {
685         HandleLunarMonthDaysChange(isAdd, index);
686     } else {
687         HandleSolarMonthDaysChange(isAdd, index);
688     }
689 
690     resultTags.emplace_back(monthDaysNode);
691 }
692 
GetSelectedObject(bool isColumnChange,int status) const693 std::string DatePickerPattern::GetSelectedObject(bool isColumnChange, int status) const
694 {
695     auto date = selectedDate_;
696     if (isColumnChange) {
697         date = GetCurrentDate();
698     }
699     // W3C's month is between 0 to 11, need to reduce one.
700     auto getMonth = date.GetMonth();
701     getMonth = getMonth > 0 ? getMonth - 1 : 0;
702     date.SetMonth(getMonth);
703 
704     auto dateTimeString = std::string("{\"year\":") + std::to_string(date.GetYear()) +
705                           ",\"month\":" + std::to_string(date.GetMonth()) + ",\"day\":" + std::to_string(date.GetDay());
706     auto pickTime = PickerTime::Current();
707     if (showTime_) {
708         auto host = GetHost();
709         CHECK_NULL_RETURN(host, date.ToString(true, status));
710         if (showMonthDays_) {
711             auto pickerRow = host->GetParent();
712             CHECK_NULL_RETURN(pickerRow, date.ToString(true, status));
713             auto timeNode = AceType::DynamicCast<FrameNode>(pickerRow->GetChildAtIndex(1));
714             CHECK_NULL_RETURN(timeNode, date.ToString(true, status));
715             auto timePickerPattern = timeNode->GetPattern<TimePickerRowPattern>();
716             CHECK_NULL_RETURN(timePickerPattern, date.ToString(true, status));
717             pickTime = timePickerPattern->GetCurrentTime();
718         } else {
719             auto pickerStack = host->GetParent();
720             CHECK_NULL_RETURN(pickerStack, date.ToString(true, status));
721             auto pickerRow = pickerStack->GetLastChild();
722             CHECK_NULL_RETURN(pickerRow, date.ToString(true, status));
723             auto timeNode = AceType::DynamicCast<FrameNode>(pickerRow->GetChildAtIndex(1));
724             CHECK_NULL_RETURN(timeNode, date.ToString(true, status));
725             auto timePickerPattern = timeNode->GetPattern<TimePickerRowPattern>();
726             CHECK_NULL_RETURN(timePickerPattern, date.ToString(true, status));
727             pickTime = timePickerPattern->GetCurrentTime();
728         }
729     }
730     dateTimeString += std::string(",\"hour\":") + std::to_string(pickTime.GetHour()) +
731                       ",\"minute\":" + std::to_string(pickTime.GetMinute()) + ",\"status\":" + std::to_string(status) +
732                       "}";
733     return dateTimeString;
734 }
735 
HandleDayChange(bool isAdd,uint32_t index,std::vector<RefPtr<FrameNode>> & resultTags)736 void DatePickerPattern::HandleDayChange(bool isAdd, uint32_t index, std::vector<RefPtr<FrameNode>>& resultTags)
737 {
738     auto allChildNode = GetAllChildNode();
739     auto yearNode = allChildNode["year"];
740     auto monthNode = allChildNode["month"];
741     auto dayNode = allChildNode["day"];
742     CHECK_NULL_VOID(yearNode);
743     CHECK_NULL_VOID(monthNode);
744     CHECK_NULL_VOID(dayNode);
745     if (IsShowLunar()) {
746         HandleLunarDayChange(isAdd, index);
747     } else {
748         HandleSolarDayChange(isAdd, index);
749     }
750     resultTags.emplace_back(yearNode);
751     resultTags.emplace_back(monthNode);
752     resultTags.emplace_back(dayNode);
753 }
754 
HandleSolarDayChange(bool isAdd,uint32_t index)755 void DatePickerPattern::HandleSolarDayChange(bool isAdd, uint32_t index)
756 {
757     auto allChildNode = GetAllChildNode();
758     auto yearNode = allChildNode["year"];
759     auto monthNode = allChildNode["month"];
760     auto dayNode = allChildNode["day"];
761 
762     CHECK_NULL_VOID(yearNode);
763     CHECK_NULL_VOID(monthNode);
764     CHECK_NULL_VOID(dayNode);
765     auto yearDatePickerColumnPattern = yearNode->GetPattern<DatePickerColumnPattern>();
766     auto monthDatePickerColumnPattern = monthNode->GetPattern<DatePickerColumnPattern>();
767     auto dayDatePickerColumnPattern = dayNode->GetPattern<DatePickerColumnPattern>();
768     CHECK_NULL_VOID(yearDatePickerColumnPattern);
769     CHECK_NULL_VOID(monthDatePickerColumnPattern);
770     CHECK_NULL_VOID(dayDatePickerColumnPattern);
771 
772     auto date = GetCurrentDate();
773     if (isAdd && index == 0) {
774         date.SetMonth(date.GetMonth() + 1);   // add to next month
775         if (date.GetMonth() > 12) {           // invalidate month, max month is 12
776             date.SetMonth(1);                 // first month is 1
777             date.SetYear(date.GetYear() + 1); // add to next year
778             if (date.GetYear() > endDateSolar_.GetYear()) {
779                 date.SetYear(startDateSolar_.GetYear());
780             }
781         }
782     }
783     auto getOptionCount = GetOptionCount(dayNode);
784     getOptionCount = getOptionCount > 0 ? getOptionCount - 1 : 0;
785     if (!isAdd &&
786         dayDatePickerColumnPattern->GetCurrentIndex() == getOptionCount) { // last index is count - 1
787         auto getMonth = date.GetMonth();
788         getMonth = getMonth > 0 ? getMonth - 1 : 0;
789         date.SetMonth(getMonth);                                             // reduce to previous month
790         if (date.GetMonth() == 0) {                                                     // min month is 1, invalidate
791             date.SetMonth(12);                                                          // set to be the last month
792             auto getYear = date.GetYear();
793             getYear = getYear > 0 ? getYear - 1 : 0;
794             date.SetYear(getYear);                                           // reduce to previous year
795             if (date.GetYear() < startDateSolar_.GetYear()) {
796                 date.SetYear(endDateSolar_.GetYear());
797             }
798         }
799         date.SetDay(PickerDate::GetMaxDay(date.GetYear(), date.GetMonth())); // reduce to previous month's last day
800     }
801     uint32_t maxDay = PickerDate::GetMaxDay(date.GetYear(), date.GetMonth());
802     if (date.GetDay() > maxDay) {
803         date.SetDay(maxDay);
804     }
805     AdjustSolarDate(date);
806     SolarColumnsBuilding(date);
807 }
808 
HandleLunarDayChange(bool isAdd,uint32_t index)809 void DatePickerPattern::HandleLunarDayChange(bool isAdd, uint32_t index)
810 {
811     if (isAdd) {
812         HandleAddLunarDayChange(index);
813     } else {
814         HandleReduceLunarDayChange(index);
815     }
816 }
817 
HandleReduceLunarDayChange(uint32_t index)818 void DatePickerPattern::HandleReduceLunarDayChange(uint32_t index)
819 {
820     auto allChildNode = GetAllChildNode();
821     auto yearNode = allChildNode["year"];
822     auto monthNode = allChildNode["month"];
823     auto dayNode = allChildNode["day"];
824 
825     CHECK_NULL_VOID(yearNode);
826     CHECK_NULL_VOID(monthNode);
827     CHECK_NULL_VOID(dayNode);
828 
829     auto yearDatePickerColumnPattern = yearNode->GetPattern<DatePickerColumnPattern>();
830     auto monthDatePickerColumnPattern = monthNode->GetPattern<DatePickerColumnPattern>();
831     auto dayDatePickerColumnPattern = dayNode->GetPattern<DatePickerColumnPattern>();
832 
833     uint32_t nowLunarYear = startDateLunar_.year + yearDatePickerColumnPattern->GetCurrentIndex();
834     auto lunarDate = GetCurrentLunarDate(nowLunarYear);
835     uint32_t lunarLeapMonth = 0;
836     bool hasLeapMonth = GetLunarLeapMonth(lunarDate.year, lunarLeapMonth);
837     auto getOptionCount = GetOptionCount(dayNode);
838     getOptionCount = getOptionCount > 0 ? getOptionCount - 1 : 0;
839     if (dayDatePickerColumnPattern->GetCurrentIndex() == getOptionCount) { // max index is count - 1
840         if (monthDatePickerColumnPattern->GetCurrentIndex() == 0) {
841             lunarDate.year = lunarDate.year > 0 ? lunarDate.year - 1 : 0; // reduce to previous year
842             if (lunarDate.year < startDateLunar_.year) {
843                 lunarDate.year = endDateLunar_.year;
844             }
845             lunarDate.month = 12; // set to be previous year's max month
846             lunarDate.isLeapMonth = false;
847             if (LunarCalculator::GetLunarLeapMonth(lunarDate.year) == 12) { // leap 12th month
848                 lunarDate.isLeapMonth = true;
849             }
850             lunarDate.day = GetLunarMaxDay(lunarDate.year, lunarDate.month, lunarDate.isLeapMonth);
851         } else {
852             if (lunarDate.isLeapMonth) {
853                 lunarDate.isLeapMonth = false;
854             } else if (!hasLeapMonth) {
855                 lunarDate.month = lunarDate.month - 1;          // reduce to previous month
856             } else if (lunarLeapMonth == lunarDate.month - 1) { // leap month is previous month
857                 lunarDate.isLeapMonth = true;
858                 lunarDate.month = lunarLeapMonth;
859             } else {
860                 lunarDate.month = lunarDate.month - 1; // reduce to previous month
861             }
862             lunarDate.day = GetLunarMaxDay(lunarDate.year, lunarDate.month, lunarDate.isLeapMonth);
863         }
864     }
865 
866     AdjustLunarDate(lunarDate);
867     LunarColumnsBuilding(lunarDate);
868 }
869 
HandleAddLunarDayChange(uint32_t index)870 void DatePickerPattern::HandleAddLunarDayChange(uint32_t index)
871 {
872     auto allChildNode = GetAllChildNode();
873     auto yearNode = allChildNode["year"];
874     auto monthNode = allChildNode["month"];
875     auto dayNode = allChildNode["day"];
876 
877     CHECK_NULL_VOID(yearNode);
878     CHECK_NULL_VOID(monthNode);
879     CHECK_NULL_VOID(dayNode);
880 
881     auto yearDatePickerColumnPattern = yearNode->GetPattern<DatePickerColumnPattern>();
882     auto monthDatePickerColumnPattern = monthNode->GetPattern<DatePickerColumnPattern>();
883     auto dayDatePickerColumnPattern = dayNode->GetPattern<DatePickerColumnPattern>();
884 
885     uint32_t nowLunarYear = startDateLunar_.year + yearDatePickerColumnPattern->GetCurrentIndex();
886     auto lunarDate = GetCurrentLunarDate(nowLunarYear);
887     uint32_t lunarLeapMonth = 0;
888     bool hasLeapMonth = GetLunarLeapMonth(lunarDate.year, lunarLeapMonth);
889     if (index == 0) {
890         auto getOptionCount = GetOptionCount(monthNode);
891         getOptionCount = getOptionCount > 0 ? getOptionCount - 1 : 0;
892         if (monthDatePickerColumnPattern->GetCurrentIndex() == getOptionCount) {     // max index is count - 1
893             lunarDate.year = lunarDate.year + 1; // add to next year
894             if (lunarDate.year > endDateLunar_.year) {
895                 lunarDate.year = startDateLunar_.year;
896             }
897             lunarDate.month = 1; // first month
898             lunarDate.isLeapMonth = false;
899         } else {
900             if (lunarDate.isLeapMonth) {
901                 lunarDate.month = lunarDate.month + 1; // add to next month
902                 lunarDate.isLeapMonth = false;
903             } else if (!hasLeapMonth) {
904                 lunarDate.month = lunarDate.month + 1; // add to next month
905             } else if (lunarLeapMonth == lunarDate.month) {
906                 lunarDate.isLeapMonth = true;
907             } else {
908                 lunarDate.month = lunarDate.month + 1; // add to next month
909             }
910         }
911     }
912 
913     AdjustLunarDate(lunarDate);
914     LunarColumnsBuilding(lunarDate);
915 }
916 
HandleSolarMonthDaysChange(bool isAdd,uint32_t index)917 void DatePickerPattern::HandleSolarMonthDaysChange(bool isAdd, uint32_t index)
918 {
919     auto host = GetHost();
920     CHECK_NULL_VOID(host);
921 
922     auto children = host->GetChildren();
923     if (children.size() <= SINGLE_CHILD_SIZE) {
924         return;
925     }
926     auto iter = children.begin();
927     auto monthDays = (*iter);
928     CHECK_NULL_VOID(monthDays);
929     auto stackMonthDays = DynamicCast<FrameNode>(monthDays);
930     CHECK_NULL_VOID(stackMonthDays);
931     auto blendMonthDays = DynamicCast<FrameNode>(stackMonthDays->GetLastChild());
932     CHECK_NULL_VOID(blendMonthDays);
933     auto monthDaysNode = DynamicCast<FrameNode>(blendMonthDays->GetLastChild());
934     CHECK_NULL_VOID(monthDaysNode);
935     auto monthDaysDatePickerColumnPattern = monthDaysNode->GetPattern<DatePickerColumnPattern>();
936     CHECK_NULL_VOID(monthDaysDatePickerColumnPattern);
937 
938     auto date = GetCurrentDate();
939 
940     if (isAdd && index == 0) {
941         // add to next year
942         date.SetYear(date.GetYear() + 1); // add to next year
943         if (date.GetYear() > endDateSolar_.GetYear()) {
944             date.SetYear(startDateSolar_.GetYear());
945         }
946     }
947     auto getOptionCount = GetOptionCount(monthDaysNode);
948     getOptionCount = getOptionCount > 0 ? getOptionCount - 1 : 0;
949     if (!isAdd && monthDaysDatePickerColumnPattern->GetCurrentIndex() == getOptionCount) {
950         // reduce to previous year
951         auto getYear = date.GetYear();
952         getYear = getYear > 0 ? getYear - 1 : 0;
953         date.SetYear(getYear);
954         if (date.GetYear() < startDateSolar_.GetYear()) {
955             date.SetYear(endDateSolar_.GetYear());
956         }
957         // reduce to previous year's last day
958         date.SetMonth(MAX_MONTH);
959         date.SetDay(PickerDate::GetMaxDay(date.GetYear(), date.GetMonth()));
960     }
961     uint32_t maxDay = PickerDate::GetMaxDay(date.GetYear(), date.GetMonth());
962     if (date.GetDay() > maxDay) {
963         date.SetDay(maxDay);
964     }
965     AdjustSolarDate(date);
966     SolarMonthDaysColumnsBuilding(date);
967 }
968 
HandleLunarMonthDaysChange(bool isAdd,uint32_t index)969 void DatePickerPattern::HandleLunarMonthDaysChange(bool isAdd, uint32_t index)
970 {
971     if (isAdd) {
972         HandleAddLunarMonthDaysChange(index);
973     } else {
974         HandleReduceLunarMonthDaysChange(index);
975     }
976 }
977 
HandleAddLunarMonthDaysChange(uint32_t index)978 void DatePickerPattern::HandleAddLunarMonthDaysChange(uint32_t index)
979 {
980     auto host = GetHost();
981     CHECK_NULL_VOID(host);
982 
983     auto children = host->GetChildren();
984     if (children.size() <= SINGLE_CHILD_SIZE) {
985         return;
986     }
987     auto iter = children.begin();
988     auto monthDays = (*iter);
989     CHECK_NULL_VOID(monthDays);
990     iter++;
991     auto year = *iter;
992     CHECK_NULL_VOID(year);
993     auto stackMonthDays = DynamicCast<FrameNode>(monthDays);
994     auto blendMonthDays = DynamicCast<FrameNode>(stackMonthDays->GetLastChild());
995     CHECK_NULL_VOID(blendMonthDays);
996     auto monthDaysNode = DynamicCast<FrameNode>(blendMonthDays->GetLastChild());
997     auto stackYear = DynamicCast<FrameNode>(year);
998     auto blendYear = DynamicCast<FrameNode>(stackYear->GetLastChild());
999     CHECK_NULL_VOID(blendYear);
1000     auto yearDaysNode = DynamicCast<FrameNode>(blendYear->GetLastChild());
1001     CHECK_NULL_VOID(monthDaysNode);
1002     CHECK_NULL_VOID(yearDaysNode);
1003 
1004     auto monthDaysDatePickerColumnPattern = monthDaysNode->GetPattern<DatePickerColumnPattern>();
1005     auto yearDatePickerColumnPattern = yearDaysNode->GetPattern<DatePickerColumnPattern>();
1006 
1007     uint32_t nowLunarYear = startDateLunar_.year + yearDatePickerColumnPattern->GetCurrentIndex();
1008     auto lunarDate = GetCurrentLunarDateByMonthDaysColumn(nowLunarYear);
1009     if (index == 0) {
1010         lunarDate.year = lunarDate.year + 1; // add to next year
1011         if (lunarDate.year > endDateLunar_.year) {
1012             lunarDate.year = startDateLunar_.year;
1013         }
1014         lunarDate.month = 1;
1015         lunarDate.isLeapMonth = false;
1016     }
1017 
1018     AdjustLunarDate(lunarDate);
1019     LunarMonthDaysColumnBuilding(lunarDate);
1020 }
1021 
HandleReduceLunarMonthDaysChange(uint32_t index)1022 void DatePickerPattern::HandleReduceLunarMonthDaysChange(uint32_t index)
1023 {
1024     auto host = GetHost();
1025     CHECK_NULL_VOID(host);
1026 
1027     auto children = host->GetChildren();
1028     if (children.size() <= SINGLE_CHILD_SIZE) {
1029         return;
1030     }
1031     auto iter = children.begin();
1032     auto monthDays = (*iter);
1033     CHECK_NULL_VOID(monthDays);
1034     iter++;
1035     auto year = *iter;
1036     CHECK_NULL_VOID(year);
1037     auto stackMonthDays = DynamicCast<FrameNode>(monthDays);
1038     auto blendMonthDays = DynamicCast<FrameNode>(stackMonthDays->GetLastChild());
1039     CHECK_NULL_VOID(blendMonthDays);
1040     auto monthDaysNode = DynamicCast<FrameNode>(blendMonthDays->GetLastChild());
1041     auto stackYear = DynamicCast<FrameNode>(year);
1042     auto blendYear = DynamicCast<FrameNode>(stackYear->GetLastChild());
1043     CHECK_NULL_VOID(blendYear);
1044     auto yearDaysNode = DynamicCast<FrameNode>(blendYear->GetLastChild());
1045     CHECK_NULL_VOID(monthDaysNode);
1046     CHECK_NULL_VOID(yearDaysNode);
1047 
1048     auto monthDaysDatePickerColumnPattern = monthDaysNode->GetPattern<DatePickerColumnPattern>();
1049     auto yearDatePickerColumnPattern = yearDaysNode->GetPattern<DatePickerColumnPattern>();
1050     CHECK_NULL_VOID(monthDaysDatePickerColumnPattern);
1051     CHECK_NULL_VOID(yearDatePickerColumnPattern);
1052 
1053     uint32_t nowLunarYear = startDateLunar_.year + yearDatePickerColumnPattern->GetCurrentIndex();
1054     auto lunarDate = GetCurrentLunarDateByMonthDaysColumn(nowLunarYear);
1055     auto getOptionCount = GetOptionCount(monthDaysNode);
1056     getOptionCount = getOptionCount > 0 ? getOptionCount - 1 : 0;
1057     if (monthDaysDatePickerColumnPattern->GetCurrentIndex() == getOptionCount) {
1058         lunarDate.year = lunarDate.year > 0 ? lunarDate.year - 1 : 0; // reduce to previous year
1059         if (lunarDate.year < startDateLunar_.year) {
1060             lunarDate.year = endDateLunar_.year;
1061         }
1062         lunarDate.month = MAX_MONTH; // set to be previous year's max month
1063         lunarDate.isLeapMonth = false;
1064         if (LunarCalculator::GetLunarLeapMonth(lunarDate.year) == 12) { // leap 12th month
1065             lunarDate.isLeapMonth = true;
1066         }
1067         lunarDate.day = GetLunarMaxDay(lunarDate.year, lunarDate.month, lunarDate.isLeapMonth);
1068     }
1069 
1070     AdjustLunarDate(lunarDate);
1071     LunarMonthDaysColumnBuilding(lunarDate);
1072 }
1073 
HandleYearChange(bool isAdd,uint32_t index,std::vector<RefPtr<FrameNode>> & resultTags)1074 void DatePickerPattern::HandleYearChange(bool isAdd, uint32_t index, std::vector<RefPtr<FrameNode>>& resultTags)
1075 {
1076     auto allChildNode = GetAllChildNode();
1077     auto yearNode = allChildNode["year"];
1078     auto monthNode = allChildNode["month"];
1079     auto dayNode = allChildNode["day"];
1080 
1081     CHECK_NULL_VOID(yearNode);
1082     CHECK_NULL_VOID(monthNode);
1083     CHECK_NULL_VOID(dayNode);
1084     if (IsShowLunar()) {
1085         HandleLunarYearChange(isAdd, index);
1086     } else {
1087         HandleSolarYearChange(isAdd, index);
1088     }
1089     resultTags.emplace_back(yearNode);
1090     resultTags.emplace_back(monthNode);
1091     resultTags.emplace_back(dayNode);
1092 }
1093 
HandleMonthChange(bool isAdd,uint32_t index,std::vector<RefPtr<FrameNode>> & resultTags)1094 void DatePickerPattern::HandleMonthChange(bool isAdd, uint32_t index, std::vector<RefPtr<FrameNode>>& resultTags)
1095 {
1096     auto allChildNode = GetAllChildNode();
1097     auto yearNode = allChildNode["year"];
1098     auto monthNode = allChildNode["month"];
1099     auto dayNode = allChildNode["day"];
1100 
1101     CHECK_NULL_VOID(yearNode);
1102     CHECK_NULL_VOID(monthNode);
1103     CHECK_NULL_VOID(dayNode);
1104     if (IsShowLunar()) {
1105         HandleLunarMonthChange(isAdd, index);
1106     } else {
1107         HandleSolarMonthChange(isAdd, index);
1108     }
1109     resultTags.emplace_back(yearNode);
1110     resultTags.emplace_back(monthNode);
1111     resultTags.emplace_back(dayNode);
1112 }
1113 
HandleSolarMonthChange(bool isAdd,uint32_t index)1114 void DatePickerPattern::HandleSolarMonthChange(bool isAdd, uint32_t index)
1115 {
1116     auto date = GetCurrentDate();
1117     if (isAdd && date.GetMonth() == 1) {  // first month is 1
1118         date.SetYear(date.GetYear() + 1); // add 1 year, the next year
1119         if (date.GetYear() > endDateSolar_.GetYear()) {
1120             date.SetYear(startDateSolar_.GetYear());
1121         }
1122     }
1123     if (!isAdd && date.GetMonth() == 12) { // the last month is 12
1124         auto getYear = date.GetYear();
1125         getYear = getYear > 0 ? getYear - 1 : 0;
1126         date.SetYear(getYear);  // reduce 1 year, the previous year
1127         if (date.GetYear() < startDateSolar_.GetYear()) {
1128             date.SetYear(endDateSolar_.GetYear());
1129         }
1130     }
1131     uint32_t maxDay = PickerDate::GetMaxDay(date.GetYear(), date.GetMonth());
1132     if (date.GetDay() > maxDay) {
1133         date.SetDay(maxDay);
1134     }
1135     AdjustSolarDate(date);
1136     SolarColumnsBuilding(date);
1137 }
1138 
HandleLunarMonthChange(bool isAdd,uint32_t index)1139 void DatePickerPattern::HandleLunarMonthChange(bool isAdd, uint32_t index)
1140 {
1141     auto allChildNode = GetAllChildNode();
1142     auto yearNode = allChildNode["year"];
1143     auto monthNode = allChildNode["month"];
1144     auto dayNode = allChildNode["day"];
1145 
1146     CHECK_NULL_VOID(yearNode);
1147     CHECK_NULL_VOID(monthNode);
1148     CHECK_NULL_VOID(dayNode);
1149 
1150     auto yearColumn = yearNode->GetPattern<DatePickerColumnPattern>();
1151     CHECK_NULL_VOID(yearColumn);
1152     uint32_t nowLunarYear = startDateLunar_.year + yearColumn->GetCurrentIndex();
1153     auto lunarDate = GetCurrentLunarDate(nowLunarYear);
1154     if (isAdd && index == 0) {
1155         lunarDate.year = lunarDate.year + 1; // add to next year
1156         if (lunarDate.year > endDateLunar_.year) {
1157             lunarDate.year = startDateLunar_.year;
1158         }
1159     }
1160     auto getOptionCount = GetOptionCount(monthNode);
1161     getOptionCount = getOptionCount > 0 ? getOptionCount - 1 : 0;
1162     if (!isAdd && index == getOptionCount) {
1163         lunarDate.year = lunarDate.year > 0 ? lunarDate.year - 1 : 0; // reduce to previous year
1164         if (lunarDate.year < startDateLunar_.year) {
1165             lunarDate.year = endDateLunar_.year;
1166         }
1167     }
1168     uint32_t lunarLeapMonth = 0;
1169     bool hasLeapMonth = GetLunarLeapMonth(lunarDate.year, lunarLeapMonth);
1170     if (!hasLeapMonth && lunarDate.isLeapMonth) {
1171         lunarDate.isLeapMonth = false;
1172     }
1173     uint32_t maxDay = GetLunarMaxDay(lunarDate.year, lunarDate.month, lunarDate.isLeapMonth);
1174     if (lunarDate.day > maxDay) {
1175         lunarDate.day = maxDay;
1176     }
1177 
1178     AdjustLunarDate(lunarDate);
1179     LunarColumnsBuilding(lunarDate);
1180 }
1181 
HandleLunarYearChange(bool isAdd,uint32_t index)1182 void DatePickerPattern::HandleLunarYearChange(bool isAdd, uint32_t index)
1183 {
1184     auto allChildNode = GetAllChildNode();
1185     auto yearNode = allChildNode["year"];
1186     CHECK_NULL_VOID(yearNode);
1187     auto yearColumn = DynamicCast<FrameNode>(yearNode);
1188     uint32_t lastYearIndex = index;
1189     auto optionCount = GetOptionCount(yearColumn);
1190     if (isAdd) { // need reduce one index
1191         auto countAndIndex = optionCount + lastYearIndex;
1192         countAndIndex = countAndIndex > 0 ? countAndIndex - 1 : 0;
1193         lastYearIndex = optionCount != 0 ? countAndIndex % optionCount : 0;
1194     } else { // need add one index
1195         lastYearIndex = optionCount != 0 ? (GetOptionCount(yearColumn) + lastYearIndex + 1) % optionCount : 0;
1196     }
1197     uint32_t lastLunarYear = startDateLunar_.year + lastYearIndex;
1198     auto lunarDate = GetCurrentLunarDate(lastLunarYear);
1199     uint32_t nowLeapMonth = 0;
1200     bool hasLeapMonth = GetLunarLeapMonth(lunarDate.year, nowLeapMonth);
1201     if (!hasLeapMonth && lunarDate.isLeapMonth) {
1202         lunarDate.isLeapMonth = false;
1203     }
1204     uint32_t nowMaxDay = GetLunarMaxDay(lunarDate.year, lunarDate.month, lunarDate.isLeapMonth);
1205     if (lunarDate.day > nowMaxDay) {
1206         lunarDate.day = nowMaxDay;
1207     }
1208 
1209     AdjustLunarDate(lunarDate);
1210     LunarColumnsBuilding(lunarDate);
1211 }
1212 
GetCurrentLunarDate(uint32_t lunarYear) const1213 LunarDate DatePickerPattern::GetCurrentLunarDate(uint32_t lunarYear) const
1214 {
1215     LunarDate lunarResult;
1216     RefPtr<FrameNode> stackYear;
1217     RefPtr<FrameNode> stackMonth;
1218     RefPtr<FrameNode> stackDay;
1219     OrderCurrentLunarDate(stackYear, stackMonth, stackDay);
1220     CHECK_NULL_RETURN(stackYear, lunarResult);
1221     CHECK_NULL_RETURN(stackMonth, lunarResult);
1222     CHECK_NULL_RETURN(stackDay, lunarResult);
1223     auto yearColumn = DynamicCast<FrameNode>(stackYear->GetLastChild()->GetLastChild());
1224     CHECK_NULL_RETURN(yearColumn, lunarResult);
1225     auto monthColumn = DynamicCast<FrameNode>(stackMonth->GetLastChild()->GetLastChild());
1226     CHECK_NULL_RETURN(monthColumn, lunarResult);
1227     auto dayColumn = DynamicCast<FrameNode>(stackDay->GetLastChild()->GetLastChild());
1228     CHECK_NULL_RETURN(dayColumn, lunarResult);
1229     auto yearDatePickerColumnPattern = yearColumn->GetPattern<DatePickerColumnPattern>();
1230     CHECK_NULL_RETURN(yearDatePickerColumnPattern, lunarResult);
1231     auto monthDatePickerColumnPattern = monthColumn->GetPattern<DatePickerColumnPattern>();
1232     CHECK_NULL_RETURN(monthDatePickerColumnPattern, lunarResult);
1233     auto dayDatePickerColumnPattern = dayColumn->GetPattern<DatePickerColumnPattern>();
1234     CHECK_NULL_RETURN(dayDatePickerColumnPattern, lunarResult);
1235     uint32_t lunarLeapMonth = 0;
1236     bool hasLeapMonth = GetLunarLeapMonth(lunarYear, lunarLeapMonth);
1237     lunarResult.isLeapMonth = false;
1238     if (!hasLeapMonth) {
1239         lunarResult.month =
1240             monthDatePickerColumnPattern->GetCurrentIndex() + 1; // month from 1 to 12, index from 0 to 11
1241     } else {
1242         if (monthDatePickerColumnPattern->GetCurrentIndex() == lunarLeapMonth) {
1243             lunarResult.isLeapMonth = true;
1244             lunarResult.month = lunarLeapMonth;
1245         } else if (monthDatePickerColumnPattern->GetCurrentIndex() < lunarLeapMonth) {
1246             lunarResult.month =
1247                 monthDatePickerColumnPattern->GetCurrentIndex() + 1; // month start from 1, index start from 0
1248         } else {
1249             lunarResult.month = monthDatePickerColumnPattern->GetCurrentIndex();
1250         }
1251     }
1252     lunarResult.year = startDateLunar_.year + yearDatePickerColumnPattern->GetCurrentIndex();
1253     lunarResult.day = dayDatePickerColumnPattern->GetCurrentIndex() + 1; // day start form 1, index start from 0
1254     return lunarResult;
1255 }
1256 
OrderCurrentLunarDate(RefPtr<FrameNode> & stackYear,RefPtr<FrameNode> & stackMonth,RefPtr<FrameNode> & stackDay) const1257 void DatePickerPattern::OrderCurrentLunarDate(
1258     RefPtr<FrameNode>& stackYear, RefPtr<FrameNode>& stackMonth, RefPtr<FrameNode>& stackDay) const
1259 {
1260     auto host = GetHost();
1261     CHECK_NULL_VOID(host);
1262     auto children = host->GetChildren();
1263     auto processDateNode = [&children](RefPtr<UINode>& first, RefPtr<UINode>& second, RefPtr<UINode>& third) {
1264         auto iter = children.begin();
1265         first = *iter++;
1266         CHECK_NULL_VOID(first);
1267         second = *iter++;
1268         CHECK_NULL_VOID(second);
1269         third = *iter;
1270         CHECK_NULL_VOID(third);
1271     };
1272     RefPtr<UINode> year;
1273     RefPtr<UINode> month;
1274     RefPtr<UINode> day;
1275     if (dateOrder_ == "M-d-y") {
1276         processDateNode(month, day, year);
1277     } else if (dateOrder_ == "y-d-M") {
1278         processDateNode(year, day, month);
1279     } else {
1280         processDateNode(year, month, day);
1281     }
1282     stackYear = DynamicCast<FrameNode>(year);
1283     stackMonth = DynamicCast<FrameNode>(month);
1284     stackDay = DynamicCast<FrameNode>(day);
1285 }
1286 
HandleSolarYearChange(bool isAdd,uint32_t index)1287 void DatePickerPattern::HandleSolarYearChange(bool isAdd, uint32_t index)
1288 {
1289     auto date = GetCurrentDate();
1290     bool leapYear = PickerDate::IsLeapYear(date.GetYear());
1291     if (date.GetMonth() == 2 && !leapYear && date.GetDay() > 28) { // invalidate of 2th month
1292         date.SetDay(28); // the max day of the 2th month of none leap year is 28
1293     }
1294 
1295     AdjustSolarDate(date);
1296     SolarColumnsBuilding(date);
1297 }
1298 
GetCurrentDate() const1299 PickerDate DatePickerPattern::GetCurrentDate() const
1300 {
1301     if (ShowMonthDays()) {
1302         return GetCurrentDateByMonthDaysColumn();
1303     } else {
1304         return GetCurrentDateByYearMonthDayColumn();
1305     }
1306 }
1307 
GetCurrentDateByYearMonthDayColumn() const1308 PickerDate DatePickerPattern::GetCurrentDateByYearMonthDayColumn() const
1309 {
1310     PickerDate currentDate;
1311     RefPtr<FrameNode> stackYear;
1312     RefPtr<FrameNode> stackMonth;
1313     RefPtr<FrameNode> stackDay;
1314     OrderCurrentDateByYearMonthDayColumn(stackYear, stackMonth, stackDay);
1315     CHECK_NULL_RETURN(stackYear, currentDate);
1316     CHECK_NULL_RETURN(stackMonth, currentDate);
1317     CHECK_NULL_RETURN(stackDay, currentDate);
1318     auto blendYear = DynamicCast<FrameNode>(stackYear->GetLastChild());
1319     CHECK_NULL_RETURN(blendYear, currentDate);
1320     auto yearColumn = DynamicCast<FrameNode>(blendYear->GetLastChild());
1321     CHECK_NULL_RETURN(yearColumn, currentDate);
1322     auto blendMonth = DynamicCast<FrameNode>(stackMonth->GetLastChild());
1323     CHECK_NULL_RETURN(blendMonth, currentDate);
1324     auto monthColumn = DynamicCast<FrameNode>(blendMonth->GetLastChild());
1325     CHECK_NULL_RETURN(monthColumn, currentDate);
1326     auto blendDay = DynamicCast<FrameNode>(stackDay->GetLastChild());
1327     CHECK_NULL_RETURN(blendDay, currentDate);
1328     auto dayColumn = DynamicCast<FrameNode>(blendDay->GetLastChild());
1329     CHECK_NULL_RETURN(dayColumn, currentDate);
1330     auto yearDatePickerColumnPattern = yearColumn->GetPattern<DatePickerColumnPattern>();
1331     auto monthDatePickerColumnPattern = monthColumn->GetPattern<DatePickerColumnPattern>();
1332     auto dayDatePickerColumnPattern = dayColumn->GetPattern<DatePickerColumnPattern>();
1333     CHECK_NULL_RETURN(yearDatePickerColumnPattern, currentDate);
1334     CHECK_NULL_RETURN(monthDatePickerColumnPattern, currentDate);
1335     CHECK_NULL_RETURN(dayDatePickerColumnPattern, currentDate);
1336     if (!IsShowLunar()) {
1337         currentDate.SetYear(startDateSolar_.GetYear() + yearDatePickerColumnPattern->GetCurrentIndex());
1338         currentDate.SetMonth(
1339             monthDatePickerColumnPattern->GetCurrentIndex() + 1); // month from 1 to 12, index from 0 to 11.
1340         currentDate.SetDay(dayDatePickerColumnPattern->GetCurrentIndex() + 1); // day from 1 to 31, index from 0 to 30.
1341         return currentDate;
1342     }
1343     uint32_t lunarYear = startDateLunar_.year + yearDatePickerColumnPattern->GetCurrentIndex();
1344     return LunarToSolar(GetCurrentLunarDate(lunarYear));
1345 }
1346 
OrderCurrentDateByYearMonthDayColumn(RefPtr<FrameNode> & stackYear,RefPtr<FrameNode> & stackMonth,RefPtr<FrameNode> & stackDay) const1347 void DatePickerPattern::OrderCurrentDateByYearMonthDayColumn(
1348     RefPtr<FrameNode>& stackYear, RefPtr<FrameNode>& stackMonth, RefPtr<FrameNode>& stackDay) const
1349 {
1350     auto host = GetHost();
1351     CHECK_NULL_VOID(host);
1352     auto children = host->GetChildren();
1353     if (children.size() != CHILD_SIZE) {
1354         return;
1355     }
1356     auto processDateNode = [&children](RefPtr<UINode>& first, RefPtr<UINode>& second, RefPtr<UINode>& third) {
1357         auto iter = children.begin();
1358         first = *iter++;
1359         CHECK_NULL_VOID(first);
1360         second = *iter++;
1361         CHECK_NULL_VOID(second);
1362         third = *iter;
1363         CHECK_NULL_VOID(third);
1364     };
1365     RefPtr<UINode> year;
1366     RefPtr<UINode> month;
1367     RefPtr<UINode> day;
1368     if (dateOrder_ == "M-d-y") {
1369         processDateNode(month, day, year);
1370     } else if (dateOrder_ == "y-d-M") {
1371         processDateNode(year, day, month);
1372     } else {
1373         processDateNode(year, month, day);
1374     }
1375     stackYear = DynamicCast<FrameNode>(year);
1376     stackMonth = DynamicCast<FrameNode>(month);
1377     stackDay = DynamicCast<FrameNode>(day);
1378 }
1379 
GetCurrentDateByMonthDaysColumn() const1380 PickerDate DatePickerPattern::GetCurrentDateByMonthDaysColumn() const
1381 {
1382     PickerDate currentDate;
1383     auto host = GetHost();
1384     CHECK_NULL_RETURN(host, currentDate);
1385 
1386     auto children = host->GetChildren();
1387     if (children.size() <= SINGLE_CHILD_SIZE) {
1388         return currentDate;
1389     }
1390     auto iter = children.begin();
1391     auto monthDays = (*iter);
1392     CHECK_NULL_RETURN(monthDays, currentDate);
1393     iter++;
1394     auto year = *iter;
1395     CHECK_NULL_RETURN(year, currentDate);
1396     auto stackMonthDays = DynamicCast<FrameNode>(monthDays);
1397     auto blendMonthDays = DynamicCast<FrameNode>(stackMonthDays->GetLastChild());
1398     CHECK_NULL_RETURN(blendMonthDays, currentDate);
1399     auto monthDaysNode = DynamicCast<FrameNode>(blendMonthDays->GetLastChild());
1400     auto stackYear = DynamicCast<FrameNode>(year);
1401     auto blendYear = DynamicCast<FrameNode>(stackYear->GetLastChild());
1402     CHECK_NULL_RETURN(blendYear, currentDate);
1403     auto yearDaysNode = DynamicCast<FrameNode>(blendYear->GetLastChild());
1404     CHECK_NULL_RETURN(monthDaysNode, currentDate);
1405     CHECK_NULL_RETURN(yearDaysNode, currentDate);
1406 
1407     auto monthDaysDatePickerColumnPattern = monthDaysNode->GetPattern<DatePickerColumnPattern>();
1408     auto yearDatePickerColumnPattern = yearDaysNode->GetPattern<DatePickerColumnPattern>();
1409     CHECK_NULL_RETURN(yearDatePickerColumnPattern, currentDate);
1410     CHECK_NULL_RETURN(monthDaysDatePickerColumnPattern, currentDate);
1411 
1412     if (!IsShowLunar()) {
1413         currentDate.SetYear(startDateSolar_.GetYear() + yearDatePickerColumnPattern->GetCurrentIndex());
1414         auto monthDaysIndex = monthDaysDatePickerColumnPattern->GetCurrentIndex();
1415 
1416         uint32_t month = 1;
1417         for (; month <= 12; ++month) { // month start from 1 to 12
1418             uint32_t daysInMonth = PickerDate::GetMaxDay(currentDate.GetYear(), month);
1419             if (monthDaysIndex < daysInMonth) {
1420                 break;
1421             } else {
1422                 monthDaysIndex -= daysInMonth;
1423             }
1424         }
1425         currentDate.SetMonth(month);
1426         currentDate.SetDay(monthDaysIndex + 1); // days is index start form 0 and day start form 1.
1427         return currentDate;
1428     }
1429 
1430     uint32_t lunarYear = startDateLunar_.year + yearDatePickerColumnPattern->GetCurrentIndex();
1431     return LunarToSolar(GetCurrentLunarDateByMonthDaysColumn(lunarYear));
1432 }
1433 
GetCurrentLunarDateByMonthDaysColumn(uint32_t lunarYear) const1434 LunarDate DatePickerPattern::GetCurrentLunarDateByMonthDaysColumn(uint32_t lunarYear) const
1435 {
1436     LunarDate lunarResult;
1437     auto host = GetHost();
1438     CHECK_NULL_RETURN(host, lunarResult);
1439 
1440     auto children = host->GetChildren();
1441     if (children.size() <= SINGLE_CHILD_SIZE) {
1442         return lunarResult;
1443     }
1444     auto iter = children.begin();
1445     auto monthDays = (*iter);
1446     CHECK_NULL_RETURN(monthDays, lunarResult);
1447     iter++;
1448     auto year = *iter;
1449     CHECK_NULL_RETURN(year, lunarResult);
1450     auto stackMonthDays = DynamicCast<FrameNode>(monthDays);
1451     auto monthDaysNode = DynamicCast<FrameNode>(stackMonthDays->GetLastChild()->GetLastChild());
1452     auto stackYear = DynamicCast<FrameNode>(year);
1453     auto blendYear = DynamicCast<FrameNode>(stackYear->GetLastChild());
1454     CHECK_NULL_RETURN(blendYear, lunarResult);
1455     auto yearDaysNode = DynamicCast<FrameNode>(blendYear->GetLastChild());
1456     CHECK_NULL_RETURN(monthDaysNode, lunarResult);
1457     CHECK_NULL_RETURN(yearDaysNode, lunarResult);
1458 
1459     auto monthDaysDatePickerColumnPattern = monthDaysNode->GetPattern<DatePickerColumnPattern>();
1460     auto yearDatePickerColumnPattern = yearDaysNode->GetPattern<DatePickerColumnPattern>();
1461     CHECK_NULL_RETURN(monthDaysDatePickerColumnPattern, lunarResult);
1462     CHECK_NULL_RETURN(yearDatePickerColumnPattern, lunarResult);
1463 
1464 
1465     uint32_t lunarLeapMonth = 0;
1466     bool hasLeapMonth = GetLunarLeapMonth(lunarYear, lunarLeapMonth);
1467     auto monthDaysIndex = monthDaysDatePickerColumnPattern->GetCurrentIndex();
1468     uint32_t month = 1;
1469     for (; month <= 12; ++month) { // month start from 1 to 12
1470         auto flag = hasLeapMonth && lunarLeapMonth == month;
1471         uint32_t daysInMonth = GetLunarMaxDay(lunarYear, month, flag && lunarResult.isLeapMonth);
1472         if (monthDaysIndex < daysInMonth) {
1473             break;
1474         } else {
1475             monthDaysIndex -= daysInMonth;
1476         }
1477         if (flag && !lunarResult.isLeapMonth) {
1478             --month;
1479             lunarResult.isLeapMonth = true;
1480         }
1481     }
1482     lunarResult.month = month;
1483     lunarResult.isLeapMonth = (lunarResult.month == lunarLeapMonth && hasLeapMonth);
1484     lunarResult.day = monthDaysIndex + 1; // day start form 1, index start from 0
1485     lunarResult.year = startDateLunar_.year + yearDatePickerColumnPattern->GetCurrentIndex();
1486 
1487     return lunarResult;
1488 }
1489 
AdjustLunarDate(LunarDate & date)1490 void DatePickerPattern::AdjustLunarDate(LunarDate& date)
1491 {
1492     auto host = GetHost();
1493     CHECK_NULL_VOID(host);
1494 
1495     auto dataPickerRowLayoutProperty = host->GetLayoutProperty<DataPickerRowLayoutProperty>();
1496     CHECK_NULL_VOID(dataPickerRowLayoutProperty);
1497     startDateLunar_ = dataPickerRowLayoutProperty->GetStartDate().value_or(SolarToLunar(startDateSolar_));
1498     endDateLunar_ = dataPickerRowLayoutProperty->GetEndDate().value_or(SolarToLunar(endDateSolar_));
1499 
1500     if (LunarDateCompare(date, startDateLunar_) < 0) {
1501         date = startDateLunar_;
1502         return;
1503     }
1504     if (LunarDateCompare(date, endDateLunar_) > 0) {
1505         date = endDateLunar_;
1506     }
1507 }
1508 
LunarDateCompare(const LunarDate & left,const LunarDate & right) const1509 int DatePickerPattern::LunarDateCompare(const LunarDate& left, const LunarDate& right) const
1510 {
1511     static const int leftEqualRight = 0;   // means left = right
1512     static const int leftGreatRight = 1;   // means left > right
1513     static const int leftLessRight = -1;   // means left < right
1514     static const double addingValue = 0.5; // adding value for leap month.
1515     if (left.year > right.year) {
1516         return leftGreatRight;
1517     }
1518     if (left.year < right.year) {
1519         return leftLessRight;
1520     }
1521     double leftMonth = (left.isLeapMonth ? left.month + addingValue : left.month);
1522     double rightMonth = (right.isLeapMonth ? right.month + addingValue : right.month);
1523     if (GreatNotEqual(leftMonth, rightMonth)) {
1524         return leftGreatRight;
1525     }
1526     if (LessNotEqual(leftMonth, rightMonth)) {
1527         return leftLessRight;
1528     }
1529     if (left.day > right.day) {
1530         return leftGreatRight;
1531     }
1532     if (left.day < right.day) {
1533         return leftLessRight;
1534     }
1535     return leftEqualRight;
1536 }
1537 
LunarColumnsBuilding(const LunarDate & current)1538 void DatePickerPattern::LunarColumnsBuilding(const LunarDate& current)
1539 {
1540     RefPtr<FrameNode> yearColumn;
1541     RefPtr<FrameNode> monthColumn;
1542     RefPtr<FrameNode> dayColumn;
1543     RefPtr<FrameNode> columns[COLUMNS_SIZE];
1544     auto host = GetHost();
1545     CHECK_NULL_VOID(host);
1546     int index = 0;
1547     int order[COLUMNS_SIZE];
1548     if (dateOrder_ == "M-d-y") {
1549         order[COLUMNS_ZERO] = INDEX_MONTH;
1550         order[COLUMNS_ONE] = INDEX_DAY;
1551         order[COLUMNS_TWO] = INDEX_YEAR;
1552     } else if (dateOrder_ == "y-d-M") {
1553         order[COLUMNS_ZERO] = INDEX_YEAR;
1554         order[COLUMNS_ONE] = INDEX_DAY;
1555         order[COLUMNS_TWO] = INDEX_MONTH;
1556     } else {
1557         order[COLUMNS_ZERO] = INDEX_YEAR;
1558         order[COLUMNS_ONE] = INDEX_MONTH;
1559         order[COLUMNS_TWO] = INDEX_DAY;
1560     }
1561     for (const auto& stackChild : host->GetChildren()) {
1562         CHECK_NULL_VOID(stackChild);
1563         auto blendChild = stackChild->GetLastChild();
1564         CHECK_NULL_VOID(blendChild);
1565         auto child = blendChild->GetLastChild();
1566         columns[order[index]] = GetColumn(child->GetId());
1567         index++;
1568     }
1569     yearColumn = columns[COLUMNS_ZERO];
1570     monthColumn = columns[COLUMNS_ONE];
1571     dayColumn = columns[COLUMNS_TWO];
1572     CHECK_NULL_VOID(yearColumn);
1573     CHECK_NULL_VOID(monthColumn);
1574     CHECK_NULL_VOID(dayColumn);
1575 
1576     AdjustLunarStartEndDate();
1577     auto startYear = startDateLunar_.year;
1578     auto endYear = endDateLunar_.year;
1579     auto startMonth = startDateLunar_.month;
1580     auto endMonth = endDateLunar_.month;
1581     auto startDay = startDateLunar_.day;
1582     auto endDay = endDateLunar_.day;
1583     uint32_t maxDay = GetLunarMaxDay(current.year, current.month, current.isLeapMonth);
1584     if (startYear < endYear) {
1585         startMonth = 1;
1586         endMonth = 12;
1587         startDay = 1;
1588         endDay = maxDay;
1589     }
1590     if (startYear == endYear && startMonth < endMonth) {
1591         startDay = 1;
1592         endDay = maxDay;
1593     }
1594 
1595     options_[yearColumn].clear();
1596     for (uint32_t index = startYear; index <= endYear; ++index) {
1597         if (current.year == index) {
1598             auto datePickerColumnPattern = yearColumn->GetPattern<DatePickerColumnPattern>();
1599             CHECK_NULL_VOID(datePickerColumnPattern);
1600             datePickerColumnPattern->SetCurrentIndex(options_[yearColumn].size());
1601         }
1602         options_[yearColumn].emplace_back(PickerDateF::CreateYear(index));
1603     }
1604 
1605     uint32_t lunarLeapMonth = 0;
1606     bool hasLeapMonth = GetLunarLeapMonth(current.year, lunarLeapMonth);
1607     options_[monthColumn].clear();
1608     if (startYear == endYear) {
1609         options_[monthColumn].resize(startMonth > 0 ? startMonth - 1 : 0, emptyPickerDate_);
1610     }
1611     // lunar's month start form startMonth to endMonth
1612     for (uint32_t index = startMonth; index <= endMonth; ++index) {
1613         if (!current.isLeapMonth && current.month == index) {
1614             auto datePickerColumnPattern = monthColumn->GetPattern<DatePickerColumnPattern>();
1615             CHECK_NULL_VOID(datePickerColumnPattern);
1616             datePickerColumnPattern->SetCurrentIndex(options_[monthColumn].size());
1617         }
1618         options_[monthColumn].emplace_back(PickerDateF::CreateMonth(index, true, false));
1619 
1620         if (hasLeapMonth && lunarLeapMonth == index) {
1621             if (current.isLeapMonth && current.month == index) {
1622                 auto datePickerColumnPattern = monthColumn->GetPattern<DatePickerColumnPattern>();
1623                 CHECK_NULL_VOID(datePickerColumnPattern);
1624                 datePickerColumnPattern->SetCurrentIndex(options_[monthColumn].size());
1625             }
1626             options_[monthColumn].emplace_back(PickerDateF::CreateMonth(index, true, true));
1627         }
1628     }
1629 
1630     options_[dayColumn].clear();
1631     if (startYear == endYear && startMonth == endMonth) {
1632         options_[dayColumn].resize(startDay - 1, emptyPickerDate_);
1633     }
1634     // lunar's day start from startDay
1635     for (uint32_t index = startDay; index <= endDay; ++index) {
1636         if (current.day == index) {
1637             auto datePickerColumnPattern = dayColumn->GetPattern<DatePickerColumnPattern>();
1638             CHECK_NULL_VOID(datePickerColumnPattern);
1639             datePickerColumnPattern->SetCurrentIndex(options_[dayColumn].size());
1640         }
1641         options_[dayColumn].emplace_back(PickerDateF::CreateDay(index, true));
1642     }
1643     auto yearColumnPattern = yearColumn->GetPattern<DatePickerColumnPattern>();
1644     CHECK_NULL_VOID(yearColumnPattern);
1645     auto monthColumnPattern = monthColumn->GetPattern<DatePickerColumnPattern>();
1646     CHECK_NULL_VOID(monthColumnPattern);
1647     auto dayColumnPattern = dayColumn->GetPattern<DatePickerColumnPattern>();
1648     CHECK_NULL_VOID(dayColumnPattern);
1649     yearColumnPattern->SetOptions(GetOptions());
1650     monthColumnPattern->SetOptions(GetOptions());
1651     dayColumnPattern->SetOptions(GetOptions());
1652 
1653     SetShowLunar(true);
1654 }
1655 
SolarColumnsBuilding(const PickerDate & current)1656 void DatePickerPattern::SolarColumnsBuilding(const PickerDate& current)
1657 {
1658     RefPtr<FrameNode> yearColumn;
1659     RefPtr<FrameNode> monthColumn;
1660     RefPtr<FrameNode> dayColumn;
1661 
1662     RefPtr<FrameNode> columns[COLUMNS_SIZE];
1663     auto host = GetHost();
1664     CHECK_NULL_VOID(host);
1665     int index = 0;
1666     int order[COLUMNS_SIZE];
1667     if (dateOrder_ == "M-d-y") {
1668         order[COLUMNS_ZERO] = INDEX_MONTH;
1669         order[COLUMNS_ONE] = INDEX_DAY;
1670         order[COLUMNS_TWO] = INDEX_YEAR;
1671     } else if (dateOrder_ == "y-d-M") {
1672         order[COLUMNS_ZERO] = INDEX_YEAR;
1673         order[COLUMNS_ONE] = INDEX_DAY;
1674         order[COLUMNS_TWO] = INDEX_MONTH;
1675     } else {
1676         order[COLUMNS_ZERO] = INDEX_YEAR;
1677         order[COLUMNS_ONE] = INDEX_MONTH;
1678         order[COLUMNS_TWO] = INDEX_DAY;
1679     }
1680     for (const auto& stackChild : host->GetChildren()) {
1681         CHECK_NULL_VOID(stackChild);
1682         auto blendChild = stackChild->GetLastChild();
1683         CHECK_NULL_VOID(blendChild);
1684         auto child = blendChild->GetLastChild();
1685         columns[order[index]] = GetColumn(child->GetId());
1686         index++;
1687     }
1688     yearColumn = columns[COLUMNS_ZERO];
1689     monthColumn = columns[COLUMNS_ONE];
1690     dayColumn = columns[COLUMNS_TWO];
1691 
1692     CHECK_NULL_VOID(yearColumn);
1693     CHECK_NULL_VOID(monthColumn);
1694     CHECK_NULL_VOID(dayColumn);
1695 
1696     AdjustSolarStartEndDate();
1697     auto startYear = startDateSolar_.GetYear();
1698     auto endYear = endDateSolar_.GetYear();
1699     auto startMonth = startDateSolar_.GetMonth();
1700     auto endMonth = endDateSolar_.GetMonth();
1701     auto startDay = startDateSolar_.GetDay();
1702     auto endDay = endDateSolar_.GetDay();
1703 
1704     uint32_t maxDay = PickerDate::GetMaxDay(current.GetYear(), current.GetMonth());
1705     if (startYear < endYear) {
1706         startMonth = 1;
1707         endMonth = 12;
1708         startDay = 1;
1709         endDay = maxDay;
1710     }
1711     if (startYear == endYear && startMonth < endMonth) {
1712         startDay = 1;
1713         endDay = maxDay;
1714     }
1715 
1716     options_[yearColumn].clear();
1717     for (uint32_t year = startYear; year <= endYear; ++year) {
1718         if (year == current.GetYear()) {
1719             auto datePickerColumnPattern = yearColumn->GetPattern<DatePickerColumnPattern>();
1720             CHECK_NULL_VOID(datePickerColumnPattern);
1721             datePickerColumnPattern->SetCurrentIndex(options_[yearColumn].size());
1722         }
1723         options_[yearColumn].emplace_back(PickerDateF::CreateYear(year));
1724     }
1725 
1726     options_[monthColumn].clear();
1727     if (startYear == endYear) {
1728         options_[monthColumn].resize(startMonth > 0 ? startMonth - 1 : 0, emptyPickerDate_);
1729     }
1730     // solar's month start form 1 to 12
1731     for (uint32_t month = startMonth; month <= endMonth; month++) {
1732         if (month == current.GetMonth()) {
1733             auto datePickerColumnPattern = monthColumn->GetPattern<DatePickerColumnPattern>();
1734             CHECK_NULL_VOID(datePickerColumnPattern);
1735             // back index = size - 1
1736             datePickerColumnPattern->SetCurrentIndex(options_[monthColumn].size());
1737         }
1738 
1739         options_[monthColumn].emplace_back(PickerDateF::CreateMonth(month, false, false));
1740     }
1741 
1742     options_[dayColumn].clear();
1743     if (startYear == endYear && startMonth == endMonth) {
1744         options_[dayColumn].resize(startDay - 1, emptyPickerDate_);
1745     }
1746     // solar's day start from 1
1747     for (uint32_t day = startDay; day <= endDay; day++) {
1748         if (day == current.GetDay()) {
1749             auto datePickerColumnPattern = dayColumn->GetPattern<DatePickerColumnPattern>();
1750             CHECK_NULL_VOID(datePickerColumnPattern);
1751             datePickerColumnPattern->SetCurrentIndex(options_[dayColumn].size());
1752         }
1753         options_[dayColumn].emplace_back(PickerDateF::CreateDay(day, false));
1754     }
1755 
1756     auto yearColumnPattern = yearColumn->GetPattern<DatePickerColumnPattern>();
1757     CHECK_NULL_VOID(yearColumnPattern);
1758     auto monthColumnPattern = monthColumn->GetPattern<DatePickerColumnPattern>();
1759     CHECK_NULL_VOID(monthColumnPattern);
1760     auto dayColumnPattern = dayColumn->GetPattern<DatePickerColumnPattern>();
1761     CHECK_NULL_VOID(dayColumnPattern);
1762     yearColumnPattern->SetOptions(GetOptions());
1763     monthColumnPattern->SetOptions(GetOptions());
1764     dayColumnPattern->SetOptions(GetOptions());
1765 
1766     SetShowLunar(false);
1767 }
1768 
LunarMonthDaysColumnBuilding(const LunarDate & current)1769 void DatePickerPattern::LunarMonthDaysColumnBuilding(const LunarDate& current)
1770 {
1771     RefPtr<FrameNode> monthDaysColumn;
1772     RefPtr<FrameNode> yearColumn;
1773     auto host = GetHost();
1774     CHECK_NULL_VOID(host);
1775 
1776     auto children = host->GetChildren();
1777     if (children.size() <= SINGLE_CHILD_SIZE) {
1778         return;
1779     }
1780 
1781     auto iter = children.begin();
1782     auto monthDays = (*iter);
1783     CHECK_NULL_VOID(monthDays);
1784     iter++;
1785     auto year = *iter;
1786     CHECK_NULL_VOID(year);
1787     auto stackMonthDays = DynamicCast<FrameNode>(monthDays);
1788     auto blendMonthDays = DynamicCast<FrameNode>(stackMonthDays->GetLastChild());
1789     CHECK_NULL_VOID(blendMonthDays);
1790     auto monthDaysNode = DynamicCast<FrameNode>(blendMonthDays->GetLastChild());
1791     auto stackYear = DynamicCast<FrameNode>(year);
1792     auto blendYear = DynamicCast<FrameNode>(stackYear->GetLastChild());
1793     CHECK_NULL_VOID(blendYear);
1794     auto yearDaysNode = DynamicCast<FrameNode>(blendYear->GetLastChild());
1795     CHECK_NULL_VOID(monthDaysNode);
1796     CHECK_NULL_VOID(yearDaysNode);
1797 
1798     monthDaysColumn = GetColumn(monthDaysNode->GetId());
1799     yearColumn = GetColumn(yearDaysNode->GetId());
1800     CHECK_NULL_VOID(monthDaysColumn);
1801     CHECK_NULL_VOID(yearColumn);
1802 
1803     AdjustLunarStartEndDate();
1804 
1805     auto startYear = startDateLunar_.year;
1806     auto endYear = endDateLunar_.year;
1807 
1808     options_[yearColumn].clear();
1809     for (uint32_t index = startYear; index <= endYear; ++index) {
1810         if (current.year == index) {
1811             auto datePickerColumnPattern = yearColumn->GetPattern<DatePickerColumnPattern>();
1812             CHECK_NULL_VOID(datePickerColumnPattern);
1813             datePickerColumnPattern->SetCurrentIndex(options_[yearColumn].size());
1814         }
1815         options_[yearColumn].emplace_back(PickerDateF::CreateYear(index));
1816     }
1817 
1818     FillLunarMonthDaysOptions(current, monthDaysColumn);
1819 
1820     auto yearColumnPattern = yearColumn->GetPattern<DatePickerColumnPattern>();
1821     auto monthDaysColumnPattern = monthDaysColumn->GetPattern<DatePickerColumnPattern>();
1822     CHECK_NULL_VOID(yearColumnPattern);
1823     CHECK_NULL_VOID(monthDaysColumnPattern);
1824     yearColumnPattern->SetOptions(GetOptions());
1825     monthDaysColumnPattern->SetOptions(GetOptions());
1826 
1827     SetShowLunar(true);
1828 }
1829 
SolarMonthDaysColumnsBuilding(const PickerDate & current)1830 void DatePickerPattern::SolarMonthDaysColumnsBuilding(const PickerDate& current)
1831 {
1832     RefPtr<FrameNode> monthDaysColumn;
1833     RefPtr<FrameNode> yearColumn;
1834     auto host = GetHost();
1835     CHECK_NULL_VOID(host);
1836 
1837     auto children = host->GetChildren();
1838     if (children.size() <= SINGLE_CHILD_SIZE) {
1839         return;
1840     }
1841     auto iter = children.begin();
1842     auto monthDays = (*iter);
1843     CHECK_NULL_VOID(monthDays);
1844     iter++;
1845     auto year = *iter;
1846     CHECK_NULL_VOID(year);
1847     auto stackMonthDays = DynamicCast<FrameNode>(monthDays);
1848     auto blendMonthDays = DynamicCast<FrameNode>(stackMonthDays->GetLastChild());
1849     CHECK_NULL_VOID(blendMonthDays);
1850     auto monthDaysNode = DynamicCast<FrameNode>(blendMonthDays->GetLastChild());
1851     auto stackYear = DynamicCast<FrameNode>(year);
1852     auto blendYear = DynamicCast<FrameNode>(stackYear->GetLastChild());
1853     CHECK_NULL_VOID(blendYear);
1854     auto yearDaysNode = DynamicCast<FrameNode>(blendYear->GetLastChild());
1855     monthDaysColumn = GetColumn(monthDaysNode->GetId());
1856     yearColumn = GetColumn(yearDaysNode->GetId());
1857     CHECK_NULL_VOID(monthDaysColumn);
1858     CHECK_NULL_VOID(yearColumn);
1859 
1860     AdjustSolarStartEndDate();
1861     FillSolarYearOptions(current, yearColumn);
1862 
1863     options_[monthDaysColumn].clear();
1864     for (uint32_t index = MIN_MONTH; index <= MAX_MONTH; ++index) {
1865         uint32_t maxDay = PickerDate::GetMaxDay(current.GetYear(), index);
1866         for (uint32_t dayIndex = MIN_DAY; dayIndex <= maxDay; ++dayIndex) {
1867             if (index == current.GetMonth() && dayIndex == current.GetDay()) {
1868                 auto datePickerColumnPattern = monthDaysColumn->GetPattern<DatePickerColumnPattern>();
1869                 CHECK_NULL_VOID(datePickerColumnPattern);
1870                 datePickerColumnPattern->SetCurrentIndex(options_[monthDaysColumn].size());
1871             }
1872             options_[monthDaysColumn].emplace_back(PickerDateF::CreateMonthDay(index, dayIndex, false, false));
1873         }
1874     }
1875 
1876     auto yearColumnPattern = yearColumn->GetPattern<DatePickerColumnPattern>();
1877     auto monthDaysColumnPattern = monthDaysColumn->GetPattern<DatePickerColumnPattern>();
1878     CHECK_NULL_VOID(yearColumnPattern);
1879     CHECK_NULL_VOID(monthDaysColumnPattern);
1880     yearColumnPattern->SetOptions(GetOptions());
1881     monthDaysColumnPattern->SetOptions(GetOptions());
1882 
1883     SetShowLunar(false);
1884 }
1885 
FillSolarYearOptions(const PickerDate & current,RefPtr<FrameNode> & yearColumn)1886 void DatePickerPattern::FillSolarYearOptions(const PickerDate& current, RefPtr<FrameNode>& yearColumn)
1887 {
1888     options_[yearColumn].clear();
1889     for (uint32_t year = startDateSolar_.GetYear(); year <= endDateSolar_.GetYear(); ++year) {
1890         if (year == current.GetYear()) {
1891             auto datePickerColumnPattern = yearColumn->GetPattern<DatePickerColumnPattern>();
1892             CHECK_NULL_VOID(datePickerColumnPattern);
1893             datePickerColumnPattern->SetCurrentIndex(options_[yearColumn].size());
1894         }
1895         options_[yearColumn].emplace_back(PickerDateF::CreateYear(year));
1896     }
1897 }
1898 
FillLunarMonthDaysOptions(const LunarDate & current,RefPtr<FrameNode> & monthDaysColumn)1899 void DatePickerPattern::FillLunarMonthDaysOptions(const LunarDate& current, RefPtr<FrameNode>& monthDaysColumn)
1900 {
1901     uint32_t startMonth = 1;
1902     uint32_t endMonth = 12;
1903     uint32_t startDay = 1;
1904 
1905     uint32_t lunarLeapMonth = 0;
1906     bool hasLeapMonth = GetLunarLeapMonth(current.year, lunarLeapMonth);
1907     options_[monthDaysColumn].clear();
1908 
1909     for (uint32_t index = startMonth; index <= endMonth; ++index) {
1910         uint32_t maxDay = GetLunarMaxDay(current.year, index, false);
1911         for (uint32_t dayIndex = startDay; dayIndex <= maxDay; ++dayIndex) {
1912             if (!current.isLeapMonth && current.month == index && current.day == dayIndex) {
1913                 auto datePickerColumnPattern = monthDaysColumn->GetPattern<DatePickerColumnPattern>();
1914                 CHECK_NULL_VOID(datePickerColumnPattern);
1915                 datePickerColumnPattern->SetCurrentIndex(options_[monthDaysColumn].size());
1916             }
1917             options_[monthDaysColumn].emplace_back(PickerDateF::CreateMonthDay(index, dayIndex, true, false));
1918         }
1919 
1920         if (!hasLeapMonth || lunarLeapMonth != index) {
1921             continue;
1922         }
1923 
1924         maxDay = GetLunarMaxDay(current.year, index, true);
1925         for (uint32_t dayIndex = startDay; dayIndex <= maxDay; ++dayIndex) {
1926             if (current.isLeapMonth && current.month == index && current.day == dayIndex) {
1927                 auto datePickerColumnPattern = monthDaysColumn->GetPattern<DatePickerColumnPattern>();
1928                 CHECK_NULL_VOID(datePickerColumnPattern);
1929                 datePickerColumnPattern->SetCurrentIndex(options_[monthDaysColumn].size());
1930             }
1931             options_[monthDaysColumn].emplace_back(PickerDateF::CreateMonthDay(index, dayIndex, true, true));
1932         }
1933     }
1934 }
1935 
AdjustSolarStartEndDate()1936 void DatePickerPattern::AdjustSolarStartEndDate()
1937 {
1938     auto host = GetHost();
1939     CHECK_NULL_VOID(host);
1940 
1941     auto dataPickerRowLayoutProperty = host->GetLayoutProperty<DataPickerRowLayoutProperty>();
1942     CHECK_NULL_VOID(dataPickerRowLayoutProperty);
1943     startDateSolar_ = LunarToSolar(dataPickerRowLayoutProperty->GetStartDate().value_or(SolarToLunar(startDateSolar_)));
1944     endDateSolar_ = LunarToSolar(dataPickerRowLayoutProperty->GetEndDate().value_or(SolarToLunar(endDateSolar_)));
1945 
1946     if (startDateSolar_.GetYear() > endDateSolar_.GetYear()) {
1947         startDateSolar_ = startDefaultDateSolar_;
1948         endDateSolar_ = endDefaultDateSolar_;
1949     }
1950     if (startDateSolar_.GetYear() == endDateSolar_.GetYear() && startDateSolar_.GetMonth() > endDateSolar_.GetMonth()) {
1951         startDateSolar_ = startDefaultDateSolar_;
1952         endDateSolar_ = endDefaultDateSolar_;
1953     }
1954     if (startDateSolar_.GetYear() == endDateSolar_.GetYear() &&
1955         startDateSolar_.GetMonth() == endDateSolar_.GetMonth() && startDateSolar_.GetDay() > endDateSolar_.GetDay()) {
1956         startDateSolar_ = startDefaultDateSolar_;
1957         endDateSolar_ = endDefaultDateSolar_;
1958     }
1959 }
1960 
AdjustLunarStartEndDate()1961 void DatePickerPattern::AdjustLunarStartEndDate()
1962 {
1963     auto host = GetHost();
1964     CHECK_NULL_VOID(host);
1965 
1966     auto dataPickerRowLayoutProperty = host->GetLayoutProperty<DataPickerRowLayoutProperty>();
1967     CHECK_NULL_VOID(dataPickerRowLayoutProperty);
1968     startDateLunar_ = dataPickerRowLayoutProperty->GetStartDate().value_or(SolarToLunar(startDateSolar_));
1969     endDateLunar_ = dataPickerRowLayoutProperty->GetEndDate().value_or(SolarToLunar(endDateSolar_));
1970 
1971     if (GetStartDateLunar().year > GetEndDateLunar().year) {
1972         startDateLunar_ = SolarToLunar(startDefaultDateSolar_);
1973         endDateLunar_ = SolarToLunar(endDefaultDateSolar_);
1974     }
1975     if (GetStartDateLunar().year == GetEndDateLunar().year && GetStartDateLunar().month > GetEndDateLunar().month) {
1976         startDateLunar_ = SolarToLunar(startDefaultDateSolar_);
1977         endDateLunar_ = SolarToLunar(endDefaultDateSolar_);
1978     }
1979     if (GetStartDateLunar().year == GetEndDateLunar().year && GetStartDateLunar().month == GetEndDateLunar().month &&
1980         GetStartDateLunar().day > GetEndDateLunar().day) {
1981         startDateLunar_ = SolarToLunar(startDefaultDateSolar_);
1982         endDateLunar_ = SolarToLunar(endDefaultDateSolar_);
1983     }
1984 }
1985 
GetLunarLeapMonth(uint32_t year,uint32_t & outLeapMonth) const1986 bool DatePickerPattern::GetLunarLeapMonth(uint32_t year, uint32_t& outLeapMonth) const
1987 {
1988     auto leapMonth = LunarCalculator::GetLunarLeapMonth(year);
1989     if (leapMonth <= 0) {
1990         return false;
1991     }
1992 
1993     outLeapMonth = static_cast<uint32_t>(leapMonth);
1994     return true;
1995 }
1996 
GetLunarMaxDay(uint32_t year,uint32_t month,bool isLeap) const1997 uint32_t DatePickerPattern::GetLunarMaxDay(uint32_t year, uint32_t month, bool isLeap) const
1998 {
1999     if (isLeap) {
2000         return static_cast<uint32_t>(LunarCalculator::GetLunarLeapDays(year));
2001     } else {
2002         return static_cast<uint32_t>(LunarCalculator::GetLunarMonthDays(year, month));
2003     }
2004 }
2005 
SolarToLunar(const PickerDate & date) const2006 LunarDate DatePickerPattern::SolarToLunar(const PickerDate& date) const
2007 {
2008     Date result;
2009     result.year = date.GetYear();
2010     result.month = date.GetMonth();
2011     result.day = date.GetDay();
2012     return Localization::GetInstance()->GetLunarDate(result);
2013 }
2014 
LunarToSolar(const LunarDate & date) const2015 PickerDate DatePickerPattern::LunarToSolar(const LunarDate& date) const
2016 {
2017     uint32_t days = date.day > 0 ? date.day - 1 : 0; // calculate days from 1900.1.1 to this date
2018     if (date.isLeapMonth) {
2019         days += LunarCalculator::GetLunarMonthDays(date.year, date.month);
2020     } else {
2021         uint32_t leapMonth = LunarCalculator::GetLunarLeapMonth(date.year);
2022         if (leapMonth < date.month) {
2023             days += LunarCalculator::GetLunarLeapDays(date.year);
2024         }
2025     }
2026     for (uint32_t month = 1; month < date.month; ++month) { // month start from 1
2027         days += LunarCalculator::GetLunarMonthDays(date.year, month);
2028     }
2029     for (uint32_t year = 1900; year < date.year; ++year) { // year start from 1900
2030         days += LunarCalculator::GetLunarYearDays(year);
2031     }
2032     days += 30; // days from solar's 1900.1.1 to lunar's 1900.1.1 is 30
2033     PickerDate result;
2034     result.FromDays(days);
2035     return result;
2036 }
2037 
Init()2038 void DatePickerPattern::Init()
2039 {
2040     if (inited_) {
2041         return;
2042     }
2043     years_.clear();
2044     solarMonths_.clear();
2045     solarDays_.clear();
2046     lunarMonths_.clear();
2047     lunarDays_.clear();
2048     localizedMonths_ = Localization::GetInstance()->GetMonths(true);
2049 
2050     inited_ = true;
2051     Localization::GetInstance()->SetOnChange([]() { inited_ = false; });
2052 }
2053 
GetYear(uint32_t year)2054 const std::string& DatePickerPattern::GetYear(uint32_t year)
2055 {
2056     Init();
2057     if (!(1900 <= year && year <= 2100)) { // year in [1900,2100]
2058         return empty_;
2059     }
2060     auto index = year - 1900;
2061     auto it = years_.find(index);
2062     if (it == years_.end()) {
2063         DateTime date;
2064         date.year = year;
2065         auto& dateYear = years_[index];
2066         dateYear = Localization::GetInstance()->FormatDateTime(date, "y");
2067         return dateYear;
2068     }
2069     return it->second; // index in [0, 200]
2070 }
2071 
GetSolarMonth(uint32_t month)2072 const std::string& DatePickerPattern::GetSolarMonth(uint32_t month)
2073 {
2074     Init();
2075     if (!(1 <= month && month <= 12)) { // solar month in [1,12]
2076         return empty_;
2077     }
2078     auto index = month - 1;
2079     auto it = solarMonths_.find(index);
2080     if (it == solarMonths_.end()) {
2081         auto& dateMonth = solarMonths_[index];
2082         if (index < localizedMonths_.size()) {
2083             dateMonth = localizedMonths_[index];
2084         } else {
2085             DateTime date;
2086             date.month = month - 1; // W3C's month start from 0 to 11
2087             dateMonth = Localization::GetInstance()->FormatDateTime(date, "M");
2088         }
2089         return dateMonth;
2090     }
2091     return it->second; // index in [0,11]
2092 }
2093 
GetSolarDay(uint32_t day)2094 const std::string& DatePickerPattern::GetSolarDay(uint32_t day)
2095 {
2096     Init();
2097     if (!(1 <= day && day <= 31)) { // solar day in [1,31]
2098         return empty_;
2099     }
2100     auto index = day - 1;
2101     auto it = solarDays_.find(index);
2102     if (it == solarDays_.end()) {
2103         auto& dateDay = solarDays_[index];
2104         DateTime date;
2105         date.day = day;
2106         dateDay = Localization::GetInstance()->FormatDateTime(date, "d");
2107         return dateDay;
2108     }
2109     return it->second; // index in [0,30]
2110 }
2111 
GetLunarMonth(uint32_t month,bool isLeap)2112 const std::string& DatePickerPattern::GetLunarMonth(uint32_t month, bool isLeap)
2113 {
2114     Init();
2115     uint32_t index = (isLeap ? month + 12 : month); // leap month is behind 12 index
2116     if (!(1 <= index && index <= 24)) {             // lunar month need in [1,24]
2117         return empty_;
2118     }
2119     auto it = lunarMonths_.find(index - 1);
2120     if (it == lunarMonths_.end()) {
2121         auto& dateMonth = lunarMonths_[index - 1];
2122         dateMonth = Localization::GetInstance()->GetLunarMonth(month, isLeap);
2123         return dateMonth;
2124     }
2125     return it->second; // index in [0,23]
2126 }
2127 
GetLunarDay(uint32_t day)2128 const std::string& DatePickerPattern::GetLunarDay(uint32_t day)
2129 {
2130     Init();
2131     if (!(1 <= day && day <= 30)) { // lunar day need in [1,30]
2132         return empty_;
2133     }
2134     auto index = day - 1;
2135     auto it = lunarDays_.find(index);
2136     if (it == lunarDays_.end()) {
2137         auto& dateDay = lunarDays_[index];
2138         dateDay = Localization::GetInstance()->GetLunarDay(day);
2139         return dateDay;
2140     }
2141     return it->second; // index in [0,29]
2142 }
2143 
GetFormatString(PickerDateF date)2144 const std::string DatePickerPattern::GetFormatString(PickerDateF date)
2145 {
2146     if (date.year.has_value()) {
2147         return GetYear(date.year.value());
2148     }
2149 
2150     std::string monthStr;
2151     if (date.month.has_value()) {
2152         monthStr = date.lunar ? GetLunarMonth(date.month.value(), date.leap) : GetSolarMonth(date.month.value());
2153         if (!date.day.has_value()) {
2154             return monthStr;
2155         }
2156     }
2157 
2158     std::string dayStr;
2159     if (date.day.has_value()) {
2160         dayStr = date.lunar ? GetLunarDay(date.day.value()) : GetSolarDay(date.day.value());
2161         DateTimeSequence sequence;
2162         auto language = AceApplicationInfo::GetInstance().GetLanguage();
2163         OrderResult orderResult = sequence.GetDateOrder(language);
2164         if (language == "ug") {
2165             return date.month.has_value() ? (dayStr + "-" + monthStr) : dayStr;
2166         } else {
2167             return date.month.has_value() ? (monthStr + dayStr) : dayStr;
2168         }
2169     }
2170 
2171     return "";
2172 }
2173 
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const2174 void DatePickerPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
2175 {
2176     /* no fixed attr below, just return */
2177     if (filter.IsFastFilter()) {
2178         return;
2179     }
2180     auto GetDateString = [](const PickerDate& pickerDate) {
2181         std::string ret;
2182         ret += std::to_string(pickerDate.GetYear());
2183         ret += "-";
2184         ret += std::to_string(pickerDate.GetMonth());
2185         ret += "-";
2186         ret += std::to_string(pickerDate.GetDay());
2187         return ret;
2188     };
2189     auto rowLayoutProperty = GetLayoutProperty<DataPickerRowLayoutProperty>();
2190     CHECK_NULL_VOID(rowLayoutProperty);
2191     auto jsonConstructor = JsonUtil::Create(true);
2192     auto isLunar = rowLayoutProperty->GetLunarValue(false);
2193     if (isLunar) {
2194         jsonConstructor->Put("start", rowLayoutProperty->GetDateStart().c_str());
2195         jsonConstructor->Put("end", rowLayoutProperty->GetDateEnd().c_str());
2196         jsonConstructor->Put("selected", rowLayoutProperty->GetDateSelected().c_str());
2197     } else {
2198         jsonConstructor->Put("start", GetDateString(startDateSolar_).c_str());
2199         jsonConstructor->Put("end", GetDateString(endDateSolar_).c_str());
2200         jsonConstructor->Put("selected", GetDateString(selectedDate_).c_str());
2201     }
2202     json->PutExtAttr("constructor", jsonConstructor, filter);
2203 }
2204 
SetFocusDisable()2205 void DatePickerPattern::SetFocusDisable()
2206 {
2207     auto host = GetHost();
2208     CHECK_NULL_VOID(host);
2209 
2210     auto focusHub = host->GetFocusHub();
2211     CHECK_NULL_VOID(focusHub);
2212 
2213     focusHub->SetFocusable(false);
2214 }
2215 
SetFocusEnable()2216 void DatePickerPattern::SetFocusEnable()
2217 {
2218     auto host = GetHost();
2219     CHECK_NULL_VOID(host);
2220 
2221     auto focusHub = host->GetFocusHub();
2222     CHECK_NULL_VOID(focusHub);
2223 
2224     focusHub->SetFocusable(true);
2225 }
2226 } // namespace OHOS::Ace::NG
2227