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