• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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/calendar_picker/calendar_picker_pattern.h"
17 
18 #include <algorithm>
19 
20 #include "base/i18n/localization.h"
21 #include "base/utils/utf_helper.h"
22 #include "core/components/calendar/calendar_theme.h"
23 #include "core/components_ng/pattern/calendar_picker/calendar_dialog_view.h"
24 #include "core/components_ng/pattern/container_modal/container_modal_pattern.h"
25 #include "core/components_ng/pattern/image/image_layout_property.h"
26 #include "core/components_ng/pattern/text/text_layout_property.h"
27 #include "core/pipeline_ng/pipeline_context.h"
28 
29 namespace OHOS::Ace::NG {
30 namespace {
31 constexpr int32_t YEAR_INDEX = 0;
32 constexpr int32_t FIRST_SLASH = 1;
33 constexpr int32_t MONTH_INDEX = 2;
34 constexpr int32_t SECOND_SLASH = 3;
35 constexpr int32_t DAY_INDEX = 4;
36 constexpr int32_t YEAR_LENTH = 4;
37 constexpr int32_t ADD_BUTTON_INDEX = 0;
38 constexpr int32_t SUB_BUTTON_INDEX = 1;
39 constexpr int32_t DATE_NODE_COUNT = 3;
40 constexpr uint32_t MIN_YEAR = 1;
41 constexpr uint32_t MAX_YEAR = 5000;
42 constexpr uint32_t DELAY_TIME = 2000;
43 constexpr uint32_t MAX_MONTH = 12;
44 constexpr Dimension DIALOG_HEIGHT = 348.0_vp;
45 constexpr Dimension DIALOG_WIDTH = 336.0_vp;
46 constexpr double DISABLE_ALPHA = 0.4;
47 } // namespace
OnModifyDone()48 void CalendarPickerPattern::OnModifyDone()
49 {
50     Pattern::OnModifyDone();
51 
52     auto host = GetHost();
53     CHECK_NULL_VOID(host);
54     InitDateIndex();
55     InitClickEvent();
56     InitOnKeyEvent();
57     InitOnHoverEvent();
58     HandleEnable();
59     FlushTextStyle();
60     auto pipelineContext = host->GetContext();
61     CHECK_NULL_VOID(pipelineContext);
62     pipelineContext->AddWindowSizeChangeCallback(host->GetId());
63     UpdateEntryButtonColor();
64     UpdateEntryButtonBorderWidth();
65     UpdateAccessibilityText();
66 }
67 
UpdateAccessibilityText()68 void CalendarPickerPattern::UpdateAccessibilityText()
69 {
70     auto host = GetHost();
71     CHECK_NULL_VOID(host);
72     auto contentNode = AceType::DynamicCast<FrameNode>(host->GetFirstChild());
73     CHECK_NULL_VOID(contentNode);
74     int32_t hoverIndexs[] = { yearIndex_, FIRST_SLASH, monthIndex_, SECOND_SLASH, dayIndex_ };
75     std::string message;
76     for (auto index : hoverIndexs) {
77         auto textFrameNode = DynamicCast<FrameNode>(contentNode->GetChildAtIndex(index));
78         CHECK_NULL_VOID(textFrameNode);
79         auto textLayoutProperty = textFrameNode->GetLayoutProperty<TextLayoutProperty>();
80         CHECK_NULL_VOID(textLayoutProperty);
81         message += UtfUtils::Str16ToStr8(textLayoutProperty->GetContent().value_or(u""));
82     }
83     auto textAccessibilityProperty = contentNode->GetAccessibilityProperty<AccessibilityProperty>();
84     CHECK_NULL_VOID(textAccessibilityProperty);
85     textAccessibilityProperty->SetAccessibilityText(message);
86 }
87 
InitDateIndex()88 void CalendarPickerPattern::InitDateIndex()
89 {
90     std::vector<std::string> outOrder;
91     bool result = Localization::GetInstance()->GetDateOrder(outOrder);
92     if (!result || outOrder.size() < DATE_NODE_COUNT) {
93         yearIndex_ = YEAR_INDEX;
94         monthIndex_ = MONTH_INDEX;
95         dayIndex_ = DAY_INDEX;
96     } else {
97         size_t index = 0;
98         for (size_t i = 0; i < outOrder.size(); ++i) {
99             if (outOrder[i] == "year") {
100                 yearIndex_ = static_cast<int32_t>(i + index);
101             }
102 
103             if (outOrder[i] == "month") {
104                 monthIndex_ = static_cast<int32_t>(i + index);
105             }
106 
107             if (outOrder[i] == "day") {
108                 dayIndex_ = static_cast<int32_t>(i + index);
109             }
110 
111             index++;
112         }
113     }
114 }
115 
UpdateEntryButtonColor()116 void CalendarPickerPattern::UpdateEntryButtonColor()
117 {
118     auto host = GetHost();
119     CHECK_NULL_VOID(host);
120     auto buttonFlexNode = host->GetLastChild();
121     CHECK_NULL_VOID(buttonFlexNode);
122 
123     auto pipelineContext = host->GetContext();
124     CHECK_NULL_VOID(pipelineContext);
125     RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
126     CHECK_NULL_VOID(theme);
127 
128     int32_t buttonIndex = 0;
129     for (const auto& child : buttonFlexNode->GetChildren()) {
130         CHECK_NULL_VOID(child);
131         if (child->GetTag() == V2::BUTTON_ETS_TAG) {
132             auto buttonNode = AceType::DynamicCast<FrameNode>(child);
133             CHECK_NULL_VOID(buttonNode);
134             BorderColorProperty borderColor;
135             borderColor.SetColor(theme->GetEntryBorderColor());
136             buttonNode->GetRenderContext()->UpdateBorderColor(borderColor);
137             buttonNode->GetRenderContext()->UpdateBackgroundColor(Color::TRANSPARENT);
138             buttonNode->MarkModifyDone();
139 
140             auto image = buttonNode->GetChildren().front();
141             CHECK_NULL_VOID(image);
142             auto imageNode = AceType::DynamicCast<FrameNode>(image);
143             auto imageLayoutProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
144             CHECK_NULL_VOID(imageLayoutProperty);
145             auto imageInfo = imageLayoutProperty->GetImageSourceInfo();
146             CHECK_NULL_VOID(imageInfo);
147             auto buttonColor = theme->GetEntryArrowColor();
148             if (!IsAddOrSubButtonEnable(buttonIndex)) {
149                 buttonColor = buttonColor.ChangeOpacity(DISABLE_ALPHA);
150             }
151             imageInfo->SetFillColor(buttonColor);
152             buttonIndex++;
153             imageLayoutProperty->UpdateImageSourceInfo(imageInfo.value());
154             imageNode->MarkModifyDone();
155         }
156     }
157 }
158 
UpdateEntryButtonBorderWidth()159 void CalendarPickerPattern::UpdateEntryButtonBorderWidth()
160 {
161     auto host = GetHost();
162     CHECK_NULL_VOID(host);
163     auto buttonFlexNode = host->GetLastChild();
164     CHECK_NULL_VOID(buttonFlexNode);
165     auto pipelineContext = host->GetContext();
166     CHECK_NULL_VOID(pipelineContext);
167     RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
168     CHECK_NULL_VOID(theme);
169 
170     auto addButtonNode = AceType::DynamicCast<FrameNode>(buttonFlexNode->GetChildAtIndex(ADD_BUTTON_INDEX));
171     CHECK_NULL_VOID(addButtonNode);
172     auto subButtonNode = AceType::DynamicCast<FrameNode>(buttonFlexNode->GetChildAtIndex(SUB_BUTTON_INDEX));
173     CHECK_NULL_VOID(subButtonNode);
174 
175     auto textDirection = host->GetLayoutProperty()->GetNonAutoLayoutDirection();
176     BorderWidthProperty addBorderWidth;
177     BorderWidthProperty subBorderWidth;
178     if (textDirection == TextDirection::RTL) {
179         addBorderWidth.rightDimen = theme->GetEntryBorderWidth();
180         subBorderWidth.rightDimen = theme->GetEntryBorderWidth();
181         addBorderWidth.leftDimen = 0.0_vp;
182         subBorderWidth.leftDimen = 0.0_vp;
183     } else {
184         addBorderWidth.rightDimen = 0.0_vp;
185         subBorderWidth.rightDimen = 0.0_vp;
186         addBorderWidth.leftDimen = theme->GetEntryBorderWidth();
187         subBorderWidth.leftDimen = theme->GetEntryBorderWidth();
188     }
189     addButtonNode->GetLayoutProperty()->UpdateBorderWidth(addBorderWidth);
190     subButtonNode->GetLayoutProperty()->UpdateBorderWidth(subBorderWidth);
191     addButtonNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
192     subButtonNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
193 }
194 
UpdateEdgeAlign()195 void CalendarPickerPattern::UpdateEdgeAlign()
196 {
197     auto host = GetHost();
198     CHECK_NULL_VOID(host);
199     auto layoutProperty = host->GetLayoutProperty<CalendarPickerLayoutProperty>();
200     CHECK_NULL_VOID(layoutProperty);
201     auto textDirection = layoutProperty->GetNonAutoLayoutDirection();
202 
203     auto rtlAlignType = align_;
204     auto rtlX = offset_.GetX().Value();
205     if (textDirection == TextDirection::RTL) {
206         switch (align_) {
207             case CalendarEdgeAlign::EDGE_ALIGN_START:
208                 rtlAlignType = CalendarEdgeAlign::EDGE_ALIGN_END;
209                 break;
210             case CalendarEdgeAlign::EDGE_ALIGN_END:
211                 rtlAlignType = CalendarEdgeAlign::EDGE_ALIGN_START;
212                 break;
213             default:
214                 break;
215         }
216         rtlX = -offset_.GetX().Value();
217     }
218 
219     layoutProperty->UpdateDialogAlignType(rtlAlignType);
220     layoutProperty->UpdateDialogOffset(DimensionOffset(Dimension(rtlX), offset_.GetY()));
221 }
222 
OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper> & dirty,bool,bool)223 bool CalendarPickerPattern::OnDirtyLayoutWrapperSwap(
224     const RefPtr<LayoutWrapper>& dirty, bool /* skipMeasure */, bool /* skipLayout */)
225 {
226     if (!IsDialogShow()) {
227         return true;
228     }
229 
230     auto eventHub = GetOrCreateEventHub<CalendarPickerEventHub>();
231     CHECK_NULL_RETURN(eventHub, true);
232     eventHub->FireLayoutChangeEvent();
233     return true;
234 }
235 
InitClickEvent()236 void CalendarPickerPattern::InitClickEvent()
237 {
238     if (clickListener_) {
239         return;
240     }
241     auto host = GetHost();
242     CHECK_NULL_VOID(host);
243     auto gesture = host->GetOrCreateGestureEventHub();
244     CHECK_NULL_VOID(gesture);
245     auto clickCallback = [weak = WeakClaim(this)](GestureEvent& info) {
246         auto pattern = weak.Upgrade();
247         CHECK_NULL_VOID(pattern);
248         pattern->HandleClickEvent(info.GetGlobalLocation());
249     };
250     clickListener_ = AceType::MakeRefPtr<ClickEvent>(std::move(clickCallback));
251     gesture->AddClickEvent(clickListener_);
252 }
253 
HandleHoverEvent(bool state,const Offset & globalLocation)254 void CalendarPickerPattern::HandleHoverEvent(bool state, const Offset& globalLocation)
255 {
256     bool yearState = false;
257     bool monthState = false;
258     bool dayState = false;
259     bool addState = false;
260     bool subState = false;
261     if (state) {
262         auto currSelectdDate = calendarData_.selectedDate;
263         switch (CheckRegion(globalLocation)) {
264             case CalendarPickerSelectedType::YEAR:
265                 yearState = true;
266                 break;
267             case CalendarPickerSelectedType::MONTH:
268                 monthState = true;
269                 break;
270             case CalendarPickerSelectedType::DAY:
271                 dayState = true;
272                 break;
273             case CalendarPickerSelectedType::ADDBTN:
274                 NextDateBySelectedType(currSelectdDate);
275                 if (PickerDate::IsDateInRange(currSelectdDate, calendarData_.startDate, calendarData_.endDate)) {
276                     addState = true;
277                 }
278                 break;
279             case CalendarPickerSelectedType::SUBBTN:
280                 PrevDateBySelectedType(currSelectdDate);
281                 if (PickerDate::IsDateInRange(currSelectdDate, calendarData_.startDate, calendarData_.endDate)) {
282                     subState = true;
283                 }
284                 break;
285             default:
286                 break;
287         }
288     }
289     HandleTextHoverEvent(yearState, yearIndex_);
290     HandleTextHoverEvent(monthState, monthIndex_);
291     HandleTextHoverEvent(dayState, dayIndex_);
292     HandleButtonHoverEvent(addState, ADD_BUTTON_INDEX);
293     HandleButtonHoverEvent(subState, SUB_BUTTON_INDEX);
294 }
295 
HandleTouchEvent(bool isPressed,const Offset & globalLocation)296 void CalendarPickerPattern::HandleTouchEvent(bool isPressed, const Offset& globalLocation)
297 {
298     bool addState = false;
299     bool subState = false;
300     if (isPressed) {
301         auto currSelectdDate = calendarData_.selectedDate;
302         switch (CheckRegion(globalLocation)) {
303             case CalendarPickerSelectedType::ADDBTN:
304                 NextDateBySelectedType(currSelectdDate);
305                 if (PickerDate::IsDateInRange(currSelectdDate, calendarData_.startDate, calendarData_.endDate)) {
306                     addState = true;
307                 }
308                 break;
309             case CalendarPickerSelectedType::SUBBTN:
310                 PrevDateBySelectedType(currSelectdDate);
311                 if (PickerDate::IsDateInRange(currSelectdDate, calendarData_.startDate, calendarData_.endDate)) {
312                     subState = true;
313                 }
314                 break;
315             default:
316                 break;
317         }
318     }
319     HandleButtonTouchEvent(addState, ADD_BUTTON_INDEX);
320     HandleButtonTouchEvent(subState, SUB_BUTTON_INDEX);
321 }
322 
InitOnHoverEvent()323 void CalendarPickerPattern::InitOnHoverEvent()
324 {
325     if (hoverListener_) {
326         return;
327     }
328     auto host = GetHost();
329     CHECK_NULL_VOID(host);
330     auto contentNode = AceType::DynamicCast<FrameNode>(host->GetFirstChild());
331     CHECK_NULL_VOID(contentNode);
332     int32_t hoverIndexs[] = { yearIndex_, monthIndex_, dayIndex_ };
333     for (auto index : hoverIndexs) {
334         auto textFrameNode = DynamicCast<FrameNode>(contentNode->GetChildAtIndex(index));
335         CHECK_NULL_VOID(textFrameNode);
336         auto inputHub = textFrameNode->GetOrCreateInputEventHub();
337         CHECK_NULL_VOID(inputHub);
338         auto hoverCallback = [weak = WeakClaim(this), index](bool state) {
339             auto pattern = weak.Upgrade();
340             CHECK_NULL_VOID(pattern);
341             pattern->HandleTextHoverEvent(state, index);
342         };
343         hoverListener_ = AceType::MakeRefPtr<InputEvent>(std::move(hoverCallback));
344         inputHub->AddOnHoverEvent(hoverListener_);
345     }
346 }
347 
HandleClickEvent(const Offset & globalLocation)348 void CalendarPickerPattern::HandleClickEvent(const Offset& globalLocation)
349 {
350     switch (CheckRegion(globalLocation)) {
351         case CalendarPickerSelectedType::YEAR:
352             ShowDialog();
353             SetSelectedType(CalendarPickerSelectedType::YEAR);
354             return;
355         case CalendarPickerSelectedType::MONTH:
356             ShowDialog();
357             SetSelectedType(CalendarPickerSelectedType::MONTH);
358             return;
359         case CalendarPickerSelectedType::DAY:
360             ShowDialog();
361             SetSelectedType(CalendarPickerSelectedType::DAY);
362             return;
363         case CalendarPickerSelectedType::ADDBTN:
364             HandleAddButtonClick();
365             return;
366         case CalendarPickerSelectedType::SUBBTN:
367             HandleSubButtonClick();
368             return;
369         default:
370             SetSelectedType(CalendarPickerSelectedType::OTHER);
371             break;
372     }
373 
374     if (!IsDialogShow()) {
375         ShowDialog();
376     }
377 }
378 
ResetTextState()379 void CalendarPickerPattern::ResetTextState()
380 {
381     auto host = GetHost();
382     CHECK_NULL_VOID(host);
383     auto layoutProperty = host->GetLayoutProperty<CalendarPickerLayoutProperty>();
384     CHECK_NULL_VOID(layoutProperty);
385     auto contentNode = AceType::DynamicCast<FrameNode>(host->GetFirstChild());
386     CHECK_NULL_VOID(contentNode);
387     ResetTextStateByNode(DynamicCast<FrameNode>(contentNode->GetChildAtIndex(yearIndex_)));
388     ResetTextStateByNode(DynamicCast<FrameNode>(contentNode->GetChildAtIndex(FIRST_SLASH)));
389     ResetTextStateByNode(DynamicCast<FrameNode>(contentNode->GetChildAtIndex(monthIndex_)));
390     ResetTextStateByNode(DynamicCast<FrameNode>(contentNode->GetChildAtIndex(SECOND_SLASH)));
391     ResetTextStateByNode(DynamicCast<FrameNode>(contentNode->GetChildAtIndex(dayIndex_)));
392 }
393 
ResetTextStateByNode(const RefPtr<FrameNode> & textFrameNode)394 void CalendarPickerPattern::ResetTextStateByNode(const RefPtr<FrameNode>& textFrameNode)
395 {
396     CHECK_NULL_VOID(textFrameNode);
397     textFrameNode->GetRenderContext()->UpdateBackgroundColor(Color::TRANSPARENT);
398     auto host = GetHost();
399     CHECK_NULL_VOID(host);
400     auto layoutProperty = host->GetLayoutProperty<CalendarPickerLayoutProperty>();
401     CHECK_NULL_VOID(layoutProperty);
402     auto pipeline = host->GetContext();
403     CHECK_NULL_VOID(pipeline);
404     RefPtr<CalendarTheme> calendarTheme = pipeline->GetTheme<CalendarTheme>();
405     CHECK_NULL_VOID(calendarTheme);
406     textFrameNode->GetRenderContext()->UpdateForegroundColor(
407         layoutProperty->GetColor().value_or(calendarTheme->GetEntryFontColor()));
408     textFrameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
409 }
410 
CheckRegion(const Offset & globalLocation)411 CalendarPickerSelectedType CalendarPickerPattern::CheckRegion(const Offset& globalLocation)
412 {
413     auto host = GetHost();
414     CHECK_NULL_RETURN(host, CalendarPickerSelectedType::OTHER);
415     auto contentNode = AceType::DynamicCast<FrameNode>(host->GetFirstChild());
416     CHECK_NULL_RETURN(contentNode, CalendarPickerSelectedType::OTHER);
417 
418     auto location = PointF(globalLocation.GetX(), globalLocation.GetY());
419     if (IsInNodeRegion(DynamicCast<FrameNode>(contentNode->GetChildAtIndex(yearIndex_)), location)) {
420         return CalendarPickerSelectedType::YEAR;
421     }
422     if (IsInNodeRegion(DynamicCast<FrameNode>(contentNode->GetChildAtIndex(monthIndex_)), location)) {
423         return CalendarPickerSelectedType::MONTH;
424     }
425     if (IsInNodeRegion(DynamicCast<FrameNode>(contentNode->GetChildAtIndex(dayIndex_)), location)) {
426         return CalendarPickerSelectedType::DAY;
427     }
428 
429     auto buttonFlexNode = AceType::DynamicCast<FrameNode>(host->GetLastChild());
430     CHECK_NULL_RETURN(buttonFlexNode, CalendarPickerSelectedType::OTHER);
431     if (IsInNodeRegion(DynamicCast<FrameNode>(buttonFlexNode->GetChildAtIndex(ADD_BUTTON_INDEX)), location)) {
432         return CalendarPickerSelectedType::ADDBTN;
433     }
434     if (IsInNodeRegion(DynamicCast<FrameNode>(buttonFlexNode->GetChildAtIndex(SUB_BUTTON_INDEX)), location)) {
435         return CalendarPickerSelectedType::SUBBTN;
436     }
437     return CalendarPickerSelectedType::OTHER;
438 }
439 
IsInNodeRegion(const RefPtr<FrameNode> & node,const PointF & point)440 bool CalendarPickerPattern::IsInNodeRegion(const RefPtr<FrameNode>& node, const PointF& point)
441 {
442     CHECK_NULL_RETURN(node, false);
443     auto rect = node->GetTransformRectRelativeToWindow();
444     return rect.IsInRegion(point);
445 }
446 
ReportChangeEvent(const std::string & compName,const std::string & eventName,const std::string & eventData)447 bool CalendarPickerPattern::ReportChangeEvent(const std::string& compName,
448     const std::string& eventName, const std::string& eventData)
449 {
450     auto host = GetHost();
451     CHECK_NULL_RETURN(host, false);
452     PickerDate pickerDate;
453     CHECK_NULL_RETURN(CalendarDialogView::GetReportChangeEventDate(pickerDate, eventData), false);
454     CHECK_NULL_RETURN(CalendarDialogView::CanReportChangeEvent(reportedPickerDate_, pickerDate), false);
455     return CalendarDialogView::ReportChangeEvent(host->GetId(), compName, eventName, pickerDate);
456 }
457 
FireChangeEvents(const std::string & info)458 void CalendarPickerPattern::FireChangeEvents(const std::string& info)
459 {
460     ReportChangeEvent("CalendarPicker", "onChange", info);
461     auto eventHub = GetOrCreateEventHub<CalendarPickerEventHub>();
462     CHECK_NULL_VOID(eventHub);
463     eventHub->UpdateInputChangeEvent(info);
464     eventHub->UpdateOnChangeEvent(info);
465     eventHub->UpdateChangeEvent(info);
466 }
467 
ShowDialog()468 void CalendarPickerPattern::ShowDialog()
469 {
470     if (IsDialogShow()) {
471         return;
472     }
473     auto host = GetHost();
474     CHECK_NULL_VOID(host);
475     auto pipeline = host->GetContext();
476     CHECK_NULL_VOID(pipeline);
477     auto overlayManager = pipeline->GetOverlayManager();
478 
479     std::map<std::string, NG::DialogEvent> dialogEvent;
480     auto changeId = [weak = WeakClaim(this)](const std::string& info) {
481         auto pattern = weak.Upgrade();
482         CHECK_NULL_VOID(pattern);
483         pattern->ReportChangeEvent("CalendarPicker", "onChange", info);
484         pattern->SetDate(info);
485     };
486     auto acceptId = [weak = WeakClaim(this)](const std::string& /* info */) {
487         auto pattern = weak.Upgrade();
488         CHECK_NULL_VOID(pattern);
489         pattern->SetDialogShow(false);
490     };
491     dialogEvent["changeId"] = changeId;
492     dialogEvent["acceptId"] = acceptId;
493     std::map<std::string, NG::DialogGestureEvent> dialogCancelEvent;
494     auto cancelId = [weak = WeakClaim(this)](const GestureEvent& /* info */) {
495         auto pattern = weak.Upgrade();
496         CHECK_NULL_VOID(pattern);
497         pattern->SetDialogShow(false);
498     };
499     dialogCancelEvent["cancelId"] = cancelId;
500     calendarData_.entryNode = AceType::DynamicCast<FrameNode>(host);
501     calendarData_.markToday = isMarkToday_;
502     DialogProperties properties;
503     InitDialogProperties(properties);
504     overlayManager->ShowCalendarDialog(properties, calendarData_, dialogEvent, dialogCancelEvent);
505     SetDialogShow(true);
506 }
507 
InitOnKeyEvent()508 void CalendarPickerPattern::InitOnKeyEvent()
509 {
510     auto host = GetHost();
511     CHECK_NULL_VOID(host);
512     auto focusHub = host->GetOrCreateFocusHub();
513     focusHub->SetIsFocusOnTouch(true);
514     auto keyTask = [weak = WeakClaim(this)](const KeyEvent& keyEvent) -> bool {
515         auto pattern = weak.Upgrade();
516         CHECK_NULL_RETURN(pattern, false);
517         return pattern->HandleKeyEvent(keyEvent);
518     };
519     focusHub->SetOnKeyEventInternal(std::move(keyTask));
520 
521     auto blurTask = [weak = WeakClaim(this)]() {
522         auto pattern = weak.Upgrade();
523         CHECK_NULL_VOID(pattern);
524         pattern->HandleBlurEvent();
525     };
526     focusHub->SetOnBlurInternal(std::move(blurTask));
527 }
528 
HandleBlurEvent()529 void CalendarPickerPattern::HandleBlurEvent()
530 {
531     if (IsDialogShow()) {
532         return;
533     }
534     selected_ = CalendarPickerSelectedType::OTHER;
535     ResetTextState();
536 }
537 
HandleKeyEvent(const KeyEvent & event)538 bool CalendarPickerPattern::HandleKeyEvent(const KeyEvent& event)
539 {
540     if (event.action != KeyAction::DOWN && (event.code != KeyCode::KEY_TAB || !isFirtFocus_)) {
541         return false;
542     }
543     if (event.IsNumberKey()) {
544         return HandleNumberKeyEvent(event);
545     }
546     return HandleFocusEvent(event);
547 }
548 
HandleFocusEvent(const KeyEvent & event)549 bool CalendarPickerPattern::HandleFocusEvent(const KeyEvent& event)
550 {
551     auto host = GetHost();
552     CHECK_NULL_RETURN(host, false);
553 
554     switch (event.code) {
555         case KeyCode::KEY_TAB: {
556             ResetTextState();
557             if (isFirtFocus_) {
558                 selected_ = CalendarPickerSelectedType::YEAR;
559                 HandleTextFocusEvent(yearIndex_);
560                 if (!IsDialogShow()) {
561                     ShowDialog();
562                 }
563                 isFirtFocus_ = false;
564                 return true;
565             }
566             if (selected_ != CalendarPickerSelectedType::OTHER) {
567                 selected_ = CalendarPickerSelectedType::OTHER;
568                 isFirtFocus_ = true;
569                 return HandleBlurEvent(event);
570             }
571             return false;
572         }
573         case KeyCode::KEY_DPAD_LEFT: {
574             if (selected_ == CalendarPickerSelectedType::DAY) {
575                 ResetTextState();
576                 selected_ = CalendarPickerSelectedType::MONTH;
577                 HandleTextFocusEvent(monthIndex_);
578             } else if (selected_ == CalendarPickerSelectedType::MONTH) {
579                 ResetTextState();
580                 selected_ = CalendarPickerSelectedType::YEAR;
581                 HandleTextFocusEvent(yearIndex_);
582             }
583             return true;
584         }
585         case KeyCode::KEY_DPAD_RIGHT: {
586             if (selected_ == CalendarPickerSelectedType::YEAR) {
587                 ResetTextState();
588                 selected_ = CalendarPickerSelectedType::MONTH;
589                 HandleTextFocusEvent(monthIndex_);
590             } else if (selected_ == CalendarPickerSelectedType::MONTH) {
591                 ResetTextState();
592                 selected_ = CalendarPickerSelectedType::DAY;
593                 HandleTextFocusEvent(dayIndex_);
594             }
595             return true;
596         }
597         case KeyCode::KEY_DPAD_UP: {
598             if (!isFirtFocus_ || selected_ != CalendarPickerSelectedType::OTHER) {
599                 HandleAddButtonClick();
600             }
601             return true;
602         }
603         case KeyCode::KEY_DPAD_DOWN: {
604             if (!isFirtFocus_ || selected_ != CalendarPickerSelectedType::OTHER) {
605                 HandleSubButtonClick();
606             }
607             return true;
608         }
609         case KeyCode::KEY_MOVE_HOME: {
610             ResetTextState();
611             selected_ = CalendarPickerSelectedType::YEAR;
612             HandleTextFocusEvent(yearIndex_);
613             return true;
614         }
615         case KeyCode::KEY_MOVE_END: {
616             ResetTextState();
617             selected_ = CalendarPickerSelectedType::DAY;
618             HandleTextFocusEvent(dayIndex_);
619             return true;
620         }
621         case KeyCode::KEY_SPACE:
622         case KeyCode::KEY_NUMPAD_ENTER:
623         case KeyCode::KEY_ENTER: {
624             if (!IsDialogShow()) {
625                 ShowDialog();
626             }
627             return true;
628         }
629         default:
630             break;
631     }
632     return false;
633 }
634 
HandleBlurEvent(const KeyEvent & event)635 bool CalendarPickerPattern::HandleBlurEvent(const KeyEvent& event)
636 {
637     auto host = GetHost();
638     CHECK_NULL_RETURN(host, false);
639     auto contentNode = AceType::DynamicCast<FrameNode>(host->GetFirstChild());
640     CHECK_NULL_RETURN(contentNode, false);
641     auto textFrameNode = DynamicCast<FrameNode>(contentNode->GetChildAtIndex(yearIndex_));
642     CHECK_NULL_RETURN(textFrameNode, false);
643     auto focusHub = textFrameNode->GetOrCreateFocusHub();
644     CHECK_NULL_RETURN(focusHub, false);
645     return focusHub->HandleEvent(event);
646 }
647 
HandleYearKeyWaitingEvent(const uint32_t number,const std::function<void ()> & task,const std::function<void ()> & zeroStartTask)648 bool CalendarPickerPattern::HandleYearKeyWaitingEvent(
649     const uint32_t number, const std::function<void()>& task, const std::function<void()>& zeroStartTask)
650 {
651     auto json = JsonUtil::ParseJsonString(GetEntryDateInfo());
652     if (yearPrefixZeroCount_ > 0 && yearPrefixZeroCount_ < YEAR_LENTH - 1 && number == 0 &&
653         yearEnterCount_ == yearPrefixZeroCount_ + 1) {
654         yearPrefixZeroCount_++;
655         PostTaskToUI(std::move(zeroStartTask), "ArkUICalendarPickerYearKeyWaitingZeroStart");
656         return true;
657     } else if (yearPrefixZeroCount_ >= YEAR_LENTH - 1 && number == 0) {
658         yearPrefixZeroCount_ = 0;
659         yearEnterCount_ = 0;
660         isKeyWaiting_ = false;
661         return false;
662     }
663 
664     auto newYear = json->GetUInt("year") * 10 + number;
665 
666     if (yearPrefixZeroCount_ > 0 && yearEnterCount_ == yearPrefixZeroCount_ + 1) {
667         newYear = number;
668     }
669     if (yearEnterCount_ < YEAR_LENTH) {
670         json->Replace("year", static_cast<int32_t>(newYear));
671         SetDate(json->ToString());
672         PostTaskToUI(std::move(task), "ArkUICalendarPickerYearKeyWaitingChange");
673         return true;
674     }
675     newYear = std::max(newYear, MIN_YEAR);
676     newYear = std::min(newYear, MAX_YEAR);
677     json->Replace("year", static_cast<int32_t>(newYear));
678     auto maxDay = PickerDate::GetMaxDay(newYear, json->GetUInt("month"));
679     if (json->GetUInt("day") > maxDay) {
680         json->Replace("day", static_cast<int32_t>(maxDay));
681     }
682     SetDate(json->ToString());
683     FireChangeEvents(json->ToString());
684     if (yearEnterCount_ >= YEAR_LENTH) {
685         yearPrefixZeroCount_ = 0;
686         yearEnterCount_ = 0;
687     }
688     isKeyWaiting_ = false;
689     return true;
690 }
691 
HandleYearKeyEvent(uint32_t number)692 bool CalendarPickerPattern::HandleYearKeyEvent(uint32_t number)
693 {
694     auto json = JsonUtil::ParseJsonString(GetEntryDateInfo());
695     auto taskCallback = [weak = WeakClaim(this)]() {
696         auto pattern = weak.Upgrade();
697         CHECK_NULL_VOID(pattern);
698         pattern->HandleTaskCallback();
699     };
700     auto zeroStartTaskCallback = [weak = WeakClaim(this)]() {
701         auto pattern = weak.Upgrade();
702         CHECK_NULL_VOID(pattern);
703         pattern->HandleTaskCallback();
704     };
705     if (yearEnterCount_ < YEAR_LENTH) {
706         yearEnterCount_++;
707     } else {
708         return false;
709     }
710     if (isKeyWaiting_) {
711         return HandleYearKeyWaitingEvent(number, taskCallback, zeroStartTaskCallback);
712     } else {
713         if (number == 0) {
714             yearPrefixZeroCount_++;
715             PostTaskToUI(std::move(zeroStartTaskCallback), "ArkUICalendarPickerYearZeroStart");
716             isKeyWaiting_ = true;
717         } else {
718             json->Replace("year", static_cast<int32_t>(number));
719             SetDate(json->ToString());
720             PostTaskToUI(std::move(taskCallback), "ArkUICalendarPickerYearChange");
721             isKeyWaiting_ = true;
722         }
723     }
724     return true;
725 }
726 
HandleMonthKeyEvent(uint32_t number)727 bool CalendarPickerPattern::HandleMonthKeyEvent(uint32_t number)
728 {
729     auto json = JsonUtil::ParseJsonString(GetEntryDateInfo());
730     auto taskCallback = [weak = WeakClaim(this)]() {
731         auto pattern = weak.Upgrade();
732         CHECK_NULL_VOID(pattern);
733         pattern->HandleTaskCallback();
734     };
735     auto zeroStartTaskCallback = [weak = WeakClaim(this)]() {
736         auto pattern = weak.Upgrade();
737         CHECK_NULL_VOID(pattern);
738         pattern->HandleTaskCallback();
739     };
740 
741     if (isKeyWaiting_) {
742         if (monthPrefixZeroCount_ == 1 && number == 0) {
743             monthPrefixZeroCount_ = 0;
744             isKeyWaiting_ = false;
745             return false;
746         }
747 
748         auto newMonth = json->GetUInt("month") * 10 + number;
749 
750         if (monthPrefixZeroCount_ == 1) {
751             newMonth = number;
752         }
753         if (newMonth < 1 || newMonth > MAX_MONTH) {
754             return true;
755         }
756         json->Replace("month", static_cast<int32_t>(newMonth));
757         auto maxDay = PickerDate::GetMaxDay(json->GetUInt("year"), newMonth);
758         if (json->GetUInt("day") > maxDay) {
759             json->Replace("day", static_cast<int32_t>(maxDay));
760         }
761         SetDate(json->ToString());
762         FireChangeEvents(json->ToString());
763         isKeyWaiting_ = false;
764         monthPrefixZeroCount_ = 0;
765     } else {
766         if (number == 0) {
767             monthPrefixZeroCount_++;
768             PostTaskToUI(std::move(zeroStartTaskCallback), "ArkUICalendarPickerMonthZeroStart");
769             isKeyWaiting_ = true;
770         } else {
771             json->Replace("month", static_cast<int32_t>(number));
772             SetDate(json->ToString());
773 
774             PostTaskToUI(std::move(taskCallback), "ArkUICalendarPickerMonthChange");
775             isKeyWaiting_ = true;
776         }
777     }
778 
779     return true;
780 }
781 
HandleDayKeyEvent(uint32_t number)782 bool CalendarPickerPattern::HandleDayKeyEvent(uint32_t number)
783 {
784     auto json = JsonUtil::ParseJsonString(GetEntryDateInfo());
785     auto taskCallback = [weak = WeakClaim(this)]() {
786         auto pattern = weak.Upgrade();
787         CHECK_NULL_VOID(pattern);
788         pattern->HandleTaskCallback();
789     };
790     auto zeroStartTaskCallback = [weak = WeakClaim(this)]() {
791         auto pattern = weak.Upgrade();
792         CHECK_NULL_VOID(pattern);
793         pattern->HandleTaskCallback();
794     };
795 
796     if (isKeyWaiting_) {
797         if (dayPrefixZeroCount_ == 1 && number == 0) {
798             dayPrefixZeroCount_ = 0;
799             isKeyWaiting_ = false;
800             return false;
801         }
802 
803         auto newDay = json->GetUInt("day") * 10 + number;
804 
805         if (dayPrefixZeroCount_ == 1) {
806             newDay = number;
807         }
808         if (newDay <= PickerDate::GetMaxDay(json->GetUInt("year"), json->GetUInt("month"))) {
809             json->Replace("day", static_cast<int32_t>(newDay));
810             SetDate(json->ToString());
811             FireChangeEvents(json->ToString());
812             isKeyWaiting_ = false;
813             dayPrefixZeroCount_ = 0;
814         }
815     } else {
816         if (number == 0) {
817             dayPrefixZeroCount_++;
818             PostTaskToUI(std::move(zeroStartTaskCallback), "ArkUICalendarPickerDayZeroStart");
819             isKeyWaiting_ = true;
820         } else {
821             json->Replace("day", static_cast<int32_t>(number));
822             SetDate(json->ToString());
823 
824             PostTaskToUI(std::move(taskCallback), "ArkUICalendarPickerDayChange");
825             isKeyWaiting_ = true;
826         }
827     }
828 
829     return true;
830 }
831 
HandleNumberKeyEvent(const KeyEvent & event)832 bool CalendarPickerPattern::HandleNumberKeyEvent(const KeyEvent& event)
833 {
834     if (!event.IsNumberKey()) {
835         return false;
836     }
837 
838     uint32_t number = 0;
839     if (KeyCode::KEY_0 <= event.code && event.code <= KeyCode::KEY_9) {
840         number = static_cast<uint32_t>(event.code) - static_cast<uint32_t>(KeyCode::KEY_0);
841     }
842     if (KeyCode::KEY_NUMPAD_0 <= event.code && event.code <= KeyCode::KEY_NUMPAD_9) {
843         number = static_cast<uint32_t>(event.code) - static_cast<uint32_t>(KeyCode::KEY_NUMPAD_0);
844     }
845 
846     switch (GetSelectedType()) {
847         case CalendarPickerSelectedType::YEAR:
848             return HandleYearKeyEvent(number);
849         case CalendarPickerSelectedType::MONTH:
850             return HandleMonthKeyEvent(number);
851         case CalendarPickerSelectedType::DAY:
852             return HandleDayKeyEvent(number);
853         default:
854             break;
855     }
856     return false;
857 }
858 
PostTaskToUI(const std::function<void ()> & task,const std::string & name)859 void CalendarPickerPattern::PostTaskToUI(const std::function<void()>& task, const std::string& name)
860 {
861     CHECK_NULL_VOID(task);
862     auto host = GetHost();
863     CHECK_NULL_VOID(host);
864     auto context = host->GetContext();
865     CHECK_NULL_VOID(context);
866 
867     auto taskExecutor = context->GetTaskExecutor();
868     CHECK_NULL_VOID(taskExecutor);
869 
870     taskCount_++;
871     taskExecutor->PostDelayedTask(task, TaskExecutor::TaskType::UI, DELAY_TIME, name);
872 }
873 
HandleTaskCallback()874 void CalendarPickerPattern::HandleTaskCallback()
875 {
876     taskCount_--;
877     if (taskCount_ > 0) {
878         return;
879     } else if (taskCount_ < 0) {
880         taskCount_ = 0;
881     }
882     if (!isKeyWaiting_) {
883         return;
884     }
885 
886     auto json = JsonUtil::ParseJsonString(GetEntryDateInfo());
887     auto newYear = json->GetUInt("year");
888     newYear = std::max(newYear, MIN_YEAR);
889     newYear = std::min(newYear, MAX_YEAR);
890     json->Replace("year", static_cast<int32_t>(newYear));
891     auto maxDay = PickerDate::GetMaxDay(newYear, json->GetUInt("month"));
892     if (json->GetUInt("day") > maxDay) {
893         json->Replace("day", static_cast<int32_t>(maxDay));
894     }
895     SetDate(json->ToString());
896     FireChangeEvents(json->ToString());
897     yearEnterCount_ = 0;
898     yearPrefixZeroCount_ = 0;
899     monthPrefixZeroCount_ = 0;
900     dayPrefixZeroCount_ = 0;
901     isKeyWaiting_ = false;
902 }
903 
HandleZeroStartTaskCallback()904 void CalendarPickerPattern::HandleZeroStartTaskCallback()
905 {
906     taskCount_--;
907     if (taskCount_ > 0) {
908         return;
909     } else if (taskCount_ < 0) {
910         taskCount_ = 0;
911     }
912     if (!isKeyWaiting_) {
913         return;
914     }
915 
916     yearEnterCount_ = 0;
917     yearPrefixZeroCount_ = 0;
918     monthPrefixZeroCount_ = 0;
919     dayPrefixZeroCount_ = 0;
920     isKeyWaiting_ = false;
921 }
922 
HandleTextFocusEvent(int32_t index)923 void CalendarPickerPattern::HandleTextFocusEvent(int32_t index)
924 {
925     auto host = GetHost();
926     CHECK_NULL_VOID(host);
927     auto contentNode = AceType::DynamicCast<FrameNode>(host->GetFirstChild());
928     CHECK_NULL_VOID(contentNode);
929     auto textFrameNode = DynamicCast<FrameNode>(contentNode->GetChildAtIndex(index));
930     CHECK_NULL_VOID(textFrameNode);
931     auto pipelineContext = host->GetContext();
932     CHECK_NULL_VOID(pipelineContext);
933     RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
934     CHECK_NULL_VOID(theme);
935     textFrameNode->GetRenderContext()->UpdateBackgroundColor(theme->GetSelectBackgroundColor());
936     textFrameNode->GetRenderContext()->UpdateForegroundColor(Color::WHITE);
937     textFrameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
938     FlushAddAndSubButton();
939 }
940 
HandleTextHoverEvent(bool state,int32_t index)941 void CalendarPickerPattern::HandleTextHoverEvent(bool state, int32_t index)
942 {
943     if ((GetSelectedType() == CalendarPickerSelectedType::YEAR && index == yearIndex_) ||
944         (GetSelectedType() == CalendarPickerSelectedType::MONTH && index == monthIndex_) ||
945         (GetSelectedType() == CalendarPickerSelectedType::DAY && index == dayIndex_)) {
946         return;
947     }
948     auto host = GetHost();
949     CHECK_NULL_VOID(host);
950     auto contentNode = AceType::DynamicCast<FrameNode>(host->GetFirstChild());
951     CHECK_NULL_VOID(contentNode);
952     auto textFrameNode = DynamicCast<FrameNode>(contentNode->GetChildAtIndex(index));
953     CHECK_NULL_VOID(textFrameNode);
954     auto pipelineContext = host->GetContext();
955     CHECK_NULL_VOID(pipelineContext);
956     RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
957     CHECK_NULL_VOID(theme);
958     if (state) {
959         textFrameNode->GetRenderContext()->UpdateBackgroundColor(theme->GetBackgroundHoverColor());
960     } else {
961         textFrameNode->GetRenderContext()->UpdateBackgroundColor(Color::TRANSPARENT);
962         auto layoutProperty = host->GetLayoutProperty<CalendarPickerLayoutProperty>();
963         CHECK_NULL_VOID(layoutProperty);
964         textFrameNode->GetRenderContext()->UpdateForegroundColor(
965             layoutProperty->GetColor().value_or(theme->GetEntryFontColor()));
966     }
967 }
968 
FlushAddAndSubButton()969 void CalendarPickerPattern::FlushAddAndSubButton()
970 {
971     auto host = GetHost();
972     CHECK_NULL_VOID(host);
973     auto buttonFlexNode = AceType::DynamicCast<FrameNode>(host->GetLastChild());
974     CHECK_NULL_VOID(buttonFlexNode);
975 
976     auto pipelineContext = host->GetContext();
977     CHECK_NULL_VOID(pipelineContext);
978     RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
979     CHECK_NULL_VOID(theme);
980     int32_t buttonIndex = 0;
981     for (const auto& child : buttonFlexNode->GetChildren()) {
982         CHECK_NULL_VOID(child);
983         auto buttonNode = AceType::DynamicCast<FrameNode>(child);
984         auto image = buttonNode->GetChildren().front();
985         CHECK_NULL_VOID(image);
986         auto imageNode = AceType::DynamicCast<FrameNode>(image);
987         auto imageLayoutProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
988         CHECK_NULL_VOID(imageLayoutProperty);
989         auto imageInfo = imageLayoutProperty->GetImageSourceInfo();
990         auto buttonColor = theme->GetEntryArrowColor();
991         if (!IsAddOrSubButtonEnable(buttonIndex)) {
992             buttonColor = buttonColor.ChangeOpacity(DISABLE_ALPHA);
993         }
994         imageInfo->SetFillColor(buttonColor);
995         imageLayoutProperty->UpdateImageSourceInfo(imageInfo.value());
996         imageNode->MarkModifyDone();
997         buttonIndex++;
998     }
999 }
1000 
IsAddOrSubButtonEnable(int32_t buttonIndex)1001 bool CalendarPickerPattern::IsAddOrSubButtonEnable(int32_t buttonIndex)
1002 {
1003     PickerDate dateObj = calendarData_.selectedDate;
1004     if (buttonIndex == ADD_BUTTON_INDEX) {
1005         NextDateBySelectedType(dateObj);
1006         dateObj = PickerDate::GetAvailableNextDay(
1007             dateObj, calendarData_.startDate, calendarData_.endDate, calendarData_.disabledDateRange, true);
1008     }
1009     if (buttonIndex == SUB_BUTTON_INDEX) {
1010         PrevDateBySelectedType(dateObj);
1011         dateObj = PickerDate::GetAvailableNextDay(
1012             dateObj, calendarData_.startDate, calendarData_.endDate, calendarData_.disabledDateRange, false);
1013     }
1014     return dateObj.GetYear() > 0;
1015 }
1016 
HandleButtonHoverEvent(bool state,int32_t index)1017 void CalendarPickerPattern::HandleButtonHoverEvent(bool state, int32_t index)
1018 {
1019     auto host = GetHost();
1020     CHECK_NULL_VOID(host);
1021     auto buttonFlexNode = AceType::DynamicCast<FrameNode>(host->GetLastChild());
1022     CHECK_NULL_VOID(buttonFlexNode);
1023     auto buttonFrameNode = DynamicCast<FrameNode>(buttonFlexNode->GetChildAtIndex(index));
1024     CHECK_NULL_VOID(buttonFrameNode);
1025     buttonFrameNode->GetRenderContext()->AnimateHoverEffectBoard(state);
1026 }
1027 
HandleButtonTouchEvent(bool isPressed,int32_t index)1028 void CalendarPickerPattern::HandleButtonTouchEvent(bool isPressed, int32_t index)
1029 {
1030     auto host = GetHost();
1031     CHECK_NULL_VOID(host);
1032     auto buttonFlexNode = AceType::DynamicCast<FrameNode>(host->GetLastChild());
1033     CHECK_NULL_VOID(buttonFlexNode);
1034     auto buttonFrameNode = DynamicCast<FrameNode>(buttonFlexNode->GetChildAtIndex(index));
1035     CHECK_NULL_VOID(buttonFrameNode);
1036     auto pipelineContext = host->GetContext();
1037     CHECK_NULL_VOID(pipelineContext);
1038     RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
1039     CHECK_NULL_VOID(theme);
1040     if (isPressed) {
1041         buttonFrameNode->GetRenderContext()->UpdateBackgroundColor(theme->GetBackgroundPressColor());
1042     } else {
1043         buttonFrameNode->GetRenderContext()->UpdateBackgroundColor(Color::TRANSPARENT);
1044     }
1045 }
1046 
NextDateBySelectedType(PickerDate & dateObj)1047 void CalendarPickerPattern::NextDateBySelectedType(PickerDate& dateObj)
1048 {
1049     switch (GetSelectedType()) {
1050         case CalendarPickerSelectedType::YEAR: {
1051             dateObj.SetYear(dateObj.GetYear() == MAX_YEAR ? MIN_YEAR : dateObj.GetYear() + 1);
1052             auto maxDay = PickerDate::GetMaxDay(dateObj.GetYear(), dateObj.GetMonth());
1053             if (maxDay < dateObj.GetDay()) {
1054                 dateObj.SetDay(maxDay);
1055             }
1056             break;
1057         }
1058         case CalendarPickerSelectedType::MONTH: {
1059             dateObj.SetMonth(dateObj.GetMonth() % MAX_MONTH + 1);
1060             if (dateObj.GetMonth() == 1) {
1061                 dateObj.SetYear(dateObj.GetYear() == MAX_YEAR ? MIN_YEAR : dateObj.GetYear() + 1);
1062             }
1063             auto maxDay = PickerDate::GetMaxDay(dateObj.GetYear(), dateObj.GetMonth());
1064             if (maxDay < dateObj.GetDay()) {
1065                 dateObj.SetDay(maxDay);
1066             }
1067             break;
1068         }
1069         case CalendarPickerSelectedType::DAY:
1070         default: {
1071             auto maxDay = PickerDate::GetMaxDay(dateObj.GetYear(), dateObj.GetMonth());
1072             if (maxDay > dateObj.GetDay()) {
1073                 dateObj.SetDay(dateObj.GetDay() + 1);
1074                 break;
1075             }
1076             dateObj.SetDay(1);
1077             if (dateObj.GetMonth() < MAX_MONTH) {
1078                 dateObj.SetMonth(dateObj.GetMonth() + 1);
1079                 break;
1080             }
1081             dateObj.SetMonth(1);
1082             dateObj.SetYear(dateObj.GetYear() == MAX_YEAR ? MIN_YEAR : dateObj.GetYear() + 1);
1083             break;
1084         }
1085     }
1086 }
1087 
PrevDateBySelectedType(PickerDate & dateObj)1088 void CalendarPickerPattern::PrevDateBySelectedType(PickerDate& dateObj)
1089 {
1090     switch (GetSelectedType()) {
1091         case CalendarPickerSelectedType::YEAR: {
1092             auto getYear = dateObj.GetYear();
1093             dateObj.SetYear(dateObj.GetYear() == MIN_YEAR ? MAX_YEAR : (getYear > 0 ? getYear - 1 : 0));
1094             auto maxDay = PickerDate::GetMaxDay(dateObj.GetYear(), dateObj.GetMonth());
1095             if (maxDay < dateObj.GetDay())
1096                 dateObj.SetDay(maxDay);
1097             break;
1098         }
1099         case CalendarPickerSelectedType::MONTH: {
1100             auto getMonth = dateObj.GetMonth();
1101             auto newMonth = getMonth > 0 ? getMonth - 1 : 0;
1102             if (newMonth == 0) {
1103                 dateObj.SetMonth(MAX_MONTH);
1104                 auto getYear = dateObj.GetYear();
1105                 dateObj.SetYear(dateObj.GetYear() == MIN_YEAR ? MAX_YEAR : (getYear > 0 ? getYear - 1 : 0));
1106             } else {
1107                 dateObj.SetMonth(newMonth);
1108             }
1109             auto maxDay = PickerDate::GetMaxDay(dateObj.GetYear(), dateObj.GetMonth());
1110             if (maxDay < dateObj.GetDay())
1111                 dateObj.SetDay(maxDay);
1112             break;
1113         }
1114         case CalendarPickerSelectedType::DAY:
1115         default: {
1116             if (dateObj.GetDay() > 1) {
1117                 dateObj.SetDay(dateObj.GetDay() - 1);
1118                 break;
1119             }
1120             if (dateObj.GetMonth() == 1) {
1121                 dateObj.SetMonth(MAX_MONTH);
1122                 auto getYear = dateObj.GetYear();
1123                 dateObj.SetYear(dateObj.GetYear() == MIN_YEAR ? MAX_YEAR : (getYear > 0 ? getYear - 1 : 0));
1124             } else {
1125                 auto getMonth = dateObj.GetMonth();
1126                 dateObj.SetMonth(getMonth > 0 ? getMonth - 1 : 0);
1127             }
1128             dateObj.SetDay(PickerDate::GetMaxDay(dateObj.GetYear(), dateObj.GetMonth()));
1129             break;
1130         }
1131     }
1132 }
1133 
HandleAddButtonClick()1134 void CalendarPickerPattern::HandleAddButtonClick()
1135 {
1136     auto json = JsonUtil::ParseJsonString(GetEntryDateInfo());
1137     PickerDate dateObj = PickerDate(json->GetUInt("year"), json->GetUInt("month"), json->GetUInt("day"));
1138     NextDateBySelectedType(dateObj);
1139     dateObj = PickerDate::GetAvailableNextDay(
1140         dateObj, calendarData_.startDate, calendarData_.endDate, calendarData_.disabledDateRange, true);
1141     if (dateObj.GetYear() > 0) {
1142         if (GetSelectedType() != CalendarPickerSelectedType::YEAR &&
1143             GetSelectedType() != CalendarPickerSelectedType::MONTH) {
1144             SetSelectedType(CalendarPickerSelectedType::DAY);
1145         }
1146         SetDate(dateObj.ToString(true));
1147         FireChangeEvents(dateObj.ToString(true));
1148         FlushAddAndSubButton();
1149     }
1150 }
1151 
HandleSubButtonClick()1152 void CalendarPickerPattern::HandleSubButtonClick()
1153 {
1154     auto json = JsonUtil::ParseJsonString(GetEntryDateInfo());
1155     PickerDate dateObj = PickerDate(json->GetUInt("year"), json->GetUInt("month"), json->GetUInt("day"));
1156     PrevDateBySelectedType(dateObj);
1157     dateObj = PickerDate::GetAvailableNextDay(
1158         dateObj, calendarData_.startDate, calendarData_.endDate, calendarData_.disabledDateRange, false);
1159     if (dateObj.GetYear() > 0) {
1160         if (GetSelectedType() != CalendarPickerSelectedType::YEAR &&
1161             GetSelectedType() != CalendarPickerSelectedType::MONTH) {
1162             SetSelectedType(CalendarPickerSelectedType::DAY);
1163         }
1164         SetDate(dateObj.ToString(true));
1165         FireChangeEvents(dateObj.ToString(true));
1166         FlushAddAndSubButton();
1167     }
1168 }
1169 
HandleEnable()1170 void CalendarPickerPattern::HandleEnable()
1171 {
1172     auto host = GetHost();
1173     CHECK_NULL_VOID(host);
1174     auto eventHub = host->GetOrCreateEventHub<EventHub>();
1175     CHECK_NULL_VOID(eventHub);
1176     auto enabled = eventHub->IsEnabled();
1177     auto renderContext = host->GetRenderContext();
1178     CHECK_NULL_VOID(renderContext);
1179     auto originalOpacity = renderContext->GetOpacityValue(1.0);
1180     renderContext->OnOpacityUpdate(enabled ? originalOpacity : DISABLE_ALPHA * originalOpacity);
1181 }
1182 
CalculateDialogOffset()1183 OffsetF CalendarPickerPattern::CalculateDialogOffset()
1184 {
1185     UpdateEdgeAlign();
1186     auto host = GetHost();
1187     CHECK_NULL_RETURN(host, OffsetF());
1188     auto layoutProperty = host->GetLayoutProperty<CalendarPickerLayoutProperty>();
1189     CHECK_NULL_RETURN(layoutProperty, OffsetF());
1190     float x = 0.0f;
1191     float y = 0.0f;
1192     auto hostOffset = host->GetOffsetRelativeToWindow();
1193     auto hostSize = host->GetGeometryNode()->GetFrameSize();
1194 
1195     auto pipelineContext = host->GetContext();
1196     CHECK_NULL_RETURN(pipelineContext, OffsetF());
1197     RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
1198     CHECK_NULL_RETURN(theme, OffsetF());
1199 
1200     float dialogHeight = pipelineContext->GetRootHeight();
1201     if (IsContainerModal()) {
1202         auto rootNode = pipelineContext->GetRootElement();
1203         CHECK_NULL_RETURN(rootNode, OffsetF());
1204         auto containerNode = AceType::DynamicCast<FrameNode>(rootNode->GetChildren().front());
1205         CHECK_NULL_RETURN(containerNode, OffsetF());
1206         auto containerPattern = containerNode->GetPattern<ContainerModalPattern>();
1207         CHECK_NULL_RETURN(containerPattern, OffsetF());
1208         auto titleHeight = containerPattern->GetContainerModalTitleHeight();
1209         dialogHeight -= titleHeight;
1210         hostOffset -= OffsetF(0, titleHeight);
1211     }
1212 
1213     auto hostRect = RectF(hostOffset, hostSize);
1214     if (hostRect.Bottom() + (DIALOG_HEIGHT).ConvertToPx() > dialogHeight) {
1215         y = std::max(static_cast<float>(hostRect.Top() - (DIALOG_HEIGHT).ConvertToPx()), 0.0f);
1216     } else {
1217         y = hostRect.Bottom() + (theme->GetDialogMargin()).ConvertToPx();
1218     }
1219 
1220     CalendarEdgeAlign align = layoutProperty->GetDialogAlignType().value_or(CalendarEdgeAlign::EDGE_ALIGN_END);
1221     if (align == CalendarEdgeAlign::EDGE_ALIGN_START) {
1222         x = std::min(
1223             hostRect.Left(), static_cast<float>(pipelineContext->GetRootWidth() - (DIALOG_WIDTH).ConvertToPx()));
1224     } else if (align == CalendarEdgeAlign::EDGE_ALIGN_CENTER) {
1225         auto hostCenterX = (hostRect.Left() + hostRect.Right()) / 2;
1226         x = std::max(0.0f, static_cast<float>(hostCenterX - (DIALOG_WIDTH).ConvertToPx() / 2));
1227         x = std::min(x, static_cast<float>(pipelineContext->GetRootWidth() - (DIALOG_WIDTH).ConvertToPx()));
1228     } else {
1229         x = std::max(0.0f, static_cast<float>(hostRect.Right() - (DIALOG_WIDTH).ConvertToPx()));
1230     }
1231 
1232     auto offset = layoutProperty->GetDialogOffset().value_or(DimensionOffset());
1233 
1234     return OffsetF(x + offset.GetX().ConvertToPx(), y + offset.GetY().ConvertToPx());
1235 }
1236 
InitDialogProperties(DialogProperties & properties)1237 void CalendarPickerPattern::InitDialogProperties(DialogProperties& properties)
1238 {
1239     properties.customStyle = true;
1240     properties.maskColor = Color(0);
1241     properties.offset = DimensionOffset(CalculateDialogOffset());
1242     properties.alignment = DialogAlignment::TOP_START;
1243     auto cancelId = [weak = WeakClaim(this)]() {
1244         auto pattern = weak.Upgrade();
1245         CHECK_NULL_VOID(pattern);
1246         pattern->SetDialogShow(false);
1247     };
1248     properties.onCancel = cancelId;
1249 }
1250 
OnWindowSizeChanged(int32_t width,int32_t height,WindowSizeChangeReason type)1251 void CalendarPickerPattern::OnWindowSizeChanged(int32_t width, int32_t height, WindowSizeChangeReason type)
1252 {
1253     if (type != WindowSizeChangeReason::ROTATION && type != WindowSizeChangeReason::DRAG) {
1254         return;
1255     }
1256 
1257     auto host = GetHost();
1258     CHECK_NULL_VOID(host);
1259     host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1260 }
1261 
OnColorConfigurationUpdate()1262 void CalendarPickerPattern::OnColorConfigurationUpdate()
1263 {
1264     if (SystemProperties::ConfigChangePerform()) {
1265         auto host = GetHost();
1266         CHECK_NULL_VOID(host);
1267         auto pickerProperty = host->GetLayoutProperty<CalendarPickerLayoutProperty>();
1268         CHECK_NULL_VOID(pickerProperty);
1269         if (!pickerProperty->GetNormalTextColorSetByUser().value_or(false)) {
1270             auto pipelineContext = host->GetContext();
1271             CHECK_NULL_VOID(pipelineContext);
1272             auto calendarTheme = pipelineContext->GetTheme<CalendarTheme>(host->GetThemeScopeId());
1273             CHECK_NULL_VOID(calendarTheme);
1274             pickerProperty->UpdateColor(calendarTheme->GetEntryFontColor());
1275         }
1276     }
1277 
1278     if (IsDialogShow()) {
1279         return;
1280     }
1281     selected_ = CalendarPickerSelectedType::OTHER;
1282     ResetTextState();
1283 }
1284 
GetEntryDateInfo()1285 std::string CalendarPickerPattern::GetEntryDateInfo()
1286 {
1287     if (!HasContentNode()) {
1288         return "";
1289     }
1290     auto host = GetHost();
1291     CHECK_NULL_RETURN(host, "");
1292     auto contentNode = AceType::DynamicCast<FrameNode>(host->GetFirstChild());
1293     CHECK_NULL_RETURN(contentNode, "");
1294     auto json = JsonUtil::Create(true);
1295     auto yearNode = AceType::DynamicCast<FrameNode>(contentNode->GetChildAtIndex(yearIndex_));
1296     CHECK_NULL_RETURN(yearNode, "");
1297     auto textLayoutProperty = yearNode->GetLayoutProperty<TextLayoutProperty>();
1298     CHECK_NULL_RETURN(textLayoutProperty, "");
1299     json->Put("year",
1300         StringUtils::StringToInt(UtfUtils::Str16ToStr8(textLayoutProperty->GetContent().value_or(u"1970"))));
1301 
1302     auto monthNode = AceType::DynamicCast<FrameNode>(contentNode->GetChildAtIndex(monthIndex_));
1303     CHECK_NULL_RETURN(monthNode, "");
1304     textLayoutProperty = monthNode->GetLayoutProperty<TextLayoutProperty>();
1305     CHECK_NULL_RETURN(textLayoutProperty, "");
1306     json->Put("month",
1307         StringUtils::StringToInt(UtfUtils::Str16ToStr8(textLayoutProperty->GetContent().value_or(u"01"))));
1308 
1309     auto dayNode = AceType::DynamicCast<FrameNode>(contentNode->GetChildAtIndex(dayIndex_));
1310     CHECK_NULL_RETURN(dayNode, "");
1311     textLayoutProperty = dayNode->GetLayoutProperty<TextLayoutProperty>();
1312     CHECK_NULL_RETURN(textLayoutProperty, "");
1313     json->Put("day",
1314         StringUtils::StringToInt(UtfUtils::Str16ToStr8(textLayoutProperty->GetContent().value_or(u"01"))));
1315 
1316     return json->ToString();
1317 }
1318 
SetDate(const std::string & info)1319 void CalendarPickerPattern::SetDate(const std::string& info)
1320 {
1321     if (!HasContentNode()) {
1322         return;
1323     }
1324     auto host = GetHost();
1325     CHECK_NULL_VOID(host);
1326     auto contentNode = AceType::DynamicCast<FrameNode>(host->GetFirstChild());
1327     CHECK_NULL_VOID(contentNode);
1328     auto json = JsonUtil::ParseJsonString(info);
1329     auto selectedDate = PickerDate(json->GetUInt("year"), json->GetUInt("month"), json->GetUInt("day"));
1330     calendarData_.selectedDate =
1331         PickerDate::AdjustDateToRange(selectedDate, calendarData_.startDate, calendarData_.endDate);
1332     auto yearNode = AceType::DynamicCast<FrameNode>(contentNode->GetChildAtIndex(yearIndex_));
1333     CHECK_NULL_VOID(yearNode);
1334     auto textLayoutProperty = yearNode->GetLayoutProperty<TextLayoutProperty>();
1335     CHECK_NULL_VOID(textLayoutProperty);
1336     auto yearNum = json->GetUInt("year");
1337     auto yearStr = std::to_string(yearNum);
1338     yearStr = (yearNum < 1000 ? "0" : "") + yearStr;
1339     yearStr = (yearNum < 100 ? "0" : "") + yearStr;
1340     yearStr = (yearNum < 10 ? "0" : "") + yearStr;
1341     textLayoutProperty->UpdateContent(yearStr);
1342     yearNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1343 
1344     auto monthNode = AceType::DynamicCast<FrameNode>(contentNode->GetChildAtIndex(monthIndex_));
1345     CHECK_NULL_VOID(monthNode);
1346     textLayoutProperty = monthNode->GetLayoutProperty<TextLayoutProperty>();
1347     CHECK_NULL_VOID(textLayoutProperty);
1348     auto monthString = (json->GetUInt("month") < 10 ? "0" : "") + std::to_string(json->GetUInt("month"));
1349     textLayoutProperty->UpdateContent(monthString);
1350     monthNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1351 
1352     auto dayNode = AceType::DynamicCast<FrameNode>(contentNode->GetChildAtIndex(dayIndex_));
1353     CHECK_NULL_VOID(dayNode);
1354     textLayoutProperty = dayNode->GetLayoutProperty<TextLayoutProperty>();
1355     CHECK_NULL_VOID(textLayoutProperty);
1356     auto dayString = (json->GetUInt("day") < 10 ? "0" : "") + std::to_string(json->GetUInt("day"));
1357     textLayoutProperty->UpdateContent(dayString);
1358     dayNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1359     UpdateAccessibilityText();
1360     FlushAddAndSubButton();
1361 }
1362 
FlushTextStyle()1363 void CalendarPickerPattern::FlushTextStyle()
1364 {
1365     if (!HasContentNode()) {
1366         return;
1367     }
1368     auto host = GetHost();
1369     CHECK_NULL_VOID(host);
1370     auto layoutProperty = host->GetLayoutProperty<CalendarPickerLayoutProperty>();
1371     CHECK_NULL_VOID(layoutProperty);
1372     auto contentNode = AceType::DynamicCast<FrameNode>(host->GetFirstChild());
1373     CHECK_NULL_VOID(contentNode);
1374     int32_t len = static_cast<int32_t>(contentNode->GetChildren().size());
1375     for (int32_t i = 0; i < len; i++) {
1376         auto textNode = AceType::DynamicCast<FrameNode>(contentNode->GetChildAtIndex(i));
1377         CHECK_NULL_VOID(textNode);
1378         auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
1379         CHECK_NULL_VOID(textLayoutProperty);
1380 
1381         if (selected_ != CalendarPickerSelectedType::YEAR && selected_ != CalendarPickerSelectedType::MONTH &&
1382             selected_ != CalendarPickerSelectedType::DAY && layoutProperty->HasColor()) {
1383             ResetTextStateByNode(textNode);
1384         } else {
1385             SetSelectedType(selected_);
1386         }
1387         if (layoutProperty->HasFontSize()) {
1388             textLayoutProperty->UpdateFontSize(layoutProperty->GetFontSize().value());
1389         }
1390         if (layoutProperty->HasWeight()) {
1391             textLayoutProperty->UpdateFontWeight(layoutProperty->GetWeight().value());
1392         }
1393         textNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
1394     }
1395 }
1396 
SetSelectedType(CalendarPickerSelectedType type)1397 void CalendarPickerPattern::SetSelectedType(CalendarPickerSelectedType type)
1398 {
1399     selected_ = type;
1400     switch (selected_) {
1401         case CalendarPickerSelectedType::YEAR:
1402             ResetTextState();
1403             HandleTextFocusEvent(yearIndex_);
1404             break;
1405         case CalendarPickerSelectedType::MONTH:
1406             ResetTextState();
1407             HandleTextFocusEvent(monthIndex_);
1408             break;
1409         case CalendarPickerSelectedType::DAY:
1410             ResetTextState();
1411             HandleTextFocusEvent(dayIndex_);
1412             break;
1413         default:
1414             break;
1415     }
1416 }
1417 
IsContainerModal()1418 bool CalendarPickerPattern::IsContainerModal()
1419 {
1420     auto host = GetHost();
1421     CHECK_NULL_RETURN(host, false);
1422     auto pipelineContext = host->GetContext();
1423     CHECK_NULL_RETURN(pipelineContext, false);
1424     auto windowManager = pipelineContext->GetWindowManager();
1425     return pipelineContext->GetWindowModal() == WindowModal::CONTAINER_MODAL && windowManager &&
1426                             windowManager->GetWindowMode() == WindowMode::WINDOW_MODE_FLOATING;
1427 }
1428 
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const1429 void CalendarPickerPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
1430 {
1431     /* no fixed attr below, just return */
1432     if (filter.IsFastFilter()) {
1433         return;
1434     }
1435     json->PutExtAttr("markToday", calendarData_.markToday ? "true" : "false", filter);
1436     std::string disabledDateRangeStr = "";
1437     for (const auto& range : calendarData_.disabledDateRange) {
1438         disabledDateRangeStr += range.first.ToString(false) + "," + range.second.ToString(false) + ",";
1439     }
1440     if (!disabledDateRangeStr.empty() && disabledDateRangeStr.back() == ',') {
1441         disabledDateRangeStr.pop_back();
1442     }
1443     json->PutExtAttr("disabledDateRange", disabledDateRangeStr.c_str(), filter);
1444 
1445     if (calendarData_.startDate.ToDays() != PickerDate().ToDays()) {
1446         json->PutExtAttr("start", calendarData_.startDate.ToString(false).c_str(), filter);
1447     }
1448     if (calendarData_.endDate.ToDays() != PickerDate().ToDays()) {
1449         json->PutExtAttr("end", calendarData_.endDate.ToString(false).c_str(), filter);
1450     }
1451 }
1452 
SetMarkToday(bool isMarkToday)1453 void CalendarPickerPattern::SetMarkToday(bool isMarkToday)
1454 {
1455     isMarkToday_ = isMarkToday;
1456     calendarData_.markToday = isMarkToday;
1457 }
1458 
GetMarkToday()1459 bool CalendarPickerPattern::GetMarkToday()
1460 {
1461     return isMarkToday_;
1462 }
1463 
SetDisabledDateRange(const std::vector<std::pair<PickerDate,PickerDate>> & disabledDateRange)1464 void CalendarPickerPattern::SetDisabledDateRange(
1465     const std::vector<std::pair<PickerDate, PickerDate>>& disabledDateRange)
1466 {
1467     calendarData_.disabledDateRange = disabledDateRange;
1468 }
1469 
GetDisabledDateRange()1470 std::string CalendarPickerPattern::GetDisabledDateRange()
1471 {
1472     std::string disabledDateRangeStr;
1473     for (const auto& range : calendarData_.disabledDateRange) {
1474         disabledDateRangeStr += std::to_string(range.first.GetYear()) + "-" + std::to_string(range.first.GetMonth()) +
1475                                 "-" + std::to_string(range.first.GetDay()) + "," +
1476                                 std::to_string(range.second.GetYear()) + "-" + std::to_string(range.second.GetMonth()) +
1477                                 "-" + std::to_string(range.second.GetDay()) + ",";
1478     }
1479     if (!disabledDateRangeStr.empty() && disabledDateRangeStr.back() == ',') {
1480         disabledDateRangeStr.pop_back(); // remove the last comma.
1481     }
1482     return disabledDateRangeStr;
1483 }
1484 
UpdateTextStyle(const PickerTextStyle & textStyle)1485 void CalendarPickerPattern::UpdateTextStyle(const PickerTextStyle& textStyle)
1486 {
1487     auto host = GetHost();
1488     CHECK_NULL_VOID(host);
1489     auto pipelineContext = host->GetContext();
1490     CHECK_NULL_VOID(pipelineContext);
1491     auto calendarTheme = pipelineContext->GetTheme<CalendarTheme>(host->GetThemeScopeId());
1492     CHECK_NULL_VOID(calendarTheme);
1493     auto pickerProperty = host->GetLayoutProperty<CalendarPickerLayoutProperty>();
1494     CHECK_NULL_VOID(pickerProperty);
1495 
1496     if (pipelineContext->IsSystmColorChange()) {
1497         Color defaultColor = pickerProperty->GetColor().value_or(calendarTheme->GetEntryFontColor());
1498         pickerProperty->UpdateColor(textStyle.textColor.value_or(defaultColor));
1499 
1500         Dimension fontSize = calendarTheme->GetEntryFontSize();
1501         if (textStyle.fontSize.has_value() && textStyle.fontSize->IsValid()) {
1502             fontSize = textStyle.fontSize.value();
1503         }
1504         pickerProperty->UpdateFontSize(fontSize);
1505     }
1506 
1507     if (host->GetRerenderable()) {
1508         host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1509     }
1510 }
1511 
BeforeCreateLayoutWrapper()1512 void CalendarPickerPattern::BeforeCreateLayoutWrapper()
1513 {
1514     auto host = GetHost();
1515     CHECK_NULL_VOID(host);
1516     auto layoutProperty = host->GetLayoutProperty<CalendarPickerLayoutProperty>();
1517     CHECK_NULL_VOID(layoutProperty);
1518     auto layoutPolicy = layoutProperty->GetLayoutPolicyProperty();
1519     CHECK_NULL_VOID(layoutPolicy.has_value());
1520 
1521     if (layoutPolicy->IsWidthMatch() || layoutPolicy->IsHeightMatch()) {
1522         layoutProperty->ClearUserDefinedIdealSize(false, true);
1523     }
1524 }
1525 
1526 } // namespace OHOS::Ace::NG
1527