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