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