1 /*
2 * Copyright (c) 2021-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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_CALENDAR_CALENDAR_DATA_ADAPTER_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_CALENDAR_CALENDAR_DATA_ADAPTER_H
18
19 #include <array>
20 #include <functional>
21 #include <map>
22 #include <queue>
23 #include <vector>
24
25 #include "base/json/json_util.h"
26 #include "base/log/log.h"
27 #include "base/memory/ace_type.h"
28 #include "base/utils/string_utils.h"
29 #include "bridge/codec/codec_data.h"
30 #include "core/components/calendar/calendar_theme.h"
31 #include "core/event/ace_event_helper.h"
32 #include "core/pipeline/pipeline_context.h"
33
34 namespace OHOS::Ace {
35
36 constexpr int32_t CALENDAR_MIN_DATE_YEAR = 1970;
37 constexpr int32_t CALENDAR_MIN_DATE_MONTH = 1;
38 constexpr int32_t CALENDAR_INVALID = -1;
39 constexpr int32_t CALENDAR_FIRST_DAY_NUM_OF_MONTH = 1;
40 constexpr int32_t CALENDAR_TOTAL_MONTH_OF_YEAR = 12;
41 constexpr int32_t CALENDAR_CACHE_PAGE = 3;
42
43 struct CalendarMonth {
44 int32_t year = CALENDAR_MIN_DATE_YEAR;
45 // calendar month value is from 0 to 11
46 int32_t month = CALENDAR_MIN_DATE_MONTH;
47
48 bool operator==(const CalendarMonth& calendarMonth) const
49 {
50 return calendarMonth.month == month && calendarMonth.year == year;
51 }
52 bool operator!=(const CalendarMonth& calendarMonth) const
53 {
54 return calendarMonth.month != month || calendarMonth.year != year;
55 }
56 bool operator>(const CalendarMonth& calendarMonth) const
57 {
58 return year > calendarMonth.year || (year == calendarMonth.year && month > calendarMonth.month);
59 }
60 bool operator<(const CalendarMonth& calendarMonth) const
61 {
62 return year < calendarMonth.year || (year == calendarMonth.year && month < calendarMonth.month);
63 }
64
GetNextMonthCalendarMonth65 static CalendarMonth GetNextMonth(const CalendarMonth& calendarMonth)
66 {
67 CalendarMonth nextMonth = calendarMonth;
68 if (calendarMonth.month + 1 >= CALENDAR_TOTAL_MONTH_OF_YEAR) {
69 nextMonth.month = 0;
70 ++nextMonth.year;
71 } else {
72 ++nextMonth.month;
73 }
74 return nextMonth;
75 }
76
GetLastMonthCalendarMonth77 static CalendarMonth GetLastMonth(const CalendarMonth& calendarMonth)
78 {
79 CalendarMonth lastMonth = calendarMonth;
80 if (calendarMonth.month - 1 < 0) {
81 lastMonth.month = CALENDAR_TOTAL_MONTH_OF_YEAR - 1;
82 --lastMonth.year;
83 } else {
84 --lastMonth.month;
85 }
86 return lastMonth;
87 }
88
ToStringCalendarMonth89 std::string ToString() const
90 {
91 auto json = JsonUtil::Create(true);
92 json->Put("year", year);
93 json->Put("month", month);
94 return json->ToString();
95 }
96 };
97
98 struct HashFunc {
operatorHashFunc99 std::size_t operator()(const CalendarMonth& key) const
100 {
101 return ((std::hash<uint32_t>()(key.year) ^ (std::hash<uint32_t>()(key.month) << 1)) >> 1);
102 }
103 };
104
105 enum class MonthState {
106 CUR_MONTH,
107 PRE_MONTH,
108 NEXT_MONTH
109 };
110
111 struct CalendarDay {
112 int32_t index = 0;
113 int32_t day = 0;
114 bool weekend = false;
115 bool today = false;
116 bool focused = false;
117 bool touched = false;
118 bool isFirstOfLunar = false;
119 bool hasSchedule = false;
120 bool markLunarDay = false;
121
122 // For calendar selector
123 bool isHovering = false;
124 bool isPressing = false;
125 bool isSelected = false;
126 bool isKeyFocused = false;
127
128 std::string lunarMonth;
129 std::string lunarDay;
130 std::string dayMark;
131 std::string dayMarkValue;
132 CalendarMonth month;
133
134 static constexpr char INDEX[] { "index" };
135 static constexpr char DAY[] { "day" };
136 static constexpr char MONTH[] { "month" };
137 static constexpr char YEAR[] { "year" };
138 static constexpr char LUNAR_MONTH[] { "lunarMonth" };
139 static constexpr char LUNAR_DAY[] { "lunarDay" };
140 static constexpr char DAY_MARK[] { "dayMark" };
141 static constexpr char DAY_MARK_VALUE[] { "dayMarkValue" };
142
ToStringCalendarDay143 std::string ToString() const
144 {
145 auto json = JsonUtil::Create(true);
146 json->Put(DAY, day);
147 json->Put(INDEX, index);
148 json->Put(MONTH, month.month);
149 json->Put(YEAR, month.year);
150 json->Put(LUNAR_MONTH, lunarMonth.c_str());
151 json->Put(LUNAR_DAY, lunarDay.c_str());
152 return json->ToString();
153 }
154 };
155
156 struct CalendarDaysOfMonth {
157 CalendarMonth month;
158 int32_t firstDayIndex = CALENDAR_INVALID;
159 int32_t lastDayIndex = CALENDAR_INVALID;
160 int32_t today = CALENDAR_INVALID;
161 std::vector<CalendarDay> days;
162 };
163
164 struct CalendarDataRequest {
CalendarDataRequestCalendarDataRequest165 CalendarDataRequest(const CalendarMonth& month, int32_t indexOfContainer)
166 : month(month), indexOfContainer(indexOfContainer)
167 {}
168 ~CalendarDataRequest() = default;
169
170 int32_t selected = 0;
171 CalendarMonth month;
172 MonthState state = MonthState::CUR_MONTH;
173 int32_t indexOfContainer = 0;
174 };
175
176 struct CardCalendarAttr {
177 int32_t startDayOfWeek = 0;
178 bool isV2Component = false;
179 bool showLunar = true;
180 bool showHoliday = true;
181 bool needSlide = false;
182 bool cardCalendar = false;
183 bool listenersReady = true;
184 Axis axis = Axis::HORIZONTAL;
185 std::string offDays;
186 std::string holidays;
187 std::string workDays;
188 EventMarker requestData;
189 RefPtr<CalendarTheme> calendarTheme;
190 TextDirection textDirection = TextDirection::LTR;
191 CalendarType type { CalendarType::NORMAL };
192 };
193
194 struct ObtainedMonth {
195 int32_t year = 0;
196 int32_t month = 0;
197 int32_t firstDayIndex = CALENDAR_INVALID;
198 std::vector<CalendarDay> days;
199 };
200
201 using PendingRequestQueue = std::queue<CalendarDataRequest>;
202 using RequestDataCompleteCallback = std::function<void()>;
203
204 class CalendarDataChangeListener : public AceType {
205 DECLARE_ACE_TYPE(CalendarDataChangeListener, AceType);
206
207 public:
208 virtual void OnDataChanged(const CalendarDaysOfMonth& daysOfMonth) = 0;
209 virtual void OnSelectedDay(int32_t selected) = 0;
210 virtual void OnFocusChanged(bool focusStatus) = 0;
211 virtual void UpdateCardCalendarAttr(CardCalendarAttr&& attr) = 0;
212 virtual void OnSwiperMove() = 0;
213 };
214
215 struct DataAdapterAction {
216 std::string bundleName;
217 std::string abilityName;
218 int32_t messageCode = 0;
219 std::string data;
220
GetActionDataAdapterAction221 std::string GetAction()
222 {
223 return "{\"element\":{\"bundleName\":\"" + bundleName +
224 "\",\"name\":\"" + abilityName + "\",\"type\":1},\"code\":" +
225 std::to_string(messageCode) + "}";
226 }
227 };
228
229 struct CalendarDataAdapterAction : public DataAdapterAction {
GetDataCalendarDataAdapterAction230 std::string GetData(int32_t year, int32_t month)
231 {
232 return "{\"year\":" + std::to_string(year) + ",\"month\":" + std::to_string(month) + "}";
233 }
234
GetActionCalendarDataAdapterAction235 std::vector<Framework::CodecData> GetAction(int32_t year, int32_t month)
236 {
237 std::vector<Framework::CodecData> args;
238 Framework::CodecData header(DataAdapterAction::GetAction());
239 args.push_back(header);
240 Framework::CodecData params(GetData(year, month));
241 args.push_back(params);
242
243 return args;
244 }
245 };
246
247 class CalendarDataAdapter : public AceType {
248 DECLARE_ACE_TYPE(CalendarDataAdapter, AceType);
249
250 public:
251 explicit CalendarDataAdapter(
252 const CalendarDataAdapterAction& dataAdapterAction, const WeakPtr<PipelineContext>& pipelineContext);
253 ~CalendarDataAdapter() override = default;
254
RegisterDataListener(const RefPtr<CalendarDataChangeListener> & listener)255 void RegisterDataListener(const RefPtr<CalendarDataChangeListener>& listener)
256 {
257 allListeners_.push_back(listener);
258 if (allListeners_.size() == CALENDAR_CACHE_PAGE && !calendarAttr_.listenersReady) {
259 calendarAttr_.listenersReady = true;
260 for (const auto& listen : allListeners_) {
261 listen->UpdateCardCalendarAttr(std::move(calendarAttr_));
262 }
263 }
264 }
265
AddPendingRequest(const CalendarMonth & month,const int32_t indexOfContainer)266 void AddPendingRequest(const CalendarMonth& month, const int32_t indexOfContainer)
267 {
268 requestQueue_.emplace(month, indexOfContainer);
269 indexMap_[indexOfContainer] = month;
270 }
271
AddPendingRequest(const CalendarDataRequest & request)272 void AddPendingRequest(const CalendarDataRequest& request)
273 {
274 requestQueue_.emplace(request);
275 indexMap_[request.indexOfContainer] = request.month;
276 }
277
278 void RequestData(const CalendarDataRequest& request);
279
NotifySelectedChanged()280 void NotifySelectedChanged() const
281 {
282 int32_t listenersSize = static_cast<int32_t>(allListeners_.size());
283 if (indexOfContainer_ >= 0 && indexOfContainer_ < listenersSize) {
284 auto& listener = allListeners_[indexOfContainer_];
285 listener->OnSelectedDay(selectedDay_);
286 }
287 }
288
GetToday()289 const CalendarDay& GetToday() const
290 {
291 return today_;
292 }
293
SetToday(const CalendarDay & today)294 void SetToday(const CalendarDay& today)
295 {
296 today_.day = today.day;
297 today_.month.month = today.month.month;
298 today_.month.year = today.month.year;
299 }
300
GetCalendarCache()301 const std::array<std::vector<std::string>, 3>& GetCalendarCache()
302 {
303 return calendarCache_;
304 }
305
SetSelectedChanged(int32_t selected,int32_t indexOfContainer)306 void SetSelectedChanged(int32_t selected, int32_t indexOfContainer)
307 {
308 selectedDay_ = selected;
309 indexOfContainer_ = indexOfContainer;
310 }
311
NotifyFocusChanged(bool focusStatus)312 void NotifyFocusChanged(bool focusStatus) const
313 {
314 for (const auto& listener : allListeners_) {
315 listener->OnFocusChanged(focusStatus);
316 }
317 }
318
SetRequestDataEvent(const EventMarker & requestData)319 void SetRequestDataEvent(const EventMarker& requestData)
320 {
321 if (requestData_ != requestData.GetData().eventId) {
322 requestData_ = requestData;
323 requestDataEvent_ =
324 AceAsyncEvent<void(const std::string&)>::Create(requestData, pipelineContext_);
325 }
326 }
327
SetCardCalendar(bool cardCalendar)328 void SetCardCalendar(bool cardCalendar)
329 {
330 cardCalendar_ = cardCalendar;
331 }
332
IsCardCalendar()333 bool IsCardCalendar() const
334 {
335 return cardCalendar_;
336 }
337
SetStartDayOfWeek(int32_t indexOfWeek)338 void SetStartDayOfWeek(int32_t indexOfWeek)
339 {
340 startDayOfWeek_ = indexOfWeek;
341 }
342
GetStartDayOfWeek()343 int32_t GetStartDayOfWeek() const
344 {
345 return startDayOfWeek_;
346 }
347
SetCachePath(const std::string & cachePath)348 static void SetCachePath(const std::string& cachePath)
349 {
350 cachePath_ = cachePath;
351 }
352
GetDayOfMonthCache()353 const std::array<CalendarDaysOfMonth, CALENDAR_CACHE_PAGE>& GetDayOfMonthCache()
354 {
355 return dayOfMonthCache_;
356 }
357
ShowLunar()358 bool ShowLunar() const
359 {
360 return showLunar_;
361 }
362
SetCurrentMonth(const CalendarMonth & currentMonth)363 void SetCurrentMonth(const CalendarMonth& currentMonth)
364 {
365 currentMonth_ = currentMonth;
366 }
367
SetOffDays(const std::string & offDays)368 void SetOffDays(const std::string& offDays)
369 {
370 offDays_ = offDays;
371 }
372
GetWorkDays()373 const std::string& GetWorkDays() const
374 {
375 return workDays_;
376 }
377
GetHolidays()378 const std::string& GetHolidays() const
379 {
380 return holidays_;
381 }
382
HasMoved()383 bool HasMoved() const
384 {
385 return hasMoved_;
386 }
387
SetHasMoved(bool hasMoved)388 void SetHasMoved(bool hasMoved)
389 {
390 hasMoved_ = hasMoved;
391 }
392
SetCrossMonth(bool isCrossMonth)393 void SetCrossMonth(bool isCrossMonth)
394 {
395 isCrossMonth_ = isCrossMonth;
396 }
397
IsCrossMonth()398 bool IsCrossMonth()
399 {
400 return isCrossMonth_;
401 }
402
403 void ParseCardCalendarData(const std::string& source);
404 void ParseCalendarData(std::queue<ObtainedMonth>&& months);
405 void UpdateCardCalendarAttr(CardCalendarAttr&& attr);
406 void SetOffDays(CalendarDay& dayInfo);
407
408 private:
409 bool ParseData(int32_t index, const std::string& source, CalendarDaysOfMonth& result);
410
411 void SaveCacheData(const CalendarDataRequest& request, const std::string& result);
412
413 bool GetCacheData(const CalendarDataRequest& request);
414
415 void ParseMonthData(const std::unique_ptr<JsonValue>& monthData);
416
417 void RequestDataInWatch(const CalendarDataRequest& request);
418
419 void NotifyDataChanged(const CalendarDaysOfMonth& data, int32_t indexOfContainer);
420
421 void FillMonthData(const CalendarDataRequest& request, CalendarDaysOfMonth& result);
422 void FillPreMonthData(
423 const CalendarMonth& currentMonth, int32_t indexOfContainer, int32_t& index, CalendarDaysOfMonth& result);
424 void FillCurrentMonthData(
425 const CalendarMonth& currentMonth, int32_t indexOfContainer, int32_t& index, CalendarDaysOfMonth& result);
426 void FillNextMonthData(
427 const CalendarMonth& currentMonth, int32_t indexOfContainer, int32_t& index, CalendarDaysOfMonth& result);
428
RequestNextData()429 void RequestNextData()
430 {
431 if (!requestQueue_.empty()) {
432 CalendarDataRequest request = requestQueue_.front();
433 RequestData(request);
434 requestQueue_.pop();
435 } else {
436 NotifySelectedChanged();
437 }
438 }
439
HandleDataRequestResult(const CalendarDataRequest & request,const std::string & result)440 void HandleDataRequestResult(const CalendarDataRequest& request, const std::string& result)
441 {
442 CalendarDaysOfMonth daysOfMonth;
443 daysOfMonth.month = request.month;
444 if (request.indexOfContainer >= 0 && request.indexOfContainer < CALENDAR_CACHE_PAGE) {
445 if (!ParseData(request.indexOfContainer, result, daysOfMonth)) {
446 return;
447 }
448 NotifyDataChanged(daysOfMonth, request.indexOfContainer);
449 RequestNextData();
450 }
451 }
452
453 bool cardCalendar_ = false;
454 bool showLunar_ = true;
455 bool firstLoad_ = true;
456 bool hasMoved_ = false;
457 bool isV2Component_ = false;
458 bool isCrossMonth_ = false;
459 int32_t selectedDay_ = 0;
460 int32_t indexOfContainer_ = 0;
461 int32_t startDayOfWeek_ = 0;
462 int32_t requestNextIndex_ = -1;
463 std::string offDays_;
464 std::string workDays_;
465 std::string holidays_;
466 CalendarDay today_;
467 EventMarker requestData_;
468 CalendarMonth currentMonth_;
469 PendingRequestQueue requestQueue_;
470 CalendarType type_ { CalendarType::NORMAL };
471 CardCalendarAttr calendarAttr_;
472 CalendarDataAdapterAction dataAdapterAction_;
473 WeakPtr<PipelineContext> pipelineContext_;
474 std::array<std::vector<std::string>, CALENDAR_CACHE_PAGE> calendarCache_;
475 std::array<CalendarDaysOfMonth, CALENDAR_CACHE_PAGE> dayOfMonthCache_;
476 std::vector<RefPtr<CalendarDataChangeListener>> allListeners_;
477 std::function<void(const std::string&)> requestDataEvent_;
478 std::unordered_map<int32_t, CalendarMonth> indexMap_;
479 std::unordered_map<CalendarMonth, std::string, HashFunc> monthCache_;
480
481 static std::string cachePath_;
482 };
483
484 namespace StringUtils {
485
StringToCalendarDay(const std::string & str,CalendarDay & day)486 inline bool StringToCalendarDay(const std::string& str, CalendarDay& day)
487 {
488 std::vector<int> date;
489 StringSplitter(str, '-', date);
490 if (date.size() == 3) {
491 day.month.year = date[0];
492 day.month.month = date[1] - 1;
493 day.day = date[2];
494 return true;
495 }
496 return false;
497 }
498
499 } // namespace StringUtils
500 } // namespace OHOS::Ace
501
502 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_CALENDAR_CALENDAR_DATA_ADAPTER_H
503