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