1 /*
2  * Copyright (c) 2021 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/calendar/calendar_element.h"
17 
18 #include "base/i18n/localization.h"
19 #include "core/components/calendar/calendar_component_v2.h"
20 #include "core/components/calendar/render_calendar.h"
21 #include "core/components/display/render_display.h"
22 #include "core/components/swiper/swiper_element.h"
23 
24 namespace OHOS::Ace {
25 namespace {
26 
27 constexpr int REGISTER_CHANGE_LISTENER_ID = 1003;
28 
29 }
30 
PerformBuild()31 void CalendarElement::PerformBuild()
32 {
33     RefPtr<CalendarComponent> calendar = AceType::DynamicCast<CalendarComponent>(component_);
34     if (!calendar) {
35         LOGE("Can not dynamicCast to CalendarComponent!");
36         return;
37     }
38 
39     if (!calendarController_) {
40         calendarController_ = AceType::MakeRefPtr<CalendarController>(calendar->GetDataAdapterAction(), context_);
41         UpdateAttr(calendar);
42         calendarController_->Initialize();
43         auto calendarV2 = AceType::DynamicCast<CalendarComponentV2>(calendar);
44         if (calendarV2) {
45             auto controllerV2 = calendarV2->GetControllerV2();
46             if (controllerV2) {
47                 controllerV2->SetCalendarController(calendarController_);
48             }
49         }
50     } else {
51         auto calendarV2 = AceType::DynamicCast<CalendarComponentV2>(calendar);
52         if (calendarV2) {
53             auto dataAdapter = calendarController_->GetDataAdapter();
54             dataAdapter->ParseCalendarData(calendarV2->GetObtainedMonths());
55             auto controllerV2 = calendarV2->GetControllerV2();
56             if (controllerV2) {
57                 controllerV2->SetCalendarController(calendarController_);
58             }
59         }
60         calendarController_->UpdateTheme();
61         UpdateAttr(calendar);
62         return;
63     }
64 
65     const auto& child = children_.empty() ? nullptr : children_.front();
66     auto newComponent = calendar->Build(GetContext(), calendarController_);
67     auto childElement = UpdateChild(child, newComponent);
68     auto element = childElement;
69     if (calendar->IsCardCalendar()) {
70         BuildCardCalendar(calendar, childElement);
71         element = childElement->GetChildren().back();
72     }
73 
74     auto swiperElement = AceType::DynamicCast<SwiperElement>(element);
75 
76     calendarController_->SetRequestFocusImpl([weak = WeakClaim(this)]() {
77         auto element = weak.Upgrade();
78         if (!element) {
79             return;
80         }
81         element->RequestFocus();
82     });
83     if (swiperElement) {
84         renderSwiper_ = AceType::DynamicCast<RenderSwiper>(swiperElement->GetRenderNode());
85         if (renderSwiper_) {
86             calendarController_->SetRenderSwiper(renderSwiper_);
87         }
88     }
89     RegisterChangeEndListener(calendar, childElement);
90     RequestFocusImmediately();
91 }
92 
RegisterChangeEndListener(const RefPtr<CalendarComponent> & calendar,const RefPtr<Element> & element)93 void CalendarElement::RegisterChangeEndListener(
94     const RefPtr<CalendarComponent>& calendar, const RefPtr<Element>& element)
95 {
96     if (!calendar->IsCardCalendar()) {
97         return;
98     }
99     auto children = element->GetChildren().front()->GetChildren();
100     int32_t index = 0;
101     RefPtr<Element> flex;
102     for (const auto& item : children) {
103         if (index == 1) {
104             flex = item;
105             break;
106         }
107         ++index;
108     }
109 
110     auto text = GetTextElement(flex);
111     CHECK_NULL_VOID(text);
112     auto renderText = AceType::DynamicCast<RenderText>(text->GetRenderNode());
113     CHECK_NULL_VOID(renderSwiper_);
114     auto onChanged = [text = WeakClaim(RawPtr(renderText)), weakController = WeakClaim(RawPtr(calendarController_))](
115                          bool index) {
116         auto controller = weakController.Upgrade();
117         CHECK_NULL_VOID(controller);
118         auto renderText = text.Upgrade();
119         CHECK_NULL_VOID(renderText);
120         auto currentDate = controller->GetCurrentMonth();
121         DateTime dateTime;
122         dateTime.year = currentDate.year < 0 ? 0 : static_cast<uint32_t>(currentDate.year);
123         dateTime.month = currentDate.month < 0 ? 0 : static_cast<uint32_t>(currentDate.month);
124         auto date = Localization::GetInstance()->FormatDateTime(dateTime, "yyyyMMM");
125         auto textComponent = AceType::MakeRefPtr<TextComponent>(date);
126         auto cardTheme = renderText->GetTheme<CalendarTheme>();
127         CHECK_NULL_VOID(cardTheme);
128         TextStyle style;
129         style.SetFontSize(cardTheme->GetCardCalendarTheme().titleFontSize);
130         style.SetTextColor(cardTheme->GetCardCalendarTheme().titleTextColor);
131         style.SetFontWeight(FontWeight::W500);
132         style.SetAllowScale(false);
133         textComponent->SetTextStyle(style);
134         renderText->Update(textComponent);
135         renderText->MarkNeedLayout();
136     };
137     renderSwiper_->RegisterChangeEndListener(REGISTER_CHANGE_LISTENER_ID, onChanged);
138 }
139 
BuildCardCalendar(const RefPtr<CalendarComponent> & calendar,const RefPtr<Element> & element)140 void CalendarElement::BuildCardCalendar(const RefPtr<CalendarComponent>& calendar, const RefPtr<Element>& element)
141 {
142     if (!element || !element->GetChildren().front()) {
143         return;
144     }
145     auto children = element->GetChildren().front()->GetChildren();
146     int32_t index = 0;
147     RefPtr<Element> flex;
148     for (const auto& item : children) {
149         if (index == 0) {
150             SetArrowImage(item, true);
151         }
152         if (index == 1) {
153             flex = item;
154         }
155         if (index == 2) {
156             SetArrowImage(item, false);
157         }
158         ++index;
159     }
160     auto text = GetTextElement(flex);
161     if (!text) {
162         LOGE("Get text element error");
163         return;
164     }
165     auto renderText = AceType::DynamicCast<RenderText>(text->GetRenderNode());
166     calendarController_->SetCardTitle(renderText);
167     auto buttonCallback = [weak = WeakClaim(RawPtr(calendar)), text = WeakClaim(RawPtr(renderText)),
168                               weakController = WeakClaim(RawPtr(calendarController_))](bool pre) {
169         auto calendar = weak.Upgrade();
170         auto controller = weakController.Upgrade();
171         if (!controller || !calendar) {
172             LOGE("build arrow callback error");
173             return;
174         }
175         auto swiper = controller->GetRenderSwiper();
176         if (!swiper) {
177             return;
178         }
179         if (swiper->GetMoveStatus()) {
180             return;
181         }
182         if (controller->GetCurrentIndex() != swiper->GetCurrentIndex()) {
183             return;
184         }
185         pre ? controller->GoToPrevMonth(1) : controller->GoToNextMonth(1);
186     };
187     BackEndEventManager<void()>::GetInstance().BindBackendEvent(calendar->GetPreClickId(), [buttonCallback]() {
188         AceApplicationInfo::GetInstance().IsRightToLeft() ? buttonCallback(false) : buttonCallback(true);
189     });
190     BackEndEventManager<void()>::GetInstance().BindBackendEvent(calendar->GetNextClickId(), [buttonCallback]() {
191         AceApplicationInfo::GetInstance().IsRightToLeft() ? buttonCallback(true) : buttonCallback(false);
192     });
193     dateEvent_ = AceAsyncEvent<void(const std::string&)>::Create(calendar->GetSelectedChangeEvent(), context_);
194     BackEndEventManager<void()>::GetInstance().BindBackendEvent(calendar->GetDateClickId(),
195         [date = dateEvent_, weakController = WeakPtr<CalendarController>(calendarController_)]() {
196             auto controller = weakController.Upgrade();
197             if (!controller) {
198                 LOGE("build calendar title callback error");
199                 return;
200             }
201             if (!date) {
202                 return;
203             }
204             auto currentDate = controller->GetCurrentMonth();
205             auto today = controller->GetToday();
206             auto json = JsonUtil::Create(true);
207             today.month == currentDate ? json->Put("day", today.day) : json->Put("day", 1);
208             json->Put("month", currentDate.month);
209             json->Put("year", currentDate.year);
210             date(json->ToString());
211         });
212 }
213 
UpdateAttr(const RefPtr<CalendarComponent> & calendar)214 void CalendarElement::UpdateAttr(const RefPtr<CalendarComponent>& calendar)
215 {
216     auto dataAdapter = calendarController_->GetDataAdapter();
217     if (!dataAdapter) {
218         return;
219     }
220     if (calendar->IsSetToday()) {
221         auto today = dataAdapter->GetToday();
222         auto date = calendar->GetDate();
223         if (today.day != date.day || today.month != date.month) {
224             calendarController_->SetToday(date);
225             calendarController_->GoTo(date.month.year, date.month.month, date.day);
226             calendarController_->UpdateTitle(date);
227         }
228     }
229     CardCalendarAttr attr;
230     attr.startDayOfWeek = calendar->GetStartDayOfWeek();
231     attr.showLunar = calendar->IsShowLunar();
232     attr.textDirection = calendar->GetTextDirection();
233     attr.cardCalendar = calendar->IsCardCalendar();
234     attr.requestData = calendar->GetRequestDataEvent();
235     attr.showHoliday = calendar->GetShowHoliday();
236     attr.needSlide = calendar->IsNeedSlide();
237     attr.offDays = calendar->GetOffDays();
238     attr.holidays = calendar->GetHolidays();
239     attr.workDays = calendar->GetWorkDays();
240     attr.axis = calendar->GetAxis();
241 
242     auto calendarV2 = AceType::DynamicCast<CalendarComponentV2>(calendar);
243     if (calendarV2) {
244         attr.isV2Component = true;
245     }
246     attr.calendarTheme = calendar->GetCalendarTheme();
247     attr.type = calendar->GetCalendarType();
248     dataAdapter->UpdateCardCalendarAttr(std::move(attr));
249 }
250 
SetArrowImage(const RefPtr<Element> & element,bool isLeft)251 void CalendarElement::SetArrowImage(const RefPtr<Element>& element, bool isLeft)
252 {
253     if (!element) {
254         return;
255     }
256     auto imageElement = element->GetChildren().front();
257     if (!imageElement) {
258         return;
259     }
260     auto image = AceType::DynamicCast<RenderImage>(imageElement->GetRenderNode());
261     if (image) {
262         isLeft ? calendarController_->SetLeftRowImage(image) : calendarController_->SetRightRowImage(image);
263     }
264 }
265 
GetTextElement(const RefPtr<Element> & flex)266 RefPtr<TextElement> CalendarElement::GetTextElement(const RefPtr<Element>& flex)
267 {
268     auto element = flex;
269     while (element && element->GetChildren().front()) {
270         element = element->GetChildren().front();
271     }
272     return AceType::DynamicCast<TextElement>(element);
273 }
274 
Update()275 void CalendarMonthElement::Update()
276 {
277     RenderElement::Update();
278 }
279 
OnKeyEvent(const KeyEvent & keyEvent)280 bool CalendarMonthElement::OnKeyEvent(const KeyEvent& keyEvent)
281 {
282     if (keyEvent.action != KeyAction::UP) {
283         return false;
284     }
285 
286     auto display = AceType::DynamicCast<RenderDisplay>(renderNode_->GetParent().Upgrade());
287     if (display) {
288         auto swiper = AceType::DynamicCast<RenderSwiper>(display->GetParent().Upgrade());
289         if (swiper) {
290             if (swiper->GetMoveStatus()) {
291                 return true;
292             }
293         }
294     }
295 
296     switch (keyEvent.code) {
297         case KeyCode::TV_CONTROL_UP:
298             return RequestNextFocus(true, true, GetRect());
299         case KeyCode::TV_CONTROL_DOWN:
300             return RequestNextFocus(true, false, GetRect());
301         case KeyCode::TV_CONTROL_LEFT:
302             return RequestNextFocus(false, true, GetRect());
303         case KeyCode::TV_CONTROL_RIGHT:
304             return RequestNextFocus(false, false, GetRect());
305         case KeyCode::KEY_TAB:
306             return RequestNextFocus(false, false, GetRect()) || RequestNextFocus(true, false, GetRect());
307         default:
308             return false;
309     }
310 }
311 
RequestNextFocus(bool vertical,bool reverse,const Rect & rect)312 bool CalendarMonthElement::RequestNextFocus(bool vertical, bool reverse, const Rect& rect)
313 {
314     RefPtr<FocusableGrid> focusableGrid = AceType::DynamicCast<FocusableGrid>(renderNode_);
315     if (!focusableGrid) {
316         LOGE("focusable grid is null.");
317         return false;
318     }
319     bool needFocus = focusableGrid->RequestNextFocus(vertical, reverse) >= 0;
320     if (needFocus) {
321         auto calendar = DynamicCast<RenderCalendar>(renderNode_);
322         if (!calendar) {
323             LOGE("get render node failed");
324             return false;
325         }
326         calendar->MarkNeedRender();
327     }
328     return needFocus;
329 }
330 
OnFocus()331 void CalendarMonthElement::OnFocus()
332 {
333     if (renderNode_) {
334         renderNode_->ChangeStatus(RenderStatus::FOCUS);
335     }
336 }
337 
OnBlur()338 void CalendarMonthElement::OnBlur()
339 {
340     if (renderNode_) {
341         renderNode_->ChangeStatus(RenderStatus::BLUR);
342     }
343 }
344 
345 } // namespace OHOS::Ace
346