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_dialog_pattern.h"
17
18 #include "base/i18n/localization.h"
19 #include "base/utils/date_util.h"
20 #include "core/components/calendar/calendar_data_adapter.h"
21 #include "core/components/dialog/dialog_theme.h"
22 #include "core/components_ng/pattern/calendar/calendar_model_ng.h"
23 #include "core/components_ng/pattern/calendar/calendar_month_pattern.h"
24 #include "core/components_ng/pattern/calendar_picker/calendar_dialog_view.h"
25 #include "core/components_ng/pattern/calendar_picker/calendar_picker_pattern.h"
26 #include "core/components_ng/pattern/dialog/dialog_layout_property.h"
27 #include "core/components_ng/pattern/image/image_layout_property.h"
28 #include "core/components_ng/pattern/text/text_layout_property.h"
29 #include "core/components_ng/pattern/button/button_layout_property.h"
30 #include "core/pipeline_ng/pipeline_context.h"
31
32 namespace OHOS::Ace::NG {
33 namespace {
34 constexpr int32_t TITLE_NODE_INDEX = 0;
35 constexpr int32_t CALENDAR_NODE_INDEX = 1;
36 constexpr int32_t OPTIONS_NODE_INDEX = 2;
37 constexpr int32_t TITLE_LAST_YEAR_BUTTON_NODE_INDEX = 0;
38 constexpr int32_t TITLE_LAST_MONTH_BUTTON_NODE_INDEX = 1;
39 constexpr int32_t TITLE_TEXT_NODE_INDEX = 2;
40 constexpr int32_t TITLE_NEXT_MONTH_BUTTON_NODE_INDEX = 3;
41 constexpr int32_t TITLE_NEXT_YEAR_BUTTON_NODE_INDEX = 4;
42 constexpr int32_t OPTIONS_DIVIDER_NODE_INDEX = 1;
43 constexpr int32_t SWIPER_CHILDREN_SIZE = 3;
44 constexpr int32_t WEEK_DAYS = 7;
45 constexpr int32_t MAX_MONTH = 12;
46 constexpr int32_t MIN_YEAR = 1;
47 constexpr int32_t MAX_YEAR = 5000;
48 constexpr size_t CANCEL_BUTTON_FONT_COLOR_INDEX = 0;
49 constexpr size_t CANCEL_BUTTON_BACKGROUND_COLOR_INDEX = 1;
50 constexpr size_t ACCEPT_BUTTON_FONT_COLOR_INDEX = 2;
51 constexpr size_t ACCEPT_BUTTON_BACKGROUND_COLOR_INDEX = 3;
52 constexpr size_t OPTION_CANCEL_BUTTON_INDEX = 0;
53 constexpr size_t OPTION_ACCEPT_BUTTON_INDEX = 1;
54 } // namespace
OnModifyDone()55 void CalendarDialogPattern::OnModifyDone()
56 {
57 LinearLayoutPattern::OnModifyDone();
58 UpdateCalendarLayout();
59
60 InitClickEvent();
61 InitOnKeyEvent();
62 InitOnTouchEvent();
63 InitHoverEvent();
64 InitTitleArrowsEvent();
65 InitEntryChangeEvent();
66
67 UpdateTitleArrowsImage();
68 UpdateOptionsButton();
69 UpdateDialogBackgroundColor();
70 UpdateTitleArrowsColor();
71 UpdateOptionsButtonColor();
72 }
73
UpdateCalendarLayout()74 void CalendarDialogPattern::UpdateCalendarLayout()
75 {
76 auto entryNode = entryNode_.Upgrade();
77 CHECK_NULL_VOID(entryNode);
78 auto textDirection = entryNode->GetLayoutProperty()->GetNonAutoLayoutDirection();
79 auto calendarNode = GetCalendarFrameNode();
80 CHECK_NULL_VOID(calendarNode);
81 const auto& calendarLayoutProperty = calendarNode->GetLayoutProperty();
82 CHECK_NULL_VOID(calendarLayoutProperty);
83 calendarLayoutProperty->UpdateLayoutDirection(textDirection);
84
85 auto host = GetHost();
86 CHECK_NULL_VOID(host);
87 auto hostNode = AceType::DynamicCast<FrameNode>(host);
88 CHECK_NULL_VOID(hostNode);
89 auto title = host->GetChildAtIndex(TITLE_NODE_INDEX);
90 CHECK_NULL_VOID(title);
91 auto titleNode = AceType::DynamicCast<FrameNode>(title);
92 CHECK_NULL_VOID(titleNode);
93 auto titleLayoutProperty = titleNode->GetLayoutProperty();
94 CHECK_NULL_VOID(titleLayoutProperty);
95 titleLayoutProperty->UpdateLayoutDirection(textDirection);
96 }
UpdateDialogBackgroundColor()97 void CalendarDialogPattern::UpdateDialogBackgroundColor()
98 {
99 auto host = GetHost();
100 CHECK_NULL_VOID(host);
101 auto wrapperNode = AceType::DynamicCast<FrameNode>(host->GetParent());
102 CHECK_NULL_VOID(wrapperNode);
103 auto pipelineContext = host->GetContext();
104 CHECK_NULL_VOID(pipelineContext);
105 RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
106 auto contentRenderContext = wrapperNode->GetRenderContext();
107 CHECK_NULL_VOID(contentRenderContext);
108 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN)) {
109 contentRenderContext->UpdateBackgroundColor(theme->GetDialogBackgroundColor());
110 }
111 }
112
UpdateTitleArrowsColor()113 void CalendarDialogPattern::UpdateTitleArrowsColor()
114 {
115 auto host = GetHost();
116 CHECK_NULL_VOID(host);
117 auto title = host->GetChildAtIndex(TITLE_NODE_INDEX);
118 CHECK_NULL_VOID(title);
119 auto pipelineContext = host->GetContext();
120 CHECK_NULL_VOID(pipelineContext);
121 RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
122 CHECK_NULL_VOID(theme);
123
124 for (const auto& child : title->GetChildren()) {
125 CHECK_NULL_VOID(child);
126 if (child->GetTag() == V2::BUTTON_ETS_TAG) {
127 auto buttonNode = AceType::DynamicCast<FrameNode>(child);
128 CHECK_NULL_VOID(buttonNode);
129 buttonNode->GetRenderContext()->UpdateBackgroundColor(Color::TRANSPARENT);
130 buttonNode->MarkModifyDone();
131
132 auto image = buttonNode->GetChildren().front();
133 CHECK_NULL_VOID(image);
134 auto imageNode = AceType::DynamicCast<FrameNode>(image);
135 auto imageLayoutProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
136 CHECK_NULL_VOID(imageLayoutProperty);
137 auto imageInfo = imageLayoutProperty->GetImageSourceInfo();
138 imageInfo->SetFillColor(theme->GetEntryArrowColor());
139 imageLayoutProperty->UpdateImageSourceInfo(imageInfo.value());
140 imageNode->MarkModifyDone();
141 }
142 }
143 }
144
UpdateTitleArrowsImage()145 void CalendarDialogPattern::UpdateTitleArrowsImage()
146 {
147 auto host = GetHost();
148 CHECK_NULL_VOID(host);
149 auto title = host->GetChildAtIndex(TITLE_NODE_INDEX);
150 CHECK_NULL_VOID(title);
151 auto titleNode = AceType::DynamicCast<FrameNode>(title);
152 CHECK_NULL_VOID(titleNode);
153 auto titleLayoutProperty = titleNode->GetLayoutProperty();
154 CHECK_NULL_VOID(titleLayoutProperty);
155 auto textDirection = titleLayoutProperty->GetNonAutoLayoutDirection();
156
157 auto lastYearNode = AceType::DynamicCast<FrameNode>(title->GetChildAtIndex(TITLE_LAST_YEAR_BUTTON_NODE_INDEX));
158 CHECK_NULL_VOID(lastYearNode);
159 auto lastMonthNode = AceType::DynamicCast<FrameNode>(title->GetChildAtIndex(TITLE_LAST_MONTH_BUTTON_NODE_INDEX));
160 CHECK_NULL_VOID(lastMonthNode);
161 auto nextMonthNode = AceType::DynamicCast<FrameNode>(title->GetChildAtIndex(TITLE_NEXT_MONTH_BUTTON_NODE_INDEX));
162 CHECK_NULL_VOID(nextMonthNode);
163 auto nextYearNode = AceType::DynamicCast<FrameNode>(title->GetChildAtIndex(TITLE_NEXT_YEAR_BUTTON_NODE_INDEX));
164 CHECK_NULL_VOID(nextYearNode);
165
166 if (textDirection == TextDirection::RTL) {
167 UpdateImage(lastYearNode, InternalResource::ResourceId::IC_PUBLIC_DOUBLE_ARROW_RIGHT_SVG);
168 UpdateImage(lastMonthNode, InternalResource::ResourceId::IC_PUBLIC_ARROW_RIGHT_SVG);
169 UpdateImage(nextMonthNode, InternalResource::ResourceId::IC_PUBLIC_ARROW_LEFT_SVG);
170 UpdateImage(nextYearNode, InternalResource::ResourceId::IC_PUBLIC_DOUBLE_ARROW_LEFT_SVG);
171 } else {
172 UpdateImage(lastYearNode, InternalResource::ResourceId::IC_PUBLIC_DOUBLE_ARROW_LEFT_SVG);
173 UpdateImage(lastMonthNode, InternalResource::ResourceId::IC_PUBLIC_ARROW_LEFT_SVG);
174 UpdateImage(nextMonthNode, InternalResource::ResourceId::IC_PUBLIC_ARROW_RIGHT_SVG);
175 UpdateImage(nextYearNode, InternalResource::ResourceId::IC_PUBLIC_DOUBLE_ARROW_RIGHT_SVG);
176 }
177 }
178
UpdateImage(const RefPtr<FrameNode> & buttonNode,const InternalResource::ResourceId & resourceId)179 void CalendarDialogPattern::UpdateImage(
180 const RefPtr<FrameNode>& buttonNode, const InternalResource::ResourceId& resourceId)
181 {
182 auto image = buttonNode->GetChildren().front();
183 CHECK_NULL_VOID(image);
184 auto imageNode = AceType::DynamicCast<FrameNode>(image);
185 auto imageLayoutProperty = imageNode->GetLayoutProperty<ImageLayoutProperty>();
186 CHECK_NULL_VOID(imageLayoutProperty);
187
188 ImageSourceInfo imageSourceInfo;
189 imageSourceInfo.SetResourceId(resourceId);
190 imageLayoutProperty->UpdateImageSourceInfo(imageSourceInfo);
191 imageNode->MarkModifyDone();
192 }
193
UpdateOptionsButton()194 void CalendarDialogPattern::UpdateOptionsButton()
195 {
196 auto host = GetHost();
197 CHECK_NULL_VOID(host);
198 auto options = host->GetChildAtIndex(OPTIONS_NODE_INDEX);
199 CHECK_NULL_VOID(options);
200
201 size_t buttonIndex = OPTION_CANCEL_BUTTON_INDEX;
202 for (const auto& child : options->GetChildren()) {
203 CHECK_NULL_VOID(child);
204 if (child->GetTag() == V2::BUTTON_ETS_TAG) {
205 auto button = AceType::DynamicCast<FrameNode>(child);
206 CHECK_NULL_VOID(button);
207 auto buttonLayoutProperty = button->GetLayoutProperty<ButtonLayoutProperty>();
208 CHECK_NULL_VOID(buttonLayoutProperty);
209 if (buttonIndex == OPTION_ACCEPT_BUTTON_INDEX) {
210 buttonLayoutProperty->UpdateLabel(Localization::GetInstance()->GetEntryLetters("common.ok"));
211 } else {
212 buttonLayoutProperty->UpdateLabel(Localization::GetInstance()->GetEntryLetters("common.cancel"));
213 }
214 button->MarkDirtyNode();
215 buttonIndex++;
216 }
217 }
218 }
219
UpdateOptionsButtonColor()220 void CalendarDialogPattern::UpdateOptionsButtonColor()
221 {
222 auto host = GetHost();
223 CHECK_NULL_VOID(host);
224 auto options = host->GetChildAtIndex(OPTIONS_NODE_INDEX);
225 CHECK_NULL_VOID(options);
226 auto pipeline = host->GetContext();
227 CHECK_NULL_VOID(pipeline);
228 auto calendarTheme = pipeline->GetTheme<CalendarTheme>();
229 CHECK_NULL_VOID(calendarTheme);
230 auto pickerTheme = pipeline->GetTheme<PickerTheme>();
231 CHECK_NULL_VOID(pickerTheme);
232
233 size_t buttonIndex = OPTION_CANCEL_BUTTON_INDEX;
234 for (const auto& child : options->GetChildren()) {
235 CHECK_NULL_VOID(child);
236 if (child->GetTag() == V2::BUTTON_ETS_TAG) {
237 auto button = AceType::DynamicCast<FrameNode>(child);
238 CHECK_NULL_VOID(button);
239 bool cancelNotUpdateBGColor =
240 buttonIndex == OPTION_CANCEL_BUTTON_INDEX && !updateColorFlags[CANCEL_BUTTON_BACKGROUND_COLOR_INDEX];
241 bool acceptNotUpdateBGColor =
242 buttonIndex == OPTION_ACCEPT_BUTTON_INDEX && !updateColorFlags[ACCEPT_BUTTON_BACKGROUND_COLOR_INDEX];
243 if (!(cancelNotUpdateBGColor || acceptNotUpdateBGColor)) {
244 auto defaultBGColor = calendarTheme->GetIsButtonTransparent()
245 ? Color::TRANSPARENT
246 : calendarTheme->GetDialogButtonBackgroundColor();
247 button->GetRenderContext()->UpdateBackgroundColor(defaultBGColor);
248 }
249 button->MarkModifyDone();
250
251 auto text = button->GetChildren().front();
252 CHECK_NULL_VOID(text);
253 auto textNode = AceType::DynamicCast<FrameNode>(text);
254 auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
255 CHECK_NULL_VOID(textLayoutProperty);
256 bool cancelNotUpdateFontColor =
257 buttonIndex == OPTION_CANCEL_BUTTON_INDEX && !updateColorFlags[CANCEL_BUTTON_FONT_COLOR_INDEX];
258 bool acceptNotUpdateFontColor =
259 buttonIndex == OPTION_ACCEPT_BUTTON_INDEX && !updateColorFlags[ACCEPT_BUTTON_FONT_COLOR_INDEX];
260 if (!(cancelNotUpdateFontColor || acceptNotUpdateFontColor)) {
261 textLayoutProperty->UpdateTextColor(pickerTheme->GetOptionStyle(true, false).GetTextColor());
262 }
263 textNode->MarkModifyDone();
264
265 buttonIndex++;
266 }
267 }
268 }
269
SetOptionsButtonUpdateColorFlags(size_t index,bool isUpdate)270 void CalendarDialogPattern::SetOptionsButtonUpdateColorFlags(size_t index, bool isUpdate)
271 {
272 if (index >= updateColorFlags.size()) {
273 return;
274 }
275
276 updateColorFlags[index] = isUpdate;
277 }
278
InitHoverEvent()279 void CalendarDialogPattern::InitHoverEvent()
280 {
281 CHECK_NULL_VOID(!hoverListener_);
282 auto host = GetHost();
283 CHECK_NULL_VOID(host);
284 auto inputHub = host->GetOrCreateInputEventHub();
285 CHECK_NULL_VOID(inputHub);
286
287 auto mouseCallback = [weak = WeakClaim(this)](const MouseInfo& info) {
288 auto pattern = weak.Upgrade();
289 CHECK_NULL_VOID(pattern);
290 CHECK_NULL_VOID(pattern->GetHoverState());
291 pattern->HandleEntryNodeHoverEvent(
292 pattern->IsInEntryRegion(info.GetGlobalLocation()), info.GetGlobalLocation());
293 };
294 inputHub->SetMouseEvent(std::move(mouseCallback));
295
296 auto hoverCallback = [weak = WeakClaim(this)](bool state) {
297 auto pattern = weak.Upgrade();
298 CHECK_NULL_VOID(pattern);
299 pattern->SetHoverState(state);
300 if (!state) {
301 Offset location;
302 pattern->HandleEntryNodeHoverEvent(false, location);
303 }
304 };
305 hoverListener_ = MakeRefPtr<InputEvent>(std::move(hoverCallback));
306 inputHub->AddOnHoverEvent(hoverListener_);
307 }
308
IsInEntryRegion(const Offset & globalLocation)309 bool CalendarDialogPattern::IsInEntryRegion(const Offset& globalLocation)
310 {
311 auto entryNode = entryNode_.Upgrade();
312 CHECK_NULL_RETURN(entryNode, false);
313 return entryNode->GetTransformRectRelativeToWindow().IsInRegion(
314 PointF(globalLocation.GetX(), globalLocation.GetY()));
315 }
316
HandleEntryNodeHoverEvent(bool state,const Offset & globalLocation)317 void CalendarDialogPattern::HandleEntryNodeHoverEvent(bool state, const Offset& globalLocation)
318 {
319 auto entryNode = entryNode_.Upgrade();
320 CHECK_NULL_VOID(entryNode);
321 auto pattern = entryNode->GetPattern<CalendarPickerPattern>();
322 CHECK_NULL_VOID(pattern);
323 pattern->HandleHoverEvent(state, globalLocation);
324 }
325
HandleEntryNodeTouchEvent(bool isPressed,const Offset & globalLocation)326 void CalendarDialogPattern::HandleEntryNodeTouchEvent(bool isPressed, const Offset& globalLocation)
327 {
328 auto entryNode = entryNode_.Upgrade();
329 CHECK_NULL_VOID(entryNode);
330 if (IsInEntryRegion(globalLocation)) {
331 auto pattern = entryNode->GetPattern<CalendarPickerPattern>();
332 CHECK_NULL_VOID(pattern);
333 pattern->HandleTouchEvent(isPressed, globalLocation);
334 }
335 }
336
InitClickEvent()337 void CalendarDialogPattern::InitClickEvent()
338 {
339 auto host = GetHost();
340 CHECK_NULL_VOID(host);
341 auto gesture = host->GetOrCreateGestureEventHub();
342 CHECK_NULL_VOID(gesture);
343 auto clickCallback = [weak = WeakClaim(this)](const GestureEvent& info) {
344 auto pattern = weak.Upgrade();
345 CHECK_NULL_VOID(pattern);
346 pattern->HandleClickEvent(info);
347 };
348 auto onClick = AceType::MakeRefPtr<ClickEvent>(clickCallback);
349 gesture->AddClickEvent(onClick);
350 }
351
HandleClickEvent(const GestureEvent & info)352 void CalendarDialogPattern::HandleClickEvent(const GestureEvent& info)
353 {
354 auto entryNode = entryNode_.Upgrade();
355 CHECK_NULL_VOID(entryNode);
356 if (IsInEntryRegion(info.GetGlobalLocation())) {
357 auto pattern = entryNode->GetPattern<CalendarPickerPattern>();
358 CHECK_NULL_VOID(pattern);
359 pattern->HandleClickEvent(info.GetGlobalLocation());
360 }
361 }
362
InitOnTouchEvent()363 void CalendarDialogPattern::InitOnTouchEvent()
364 {
365 if (touchListener_) {
366 return;
367 }
368 auto host = GetHost();
369 CHECK_NULL_VOID(host);
370 auto gesture = host->GetOrCreateGestureEventHub();
371 CHECK_NULL_VOID(gesture);
372 auto touchCallback = [weak = WeakClaim(this)](const TouchEventInfo& info) {
373 auto pattern = weak.Upgrade();
374 CHECK_NULL_VOID(pattern);
375 if (info.GetTouches().front().GetTouchType() == TouchType::DOWN) {
376 pattern->HandleEntryNodeTouchEvent(true, info.GetTouches().front().GetGlobalLocation());
377 if (!pattern->isFocused_) {
378 return;
379 }
380 pattern->isFocused_ = false;
381 pattern->isCalendarFirstFocused_ = false;
382 pattern->ClearCalendarFocusedState();
383 }
384 if (info.GetTouches().front().GetTouchType() == TouchType::UP ||
385 info.GetTouches().front().GetTouchType() == TouchType::CANCEL) {
386 pattern->HandleEntryNodeTouchEvent(false, info.GetTouches().front().GetGlobalLocation());
387 }
388 };
389 touchListener_ = MakeRefPtr<TouchEventImpl>(std::move(touchCallback));
390 gesture->AddTouchEvent(touchListener_);
391 }
392
InitOnKeyEvent()393 void CalendarDialogPattern::InitOnKeyEvent()
394 {
395 auto host = GetHost();
396 CHECK_NULL_VOID(host);
397 auto focusHub = host->GetOrCreateFocusHub();
398 CHECK_NULL_VOID(focusHub);
399
400 auto onKeyEvent = [wp = WeakClaim(this)](const KeyEvent& event) -> bool {
401 auto pattern = wp.Upgrade();
402 CHECK_NULL_RETURN(pattern, false);
403 if (event.IsNumberKey() && event.action == KeyAction::DOWN) {
404 auto entryNode = pattern->entryNode_.Upgrade();
405 CHECK_NULL_RETURN(entryNode, false);
406 auto entryPattern = entryNode->GetPattern<CalendarPickerPattern>();
407 CHECK_NULL_RETURN(entryPattern, false);
408 entryPattern->HandleNumberKeyEvent(event);
409 }
410 if (pattern->isFocused_ && !pattern->isCalendarFirstFocused_ &&
411 pattern->focusAreaID_ == CALENDAR_NODE_INDEX) {
412 pattern->isCalendarFirstFocused_ = true;
413 pattern->FocusedLastFocusedDay();
414 return true;
415 }
416 if (pattern->isFocused_ && event.action == KeyAction::DOWN) {
417 return pattern->HandleKeyEvent(event);
418 }
419 if (!pattern->isFocused_ && !pattern->hasTabKeyDown_ && event.action == KeyAction::DOWN) {
420 pattern->OnEnterKeyEvent(event);
421 }
422 return false;
423 };
424 focusHub->SetOnKeyEventInternal(std::move(onKeyEvent));
425
426 auto blurTask = [weak = WeakClaim(this)]() {
427 auto pattern = weak.Upgrade();
428 CHECK_NULL_VOID(pattern);
429 pattern->isFocused_ = false;
430 pattern->isCalendarFirstFocused_ = false;
431 pattern->ClearCalendarFocusedState();
432 };
433 focusHub->SetOnBlurInternal(std::move(blurTask));
434
435 auto getInnerPaintRectCallback = [wp = WeakClaim(this)](RoundRect& paintRect) {
436 auto pattern = wp.Upgrade();
437 CHECK_NULL_VOID(pattern);
438 pattern->GetInnerFocusPaintRect(paintRect);
439 };
440 focusHub->SetInnerFocusPaintRectCallback(getInnerPaintRectCallback);
441 }
442
InitEntryChangeEvent()443 void CalendarDialogPattern::InitEntryChangeEvent()
444 {
445 auto entryNode = entryNode_.Upgrade();
446 CHECK_NULL_VOID(entryNode);
447 auto eventHub = entryNode->GetEventHub<CalendarPickerEventHub>();
448 CHECK_NULL_VOID(eventHub);
449 auto callback = [weak = WeakClaim(this)](const std::string& info) {
450 auto pattern = weak.Upgrade();
451 CHECK_NULL_VOID(pattern);
452 pattern->HandleEntryChange(info);
453 };
454 eventHub->SetInputChangeEvent(std::move(callback));
455 auto layoutChangeEvent = [weak = WeakClaim(this)]() {
456 auto pattern = weak.Upgrade();
457 CHECK_NULL_VOID(pattern);
458 pattern->HandleEntryLayoutChange();
459 };
460 eventHub->SetLayoutChangeEvent(layoutChangeEvent);
461 }
462
HandleKeyEvent(const KeyEvent & event)463 bool CalendarDialogPattern::HandleKeyEvent(const KeyEvent& event)
464 {
465 auto host = GetHost();
466 CHECK_NULL_RETURN(host, false);
467
468 if (event.code == KeyCode::KEY_TAB) {
469 return HandleTabKeyEvent(event);
470 }
471 if (focusAreaID_ == CALENDAR_NODE_INDEX) {
472 return HandleCalendarNodeKeyEvent(event);
473 }
474 if (focusAreaID_ != TITLE_NODE_INDEX && focusAreaID_ != OPTIONS_NODE_INDEX) {
475 return false;
476 }
477
478 auto calendarNode = GetCalendarFrameNode();
479 CHECK_NULL_RETURN(calendarNode, false);
480 auto textDirection = calendarNode->GetLayoutProperty()->GetNonAutoLayoutDirection();
481 switch (event.code) {
482 case KeyCode::KEY_DPAD_LEFT: {
483 if (textDirection == TextDirection::RTL) {
484 if ((focusAreaID_ == TITLE_NODE_INDEX && focusAreaChildID_ == TITLE_TEXT_NODE_INDEX - 1) ||
485 (focusAreaID_ == OPTIONS_NODE_INDEX && focusAreaChildID_ == OPTIONS_DIVIDER_NODE_INDEX - 1)) {
486 focusAreaChildID_++;
487 }
488 focusAreaChildID_++;
489 auto childSize = static_cast<int32_t>(host->GetChildAtIndex(focusAreaID_)->GetChildren().size());
490 if (focusAreaChildID_ > childSize - 1) {
491 focusAreaChildID_ = childSize - 1;
492 }
493 } else {
494 if ((focusAreaID_ == TITLE_NODE_INDEX && focusAreaChildID_ == TITLE_TEXT_NODE_INDEX + 1) ||
495 (focusAreaID_ == OPTIONS_NODE_INDEX && focusAreaChildID_ == OPTIONS_DIVIDER_NODE_INDEX + 1)) {
496 focusAreaChildID_--;
497 }
498 focusAreaChildID_--;
499 if (focusAreaChildID_ < 0) {
500 focusAreaChildID_ = 0;
501 }
502 }
503
504 PaintFocusState();
505 ChangeEntryState();
506 return true;
507 }
508 case KeyCode::KEY_DPAD_RIGHT: {
509 if (textDirection == TextDirection::RTL) {
510 if ((focusAreaID_ == TITLE_NODE_INDEX && focusAreaChildID_ == TITLE_TEXT_NODE_INDEX + 1) ||
511 (focusAreaID_ == OPTIONS_NODE_INDEX && focusAreaChildID_ == OPTIONS_DIVIDER_NODE_INDEX + 1)) {
512 focusAreaChildID_--;
513 }
514
515 focusAreaChildID_--;
516 if (focusAreaChildID_ < 0) {
517 focusAreaChildID_ = 0;
518 }
519 } else {
520 if ((focusAreaID_ == TITLE_NODE_INDEX && focusAreaChildID_ == TITLE_TEXT_NODE_INDEX - 1) ||
521 (focusAreaID_ == OPTIONS_NODE_INDEX && focusAreaChildID_ == OPTIONS_DIVIDER_NODE_INDEX - 1)) {
522 focusAreaChildID_++;
523 }
524
525 focusAreaChildID_++;
526 auto childSize = static_cast<int32_t>(host->GetChildAtIndex(focusAreaID_)->GetChildren().size());
527 if (focusAreaChildID_ > childSize - 1) {
528 focusAreaChildID_ = childSize - 1;
529 }
530 }
531
532 PaintFocusState();
533 ChangeEntryState();
534 return true;
535 }
536 case KeyCode::KEY_MOVE_HOME: {
537 focusAreaChildID_ = 0;
538 PaintFocusState();
539 ChangeEntryState();
540 return true;
541 }
542 case KeyCode::KEY_MOVE_END: {
543 focusAreaChildID_ = static_cast<int32_t>(host->GetChildAtIndex(focusAreaID_)->GetChildren().size()) - 1;
544 PaintFocusState();
545 ChangeEntryState();
546 return true;
547 }
548 case KeyCode::KEY_SPACE:
549 case KeyCode::KEY_NUMPAD_ENTER:
550 case KeyCode::KEY_ENTER: {
551 return ActClick(focusAreaID_, focusAreaChildID_);
552 }
553 default:
554 break;
555 }
556 return false;
557 }
558
HandleCalendarNodeKeyEvent(const KeyEvent & event)559 bool CalendarDialogPattern::HandleCalendarNodeKeyEvent(const KeyEvent& event)
560 {
561 auto swiperPattern = GetSwiperPattern();
562 CHECK_NULL_RETURN(swiperPattern, false);
563 auto swiperController = swiperPattern->GetSwiperController();
564 CHECK_NULL_RETURN(swiperController, false);
565 swiperController->FinishAnimation();
566 auto calendarPattern = GetCalendarPattern();
567 CHECK_NULL_RETURN(calendarPattern, false);
568 ObtainedMonth currentMonthData = calendarPattern->GetCurrentMonthData();
569 auto calendarNode = GetCalendarFrameNode();
570 CHECK_NULL_RETURN(calendarNode, false);
571 auto textDirection = calendarNode->GetLayoutProperty()->GetNonAutoLayoutDirection();
572 int32_t focusedDayIndex = GetIndexByFocusedDay();
573
574 switch (event.code) {
575 case KeyCode::KEY_DPAD_LEFT: {
576 if (textDirection == TextDirection::RTL) {
577 focusedDayIndex++;
578 } else {
579 focusedDayIndex--;
580 }
581
582 PaintMonthFocusState(focusedDayIndex);
583 return true;
584 }
585 case KeyCode::KEY_DPAD_RIGHT: {
586 if (textDirection == TextDirection::RTL) {
587 focusedDayIndex--;
588 } else {
589 focusedDayIndex++;
590 }
591
592 PaintMonthFocusState(focusedDayIndex);
593 return true;
594 }
595 case KeyCode::KEY_DPAD_UP: {
596 focusedDayIndex -= WEEK_DAYS;
597 if (IsIndexInCurrentMonth(focusedDayIndex, currentMonthData)) {
598 focusedDay_ = currentMonthData.days[focusedDayIndex];
599 PaintCurrentMonthFocusState();
600 return true;
601 }
602 break;
603 }
604 case KeyCode::KEY_DPAD_DOWN: {
605 focusedDayIndex += WEEK_DAYS;
606 if (IsIndexInCurrentMonth(focusedDayIndex, currentMonthData)) {
607 focusedDay_ = currentMonthData.days[focusedDayIndex];
608 PaintCurrentMonthFocusState();
609 return true;
610 }
611 break;
612 }
613 case KeyCode::KEY_MOVE_HOME: {
614 auto it = std::find_if(currentMonthData.days.begin(), currentMonthData.days.end(),
615 [currentMonthData](const CalendarDay& day) {
616 return day.month.year == currentMonthData.year && day.month.month == currentMonthData.month;
617 });
618 if (it != currentMonthData.days.end()) {
619 focusedDay_ = currentMonthData.days[it->index];
620 PaintCurrentMonthFocusState();
621 return true;
622 }
623 break;
624 }
625 case KeyCode::KEY_MOVE_END: {
626 auto it = std::find_if(currentMonthData.days.rbegin(), currentMonthData.days.rend(),
627 [currentMonthData](const CalendarDay& day) {
628 return day.month.year == currentMonthData.year && day.month.month == currentMonthData.month;
629 });
630 if (it != currentMonthData.days.rend()) {
631 focusedDay_ = currentMonthData.days[it->index];
632 PaintCurrentMonthFocusState();
633 return true;
634 }
635 break;
636 }
637 case KeyCode::KEY_SPACE:
638 case KeyCode::KEY_NUMPAD_ENTER:
639 case KeyCode::KEY_ENTER: {
640 PickerDate selectedDay(focusedDay_.month.year, focusedDay_.month.month, focusedDay_.day);
641 calendarPattern->SetSelectedDay(selectedDay);
642 auto calendarFrameNode = GetCalendarFrameNode();
643 CHECK_NULL_RETURN(calendarFrameNode, false);
644 calendarFrameNode->MarkModifyDone();
645 FireChangeByKeyEvent(selectedDay);
646 return true;
647 }
648 default:
649 break;
650 }
651 return false;
652 }
653
PaintMonthFocusState(int32_t focusedDayIndex)654 void CalendarDialogPattern::PaintMonthFocusState(int32_t focusedDayIndex)
655 {
656 auto calendarPattern = GetCalendarPattern();
657 CHECK_NULL_VOID(calendarPattern);
658 ObtainedMonth currentMonthData = calendarPattern->GetCurrentMonthData();
659 if (IsIndexInCurrentMonth(focusedDayIndex, currentMonthData)) {
660 focusedDay_ = currentMonthData.days[focusedDayIndex];
661 PaintCurrentMonthFocusState();
662 } else {
663 PaintNonCurrentMonthFocusState(focusedDayIndex);
664 }
665 }
666
IsIndexInCurrentMonth(int32_t focusedDayIndex,const ObtainedMonth & currentMonthData)667 bool CalendarDialogPattern::IsIndexInCurrentMonth(int32_t focusedDayIndex, const ObtainedMonth& currentMonthData)
668 {
669 return focusedDayIndex >= 0 && focusedDayIndex < static_cast<int32_t>(currentMonthData.days.size()) &&
670 currentMonthData.days[focusedDayIndex].month.year == currentMonthData.year &&
671 currentMonthData.days[focusedDayIndex].month.month == currentMonthData.month;
672 }
673
HandleTabKeyEvent(const KeyEvent & event)674 bool CalendarDialogPattern::HandleTabKeyEvent(const KeyEvent& event)
675 {
676 hasTabKeyDown_ = true;
677 auto host = GetHost();
678 CHECK_NULL_RETURN(host, false);
679 auto childSize = static_cast<int32_t>(host->GetChildren().size());
680 if (event.IsShiftWith(KeyCode::KEY_TAB)) {
681 focusAreaID_ = (focusAreaID_ + childSize - 1) % childSize;
682 } else {
683 focusAreaID_ = (focusAreaID_ + 1) % childSize;
684 }
685
686 if (focusAreaID_ == CALENDAR_NODE_INDEX) {
687 isCalendarFirstFocused_ = true;
688 FocusedLastFocusedDay();
689 } else {
690 ClearCalendarFocusedState();
691 focusAreaChildID_ = 0;
692 PaintFocusState();
693 }
694 ChangeEntryState();
695 return true;
696 }
697
FocusedLastFocusedDay()698 void CalendarDialogPattern::FocusedLastFocusedDay()
699 {
700 auto calendarPattern = GetCalendarPattern();
701 CHECK_NULL_VOID(calendarPattern);
702 if (focusedDay_.day < 0) {
703 PickerDate selectedDay = calendarPattern->GetSelectedDay();
704 focusedDay_.month.year = static_cast<int32_t>(selectedDay.GetYear());
705 focusedDay_.month.month = static_cast<int32_t>(selectedDay.GetMonth());
706 focusedDay_.day = static_cast<int32_t>(selectedDay.GetDay());
707 }
708
709 ObtainedMonth currentMonthData = calendarPattern->GetCurrentMonthData();
710 if (currentMonthData.year == focusedDay_.month.year && currentMonthData.month == focusedDay_.month.month) {
711 PaintCurrentMonthFocusState();
712 return;
713 }
714 ObtainedMonth monthData;
715 GetCalendarMonthData(focusedDay_.month.year, focusedDay_.month.month, monthData);
716 auto isPrev = currentMonthData.year > focusedDay_.month.year ||
717 (currentMonthData.year == focusedDay_.month.year && currentMonthData.month > focusedDay_.month.month);
718 auto it = std::find_if(monthData.days.begin(), monthData.days.end(),
719 [this](CalendarDay day) {
720 return day.day == focusedDay_.day && day.month == focusedDay_.month;
721 });
722 if (it != monthData.days.end()) {
723 focusedDay_ = *it;
724 it->isKeyFocused = true;
725 calendarPattern->SetDialogClickEventState(true);
726 UpdateSwiperNode(monthData, isPrev);
727 }
728 }
729
UpdateSwiperNode(const ObtainedMonth & monthData,bool isPrev)730 void CalendarDialogPattern::UpdateSwiperNode(const ObtainedMonth& monthData, bool isPrev)
731 {
732 auto calendarPattern = GetCalendarPattern();
733 CHECK_NULL_VOID(calendarPattern);
734 auto swiperPattern = GetSwiperPattern();
735 CHECK_NULL_VOID(swiperPattern);
736 int32_t currentIndex = swiperPattern->GetCurrentIndex();
737 int32_t targetIndex = (currentIndex + SWIPER_CHILDREN_SIZE + (isPrev ? -1 : 1)) % SWIPER_CHILDREN_SIZE;
738
739 auto swiperNode = GetSwiperFrameNode();
740 CHECK_NULL_VOID(swiperNode);
741 auto monthFrameNode = AceType::DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(targetIndex));
742 CHECK_NULL_VOID(monthFrameNode);
743 auto monthPattern = monthFrameNode->GetPattern<CalendarMonthPattern>();
744 CHECK_NULL_VOID(monthPattern);
745
746 if (isPrev) {
747 monthPattern->SetMonthData(monthData, MonthState::PRE_MONTH);
748 calendarPattern->SetPreMonthData(monthData);
749 } else {
750 monthPattern->SetMonthData(monthData, MonthState::NEXT_MONTH);
751 calendarPattern->SetNextMonthData(monthData);
752 }
753
754 monthFrameNode->MarkModifyDone();
755 monthFrameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
756 if (isPrev) {
757 swiperPattern->ShowPrevious();
758 } else {
759 swiperPattern->ShowNext();
760 }
761 }
762
UpdateSwiperNodeFocusedDay(const CalendarDay & focusedDay,bool isPrev)763 void CalendarDialogPattern::UpdateSwiperNodeFocusedDay(const CalendarDay& focusedDay, bool isPrev)
764 {
765 auto calendarPattern = GetCalendarPattern();
766 CHECK_NULL_VOID(calendarPattern);
767 ObtainedMonth targetMonthData = isPrev ? calendarPattern->GetPreMonthData() : calendarPattern->GetNextMonthData();
768 if (focusedDay.month.year != targetMonthData.year || focusedDay.month.month != targetMonthData.month) {
769 return;
770 }
771
772 auto it = std::find_if(targetMonthData.days.begin(), targetMonthData.days.end(),
773 [focusedDay](CalendarDay day) {
774 return day.day == focusedDay.day && day.month == focusedDay.month;
775 });
776 if (it != targetMonthData.days.end()) {
777 focusedDay_ = *it;
778 it->isKeyFocused = true;
779 auto swiperPattern = GetSwiperPattern();
780 CHECK_NULL_VOID(swiperPattern);
781 if (isPrev) {
782 calendarPattern->SetPreMonthData(targetMonthData);
783 swiperPattern->ShowPrevious();
784 } else {
785 calendarPattern->SetNextMonthData(targetMonthData);
786 swiperPattern->ShowNext();
787 }
788 }
789 }
790
ActClick(int32_t focusAreaID,int32_t focusAreaChildID)791 bool CalendarDialogPattern::ActClick(int32_t focusAreaID, int32_t focusAreaChildID)
792 {
793 auto host = GetHost();
794 CHECK_NULL_RETURN(host, false);
795 auto focusArea = host->GetChildAtIndex(focusAreaID);
796 CHECK_NULL_RETURN(focusArea, false);
797 auto child = focusArea->GetChildAtIndex(focusAreaChildID);
798 CHECK_NULL_RETURN(child, false);
799 auto childFrameNode = AceType::DynamicCast<FrameNode>(child);
800 CHECK_NULL_RETURN(childFrameNode, false);
801 auto gestureEventHub = childFrameNode->GetOrCreateGestureEventHub();
802 return gestureEventHub->ActClick();
803 }
804
PaintCurrentMonthFocusState()805 void CalendarDialogPattern::PaintCurrentMonthFocusState()
806 {
807 auto calendarFrameNode = GetCalendarFrameNode();
808 CHECK_NULL_VOID(calendarFrameNode);
809 auto calendarPattern = calendarFrameNode->GetPattern<CalendarPattern>();
810 CHECK_NULL_VOID(calendarPattern);
811 ObtainedMonth currentMonthData = calendarPattern->GetCurrentMonthData();
812 for (auto& day : currentMonthData.days) {
813 day.isKeyFocused = currentMonthData.year == focusedDay_.month.year &&
814 currentMonthData.month == focusedDay_.month.month &&
815 day.month == focusedDay_.month && day.day == focusedDay_.day;
816 }
817 calendarPattern->SetCurrentMonthData(currentMonthData);
818 calendarFrameNode->MarkModifyDone();
819 }
820
PaintNonCurrentMonthFocusState(int32_t focusedDayIndex)821 void CalendarDialogPattern::PaintNonCurrentMonthFocusState(int32_t focusedDayIndex)
822 {
823 auto calendarPattern = GetCalendarPattern();
824 CHECK_NULL_VOID(calendarPattern);
825 auto swiperPattern = GetSwiperPattern();
826 CHECK_NULL_VOID(swiperPattern);
827
828 ObtainedMonth currentMonthData = calendarPattern->GetCurrentMonthData();
829 ObtainedMonth preMonthData = calendarPattern->GetPreMonthData();
830 ObtainedMonth nextMonthData = calendarPattern->GetNextMonthData();
831
832 for (auto& day : currentMonthData.days) {
833 day.isKeyFocused = false;
834 }
835 calendarPattern->SetCurrentMonthData(currentMonthData);
836 calendarPattern->SetDialogClickEventState(true);
837 if (focusedDayIndex == -1) {
838 focusedDay_ = preMonthData.days[preMonthData.days.size() ? preMonthData.days.size() - 1 : 0];
839 preMonthData.days[preMonthData.days.size() ? preMonthData.days.size() - 1 : 0].isKeyFocused = true;
840 calendarPattern->SetPreMonthData(preMonthData);
841 swiperPattern->ShowPrevious();
842 return;
843 } else if (focusedDayIndex == static_cast<int32_t>(currentMonthData.days.size())) {
844 focusedDay_ = nextMonthData.days[0];
845 nextMonthData.days[0].isKeyFocused = true;
846 calendarPattern->SetNextMonthData(nextMonthData);
847 swiperPattern->ShowNext();
848 return;
849 }
850 UpdateNonCurrentMonthFocusedDay(focusedDayIndex);
851 }
852
UpdateNonCurrentMonthFocusedDay(int32_t focusedDayIndex)853 void CalendarDialogPattern::UpdateNonCurrentMonthFocusedDay(int32_t focusedDayIndex)
854 {
855 auto calendarPattern = GetCalendarPattern();
856 CHECK_NULL_VOID(calendarPattern);
857
858 ObtainedMonth currentMonthData = calendarPattern->GetCurrentMonthData();
859 ObtainedMonth preMonthData = calendarPattern->GetPreMonthData();
860 ObtainedMonth nextMonthData = calendarPattern->GetNextMonthData();
861
862 if (focusedDayIndex < 0 || focusedDayIndex >= static_cast<int32_t>(currentMonthData.days.size())) {
863 return;
864 }
865
866 CalendarDay focusedDay = currentMonthData.days[focusedDayIndex];
867 if (focusedDay.month.year == preMonthData.year && focusedDay.month.month == preMonthData.month) {
868 return UpdateSwiperNodeFocusedDay(focusedDay, true);
869 }
870
871 if (focusedDay.month.year == nextMonthData.year && focusedDay.month.month == nextMonthData.month) {
872 return UpdateSwiperNodeFocusedDay(focusedDay, false);
873 }
874 }
875
PaintFocusState()876 void CalendarDialogPattern::PaintFocusState()
877 {
878 auto host = GetHost();
879 CHECK_NULL_VOID(host);
880 RoundRect focusRect;
881 GetInnerFocusPaintRect(focusRect);
882 auto focusHub = host->GetFocusHub();
883 CHECK_NULL_VOID(focusHub);
884 focusHub->PaintInnerFocusState(focusRect);
885 host->MarkDirtyNode(PROPERTY_UPDATE_RENDER);
886 }
887
GetInnerFocusPaintRect(RoundRect & paintRect)888 void CalendarDialogPattern::GetInnerFocusPaintRect(RoundRect& paintRect)
889 {
890 isFocused_ = true;
891 if (focusAreaID_ == CALENDAR_NODE_INDEX) {
892 paintRect.SetRect(RectF());
893 return;
894 }
895 auto host = GetHost();
896 CHECK_NULL_VOID(host);
897 auto focusArea = DynamicCast<FrameNode>(host->GetChildAtIndex(focusAreaID_));
898 CHECK_NULL_VOID(focusArea);
899 auto focusGeometryNode = focusArea->GetGeometryNode();
900 CHECK_NULL_VOID(focusGeometryNode);
901 auto focusAreaOffset = focusGeometryNode->GetFrameOffset();
902 auto child = DynamicCast<FrameNode>(focusArea->GetChildAtIndex(focusAreaChildID_));
903 CHECK_NULL_VOID(child);
904 auto childOffset = child->GetGeometryNode()->GetFrameOffset() + focusAreaOffset;
905 auto childSize = child->GetGeometryNode()->GetFrameSize();
906 paintRect.SetRect(RectF(childOffset, childSize));
907 auto renderContext = child->GetRenderContext();
908 CHECK_NULL_VOID(renderContext);
909 auto radius = renderContext->GetBorderRadius();
910 if (radius.has_value()) {
911 if (radius->radiusTopLeft.has_value()) {
912 paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_LEFT_POS,
913 static_cast<float>(radius->radiusTopLeft->ConvertToPx()),
914 static_cast<float>(radius->radiusTopLeft->ConvertToPx()));
915 }
916 if (radius->radiusTopRight.has_value()) {
917 paintRect.SetCornerRadius(RoundRect::CornerPos::TOP_RIGHT_POS,
918 static_cast<float>(radius->radiusTopRight->ConvertToPx()),
919 static_cast<float>(radius->radiusTopRight->ConvertToPx()));
920 }
921 if (radius->radiusBottomLeft.has_value()) {
922 paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_LEFT_POS,
923 static_cast<float>(radius->radiusBottomLeft->ConvertToPx()),
924 static_cast<float>(radius->radiusBottomLeft->ConvertToPx()));
925 }
926 if (radius->radiusBottomRight.has_value()) {
927 paintRect.SetCornerRadius(RoundRect::CornerPos::BOTTOM_RIGHT_POS,
928 static_cast<float>(radius->radiusBottomRight->ConvertToPx()),
929 static_cast<float>(radius->radiusBottomRight->ConvertToPx()));
930 }
931 }
932 ChangeEntryState();
933 }
934
ClearCalendarFocusedState()935 void CalendarDialogPattern::ClearCalendarFocusedState()
936 {
937 auto calendarFrameNode = GetCalendarFrameNode();
938 CHECK_NULL_VOID(calendarFrameNode);
939 auto calendarPattern = calendarFrameNode->GetPattern<CalendarPattern>();
940 CHECK_NULL_VOID(calendarPattern);
941 ObtainedMonth currentMonthData = calendarPattern->GetCurrentMonthData();
942 for (auto& day : currentMonthData.days) {
943 day.isKeyFocused = false;
944 }
945 calendarPattern->SetCurrentMonthData(currentMonthData);
946 calendarFrameNode->MarkModifyDone();
947 }
948
ChangeEntryState()949 void CalendarDialogPattern::ChangeEntryState()
950 {
951 auto entryNode = entryNode_.Upgrade();
952 CHECK_NULL_VOID(entryNode);
953 auto enrtyPattern = entryNode->GetPattern<CalendarPickerPattern>();
954 CHECK_NULL_VOID(enrtyPattern);
955 if (focusAreaID_ == TITLE_NODE_INDEX) {
956 if (focusAreaChildID_ == TITLE_LAST_YEAR_BUTTON_NODE_INDEX ||
957 focusAreaChildID_ == TITLE_NEXT_YEAR_BUTTON_NODE_INDEX) {
958 enrtyPattern->SetSelectedType(CalendarPickerSelectedType::YEAR);
959 } else if (focusAreaChildID_ == TITLE_LAST_MONTH_BUTTON_NODE_INDEX ||
960 focusAreaChildID_ == TITLE_NEXT_MONTH_BUTTON_NODE_INDEX) {
961 enrtyPattern->SetSelectedType(CalendarPickerSelectedType::MONTH);
962 }
963 } else if (focusAreaID_ == CALENDAR_NODE_INDEX) {
964 enrtyPattern->SetSelectedType(CalendarPickerSelectedType::DAY);
965 }
966 }
967
InitTitleArrowsEvent()968 void CalendarDialogPattern::InitTitleArrowsEvent()
969 {
970 auto host = GetHost();
971 CHECK_NULL_VOID(host);
972 auto title = host->GetChildAtIndex(TITLE_NODE_INDEX);
973 CHECK_NULL_VOID(title);
974 for (const auto& child : title->GetChildren()) {
975 CHECK_NULL_VOID(child);
976 if (child->GetTag() == V2::TEXT_ETS_TAG) {
977 continue;
978 }
979 int32_t childIndex = title->GetChildIndex(child);
980 auto buttonNode = AceType::DynamicCast<FrameNode>(child);
981 CHECK_NULL_VOID(buttonNode);
982 auto event = [childIndex, wp = WeakClaim(this)](GestureEvent& /* info */) {
983 auto pattern = wp.Upgrade();
984 if (pattern) {
985 pattern->HandleTitleArrowsClickEvent(childIndex);
986 }
987 };
988
989 auto buttonNodeId = buttonNode->GetId();
990 if (clickEvents_.find(buttonNodeId) == clickEvents_.end()) {
991 auto gestureHub = buttonNode->GetOrCreateGestureEventHub();
992 CHECK_NULL_VOID(gestureHub);
993 auto clickEvent = AceType::MakeRefPtr<ClickEvent>(std::move(event));
994 clickEvents_[buttonNodeId] = clickEvent;
995 gestureHub->AddClickEvent(clickEvent);
996 }
997 }
998 }
999
HandleTitleArrowsClickEvent(int32_t nodeIndex)1000 void CalendarDialogPattern::HandleTitleArrowsClickEvent(int32_t nodeIndex)
1001 {
1002 auto swiperPattern = GetSwiperPattern();
1003 CHECK_NULL_VOID(swiperPattern);
1004 swiperPattern->GetSwiperController()->FinishAnimation();
1005
1006 auto calendarPattern = GetCalendarPattern();
1007 CHECK_NULL_VOID(calendarPattern);
1008 ObtainedMonth currentObtainedMonth = calendarPattern->GetCurrentMonthData();
1009 CalendarMonth currentMonth { .year = currentObtainedMonth.year, .month = currentObtainedMonth.month };
1010
1011 calendarPattern->SetDialogClickEventState(true);
1012 switch (nodeIndex) {
1013 case TITLE_LAST_YEAR_BUTTON_NODE_INDEX: {
1014 currentMonth.year = currentMonth.year == MIN_YEAR ? MAX_YEAR : currentMonth.year - 1;
1015 ObtainedMonth monthData;
1016 GetCalendarMonthData(currentMonth.year, currentMonth.month, monthData);
1017 UpdateSwiperNode(monthData, true);
1018 break;
1019 }
1020 case TITLE_LAST_MONTH_BUTTON_NODE_INDEX: {
1021 swiperPattern->ShowPrevious();
1022 break;
1023 }
1024 case TITLE_NEXT_MONTH_BUTTON_NODE_INDEX: {
1025 swiperPattern->ShowNext();
1026 break;
1027 }
1028 case TITLE_NEXT_YEAR_BUTTON_NODE_INDEX: {
1029 currentMonth.year = currentMonth.year == MAX_YEAR ? MIN_YEAR : currentMonth.year + 1;
1030 ObtainedMonth monthData;
1031 GetCalendarMonthData(currentMonth.year, currentMonth.month, monthData);
1032 UpdateSwiperNode(monthData, false);
1033 break;
1034 }
1035 default:
1036 break;
1037 }
1038 }
1039
GetCalendarMonthData(int32_t year,int32_t month,ObtainedMonth & calendarMonthData)1040 void CalendarDialogPattern::GetCalendarMonthData(int32_t year, int32_t month, ObtainedMonth& calendarMonthData)
1041 {
1042 calendarMonthData.year = year;
1043 calendarMonthData.month = month;
1044 calendarMonthData.firstDayIndex = 0;
1045
1046 CalendarMonth currentMonth { .year = year, .month = month };
1047
1048 int32_t currentMonthMaxDay = static_cast<int32_t>(PickerDate::GetMaxDay(year, month));
1049 int32_t preMonthMaxDay =
1050 static_cast<int32_t>(PickerDate::GetMaxDay(GetLastMonth(currentMonth).year, GetLastMonth(currentMonth).month));
1051 int32_t preMonthDaysCount = (Date::CalculateWeekDay(year, month, 1) + 1) % WEEK_DAYS;
1052 int32_t nextMonthDaysCount = 6 - ((Date::CalculateWeekDay(year, month, currentMonthMaxDay) + 1) % WEEK_DAYS);
1053
1054 int32_t index = 0;
1055 for (int32_t i = 0; i < preMonthDaysCount; i++, index++) {
1056 calendarMonthData.days.emplace_back(CalendarDay { .index = index,
1057 .day = preMonthMaxDay - preMonthDaysCount + index + 1,
1058 .month = GetLastMonth(currentMonth) });
1059 }
1060
1061 for (int32_t i = 0; i < currentMonthMaxDay; i++, index++) {
1062 calendarMonthData.days.emplace_back(CalendarDay { .index = index, .day = i + 1, .month = currentMonth });
1063 }
1064
1065 for (int32_t i = 0; i < nextMonthDaysCount; i++, index++) {
1066 calendarMonthData.days.emplace_back(
1067 CalendarDay { .index = index, .day = i + 1, .month = GetNextMonth(currentMonth) });
1068 }
1069
1070 auto calendarPattern = GetCalendarPattern();
1071 CHECK_NULL_VOID(calendarPattern);
1072 PickerDate selectedDay = calendarPattern->GetSelectedDay();
1073 for (size_t i = 0; i < calendarMonthData.days.size(); i++) {
1074 calendarMonthData.days[i].isKeyFocused = isFocused_
1075 ? ((focusedDay_.month.year == calendarMonthData.year) &&
1076 (focusedDay_.month.month == calendarMonthData.month) &&
1077 (focusedDay_.month == calendarMonthData.days[i].month) &&
1078 (focusedDay_.day == calendarMonthData.days[i].day))
1079 : false;
1080 calendarMonthData.days[i].isSelected =
1081 (selectedDay.GetYear() == static_cast<uint32_t>(calendarMonthData.year)) &&
1082 (selectedDay.GetMonth() == static_cast<uint32_t>(calendarMonthData.month)) &&
1083 (selectedDay.GetYear() == static_cast<uint32_t>(calendarMonthData.days[i].month.year)) &&
1084 (selectedDay.GetMonth() == static_cast<uint32_t>(calendarMonthData.days[i].month.month)) &&
1085 (selectedDay.GetDay() == static_cast<uint32_t>(calendarMonthData.days[i].day));
1086 }
1087 }
1088
AddHotZoneRect()1089 void CalendarDialogPattern::AddHotZoneRect()
1090 {
1091 auto entryNode = entryNode_.Upgrade();
1092 CHECK_NULL_VOID(entryNode);
1093 auto rect = entryNode->GetPaintRectWithTransform();
1094 DimensionRect hotZoneRegion;
1095 hotZoneRegion.SetSize(DimensionSize(
1096 Dimension(rect.Width()), Dimension(rect.Height())));
1097 hotZoneRegion.SetOffset(DimensionOffset(
1098 Dimension(rect.Left() - dialogOffset_.GetX()), Dimension(rect.Top() - dialogOffset_.GetY())));
1099
1100 auto host = GetHost();
1101 CHECK_NULL_VOID(host);
1102 auto geometryNode = host->GetGeometryNode();
1103 CHECK_NULL_VOID(geometryNode);
1104 DimensionRect hotZoneRegionHost;
1105 hotZoneRegionHost.SetSize(DimensionSize(
1106 Dimension(geometryNode->GetFrameRect().Width()), Dimension(geometryNode->GetFrameRect().Height())));
1107
1108 host->AddHotZoneRect(hotZoneRegion);
1109 host->AddHotZoneRect(hotZoneRegionHost);
1110 }
1111
FireChangeByKeyEvent(PickerDate & selectedDay)1112 void CalendarDialogPattern::FireChangeByKeyEvent(PickerDate& selectedDay)
1113 {
1114 auto calendarNode = GetCalendarFrameNode();
1115 CHECK_NULL_VOID(calendarNode);
1116
1117 auto swiperNode = AceType::DynamicCast<FrameNode>(calendarNode->GetFirstChild());
1118 CHECK_NULL_VOID(swiperNode);
1119 auto swiperPattern = swiperNode->GetPattern<SwiperPattern>();
1120 CHECK_NULL_VOID(swiperPattern);
1121 auto monthNode = AceType::DynamicCast<FrameNode>(swiperNode->GetChildAtIndex(swiperPattern->GetCurrentIndex()));
1122 CHECK_NULL_VOID(monthNode);
1123 auto eventHub = monthNode->GetEventHub<CalendarEventHub>();
1124 CHECK_NULL_VOID(eventHub);
1125 eventHub->UpdateSelectedChangeEvent(selectedDay.ToString(true));
1126 }
1127
GetNextMonth(const CalendarMonth & calendarMonth)1128 CalendarMonth CalendarDialogPattern::GetNextMonth(const CalendarMonth& calendarMonth)
1129 {
1130 CalendarMonth nextMonth = calendarMonth;
1131 if (calendarMonth.month + 1 > MAX_MONTH) {
1132 nextMonth.month = 1;
1133 nextMonth.year = nextMonth.year == MAX_YEAR ? MIN_YEAR : nextMonth.year + 1;
1134 } else {
1135 ++nextMonth.month;
1136 }
1137 return nextMonth;
1138 }
1139
GetLastMonth(const CalendarMonth & calendarMonth)1140 CalendarMonth CalendarDialogPattern::GetLastMonth(const CalendarMonth& calendarMonth)
1141 {
1142 CalendarMonth lastMonth = calendarMonth;
1143 if (calendarMonth.month - 1 <= 0) {
1144 lastMonth.month = MAX_MONTH;
1145 lastMonth.year = lastMonth.year == MIN_YEAR ? MAX_YEAR : lastMonth.year - 1;
1146 } else {
1147 --lastMonth.month;
1148 }
1149 return lastMonth;
1150 }
1151
GetIndexByFocusedDay()1152 int32_t CalendarDialogPattern::GetIndexByFocusedDay()
1153 {
1154 ObtainedMonth monthData;
1155 GetCalendarMonthData(focusedDay_.month.year, focusedDay_.month.month, monthData);
1156 auto it = std::find_if(monthData.days.begin(), monthData.days.end(),
1157 [this](CalendarDay day) {
1158 return day.day == focusedDay_.day && day.month == focusedDay_.month;
1159 });
1160 if (it != monthData.days.end()) {
1161 return it->index;
1162 }
1163 return -1;
1164 }
1165
HandleEntryLayoutChange()1166 void CalendarDialogPattern::HandleEntryLayoutChange()
1167 {
1168 auto entryNode = entryNode_.Upgrade();
1169 CHECK_NULL_VOID(entryNode);
1170 auto host = GetHost();
1171 CHECK_NULL_VOID(host);
1172 auto wrapperNode = host->GetParent();
1173 CHECK_NULL_VOID(wrapperNode);
1174 auto dialogNode = AceType::DynamicCast<FrameNode>(wrapperNode->GetParent());
1175 CHECK_NULL_VOID(dialogNode);
1176 auto dialogLayoutProp = dialogNode->GetLayoutProperty<DialogLayoutProperty>();
1177 CHECK_NULL_VOID(dialogLayoutProp);
1178 auto pattern = entryNode->GetPattern<CalendarPickerPattern>();
1179 CHECK_NULL_VOID(pattern);
1180 dialogLayoutProp->UpdateDialogOffset(DimensionOffset(pattern->CalculateDialogOffset()));
1181 dialogOffset_ = pattern->CalculateDialogOffset();
1182 dialogNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1183 isFirstAddhotZoneRect_ = false;
1184 }
1185
HandleEntryChange(const std::string & info)1186 void CalendarDialogPattern::HandleEntryChange(const std::string& info)
1187 {
1188 auto calendarNode = GetCalendarFrameNode();
1189 CHECK_NULL_VOID(calendarNode);
1190 auto calendarPattern = calendarNode->GetPattern<CalendarPattern>();
1191 CHECK_NULL_VOID(calendarPattern);
1192
1193 auto calendarJson = JsonUtil::ParseJsonString(calendarPattern->GetSelectDate());
1194 auto entryJson = JsonUtil::ParseJsonString(info);
1195 auto entryYear = entryJson->GetUInt("year");
1196 auto entryMonth = entryJson->GetUInt("month");
1197 auto entryDay = entryJson->GetUInt("day");
1198
1199 PickerDate selectedDay = PickerDate(entryYear, entryMonth, entryDay);
1200 if (entryYear != calendarJson->GetUInt("year") || entryMonth != calendarJson->GetUInt("month")) {
1201 CalendarData calendarData;
1202 CalendarMonth calendarMonth { .year = entryYear, .month = entryMonth };
1203
1204 GetCalendarMonthData(entryYear, entryMonth, calendarData.currentData);
1205 calendarPattern->SetCurrentMonthData(calendarData.currentData);
1206 GetCalendarMonthData(
1207 GetLastMonth(calendarMonth).year, GetLastMonth(calendarMonth).month, calendarData.preData);
1208 calendarPattern->SetPreMonthData(calendarData.preData);
1209 GetCalendarMonthData(
1210 GetNextMonth(calendarMonth).year, GetNextMonth(calendarMonth).month, calendarData.nextData);
1211 calendarPattern->SetNextMonthData(calendarData.nextData);
1212 }
1213
1214 calendarPattern->SetSelectedDay(selectedDay);
1215 calendarNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_CHILD);
1216 calendarNode->MarkModifyDone();
1217 }
1218
GetCalendarFrameNode()1219 RefPtr<FrameNode> CalendarDialogPattern::GetCalendarFrameNode()
1220 {
1221 auto host = GetHost();
1222 CHECK_NULL_RETURN(host, nullptr);
1223 auto calendarNode = host->GetChildAtIndex(CALENDAR_NODE_INDEX);
1224 return AceType::DynamicCast<FrameNode>(calendarNode);
1225 }
1226
GetCalendarPattern()1227 RefPtr<CalendarPattern> CalendarDialogPattern::GetCalendarPattern()
1228 {
1229 auto calendarFrameNode = GetCalendarFrameNode();
1230 CHECK_NULL_RETURN(calendarFrameNode, nullptr);
1231 return calendarFrameNode->GetPattern<CalendarPattern>();
1232 }
1233
GetSwiperFrameNode()1234 RefPtr<FrameNode> CalendarDialogPattern::GetSwiperFrameNode()
1235 {
1236 auto calendarFrameNode = GetCalendarFrameNode();
1237 CHECK_NULL_RETURN(calendarFrameNode, nullptr);
1238 if (calendarFrameNode->GetChildren().empty()) {
1239 return nullptr;
1240 }
1241 auto swiperNode = calendarFrameNode->GetChildren().front();
1242 CHECK_NULL_RETURN(swiperNode, nullptr);
1243 return AceType::DynamicCast<FrameNode>(swiperNode);
1244 }
1245
GetSwiperPattern()1246 RefPtr<SwiperPattern> CalendarDialogPattern::GetSwiperPattern()
1247 {
1248 auto swiperFrameNode = GetSwiperFrameNode();
1249 CHECK_NULL_RETURN(swiperFrameNode, nullptr);
1250 return swiperFrameNode->GetPattern<SwiperPattern>();
1251 }
1252
OnEnterKeyEvent(const KeyEvent & event)1253 void CalendarDialogPattern::OnEnterKeyEvent(const KeyEvent& event)
1254 {
1255 bool checkKeyCode = (event.code == KeyCode::KEY_ENTER || event.code == KeyCode::KEY_NUMPAD_ENTER ||
1256 event.code == KeyCode::KEY_SPACE);
1257 if (!checkKeyCode) {
1258 return;
1259 }
1260 auto host = GetHost();
1261 CHECK_NULL_VOID(host);
1262 auto options = host->GetChildAtIndex(OPTIONS_NODE_INDEX);
1263 CHECK_NULL_VOID(options);
1264
1265 for (const auto& child : options->GetChildren()) {
1266 CHECK_NULL_VOID(child);
1267 if (child->GetTag() != V2::BUTTON_ETS_TAG) {
1268 continue;
1269 }
1270 auto button = AceType::DynamicCast<FrameNode>(child);
1271 CHECK_NULL_VOID(button);
1272 auto focusHub = button->GetOrCreateFocusHub();
1273 if (focusHub && focusHub->IsDefaultFocus()) {
1274 auto gesture = button->GetOrCreateGestureEventHub();
1275 CHECK_NULL_VOID(gesture);
1276 gesture->ActClick();
1277 }
1278 }
1279 }
1280
OnLanguageConfigurationUpdate()1281 void CalendarDialogPattern::OnLanguageConfigurationUpdate()
1282 {
1283 auto host = GetHost();
1284 CHECK_NULL_VOID(host);
1285 auto calendarNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(CALENDAR_NODE_INDEX));
1286 CHECK_NULL_VOID(calendarNode);
1287 auto swiperNode = AceType::DynamicCast<FrameNode>(calendarNode->GetFirstChild());
1288 CHECK_NULL_VOID(swiperNode);
1289
1290 for (auto&& child : swiperNode->GetChildren()) {
1291 auto monthFrameNode = AceType::DynamicCast<FrameNode>(child);
1292 CHECK_NULL_VOID(monthFrameNode);
1293 auto pipelineContext = GetContext();
1294 CHECK_NULL_VOID(pipelineContext);
1295 RefPtr<CalendarTheme> theme = pipelineContext->GetTheme<CalendarTheme>();
1296 CHECK_NULL_VOID(theme);
1297
1298 auto fontSizeScale = pipelineContext->GetFontScale();
1299 auto fontSize = theme->GetCalendarDayFontSize();
1300 if (AceApplicationInfo::GetInstance().GetLanguage() != "zh") {
1301 ACE_UPDATE_NODE_PAINT_PROPERTY(
1302 CalendarPaintProperty, WeekFontSize, theme->GetCalendarSmallDayFontSize(), monthFrameNode);
1303 } else {
1304 if (fontSizeScale < theme->GetCalendarPickerLargeScale() || CalendarDialogView::CheckOrientationChange()) {
1305 ACE_UPDATE_NODE_PAINT_PROPERTY(CalendarPaintProperty, WeekFontSize, fontSize, monthFrameNode);
1306 } else {
1307 fontSizeScale = fontSizeScale > theme->GetCalendarPickerLargerScale()
1308 ? theme->GetCalendarPickerLargerScale()
1309 : fontSizeScale;
1310 ACE_UPDATE_NODE_PAINT_PROPERTY(
1311 CalendarPaintProperty, WeekFontSize, fontSize * fontSizeScale, monthFrameNode);
1312 }
1313 }
1314 monthFrameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1315 }
1316 }
1317
InitSurfaceChangedCallback()1318 void CalendarDialogPattern::InitSurfaceChangedCallback()
1319 {
1320 auto pipelineContext = GetContext();
1321 CHECK_NULL_VOID(pipelineContext);
1322 if (!HasSurfaceChangedCallback()) {
1323 auto callbackId = pipelineContext->RegisterSurfaceChangedCallback(
1324 [weak = WeakClaim(this)](int32_t newWidth, int32_t newHeight, int32_t prevWidth, int32_t prevHeight,
1325 WindowSizeChangeReason type) {
1326 auto pattern = weak.Upgrade();
1327 if (pattern) {
1328 pattern->HandleSurfaceChanged(newWidth, newHeight, prevWidth, prevHeight);
1329 }
1330 });
1331 UpdateSurfaceChangedCallbackId(callbackId);
1332 }
1333 }
1334
HandleSurfaceChanged(int32_t newWidth,int32_t newHeight,int32_t prevWidth,int32_t prevHeight)1335 void CalendarDialogPattern::HandleSurfaceChanged(
1336 int32_t newWidth, int32_t newHeight, int32_t prevWidth, int32_t prevHeight)
1337 {
1338 if (newWidth == prevWidth && newHeight == prevHeight) {
1339 return;
1340 }
1341
1342 auto tmpHost = GetHost();
1343 CHECK_NULL_VOID(tmpHost);
1344 tmpHost->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1345 UpdateCaretInfoToController();
1346 }
1347
UpdateCaretInfoToController()1348 void CalendarDialogPattern::UpdateCaretInfoToController()
1349 {
1350 auto host = GetHost();
1351 CHECK_NULL_VOID(host);
1352 auto titleNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(TITLE_NODE_INDEX));
1353 CHECK_NULL_VOID(titleNode);
1354 auto layoutProps = titleNode->GetLayoutProperty<LinearLayoutProperty>();
1355 CHECK_NULL_VOID(layoutProps);
1356 auto pipelineContext = GetContext();
1357 CHECK_NULL_VOID(pipelineContext);
1358 auto calendarTheme = pipelineContext->GetTheme<CalendarTheme>();
1359 CHECK_NULL_VOID(calendarTheme);
1360 auto calendarNode = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(CALENDAR_NODE_INDEX));
1361 CHECK_NULL_VOID(calendarNode);
1362 auto calendarLayoutProperty = calendarNode->GetLayoutProperty();
1363 CHECK_NULL_VOID(calendarLayoutProperty);
1364 CalendarDialogView::UpdateIdealSize(calendarTheme, layoutProps, calendarLayoutProperty);
1365
1366 auto swiperNode = AceType::DynamicCast<FrameNode>(calendarNode->GetFirstChild());
1367 CHECK_NULL_VOID(swiperNode);
1368 for (auto&& child : swiperNode->GetChildren()) {
1369 auto monthFrameNode = AceType::DynamicCast<FrameNode>(child);
1370 CHECK_NULL_VOID(monthFrameNode);
1371 auto monthPattern = monthFrameNode->GetPattern<CalendarMonthPattern>();
1372 CHECK_NULL_VOID(monthPattern);
1373 CalendarDialogView::UpdatePaintProperties(monthFrameNode, currentSettingData_);
1374 monthPattern->UpdateColRowSpace();
1375 monthFrameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1376 }
1377
1378 if (host->GetTotalChildCount() > OPTIONS_NODE_INDEX) {
1379 auto contentRow = AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(OPTIONS_NODE_INDEX));
1380 CHECK_NULL_VOID(contentRow);
1381 size_t buttonIndex = OPTION_CANCEL_BUTTON_INDEX;
1382 for (auto&& child : contentRow->GetChildren()) {
1383 auto buttonNode = AceType::DynamicCast<FrameNode>(child);
1384 CHECK_NULL_VOID(buttonNode);
1385 CalendarDialogView::UpdateButtons(buttonNode, buttonIndex, currentButtonInfos_);
1386 buttonIndex++;
1387 }
1388 }
1389
1390 auto calendarPattern = GetCalendarPattern();
1391 CHECK_NULL_VOID(calendarPattern);
1392 calendarPattern->UpdateTitleNode();
1393
1394 auto wrapperNode = host->GetParent();
1395 CHECK_NULL_VOID(wrapperNode);
1396 auto dialogNode = AceType::DynamicCast<FrameNode>(wrapperNode->GetParent());
1397 CHECK_NULL_VOID(dialogNode);
1398 dialogNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
1399 CalendarDialogView::SetPreviousOrientation();
1400 }
1401 } // namespace OHOS::Ace::NG
1402