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