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