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