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 #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 std::string lunarMonth;
122 std::string lunarDay;
123 std::string dayMark;
124 std::string dayMarkValue;
125 CalendarMonth month;
126
127 static constexpr char INDEX[] { "index" };
128 static constexpr char DAY[] { "day" };
129 static constexpr char MONTH[] { "month" };
130 static constexpr char YEAR[] { "year" };
131 static constexpr char LUNAR_MONTH[] { "lunarMonth" };
132 static constexpr char LUNAR_DAY[] { "lunarDay" };
133 static constexpr char DAY_MARK[] { "dayMark" };
134 static constexpr char DAY_MARK_VALUE[] { "dayMarkValue" };
135
ToStringCalendarDay136 std::string ToString() const
137 {
138 auto json = JsonUtil::Create(true);
139 json->Put(DAY, day);
140 json->Put(INDEX, index);
141 json->Put(MONTH, month.month);
142 json->Put(YEAR, month.year);
143 json->Put(LUNAR_MONTH, lunarMonth.c_str());
144 json->Put(LUNAR_DAY, lunarDay.c_str());
145 return json->ToString();
146 }
147 };
148
149 struct CalendarDaysOfMonth {
150 CalendarMonth month;
151 int32_t firstDayIndex = CALENDAR_INVALID;
152 int32_t lastDayIndex = CALENDAR_INVALID;
153 int32_t today = CALENDAR_INVALID;
154 std::vector<CalendarDay> days;
155 };
156
157 struct CalendarDataRequest {
CalendarDataRequestCalendarDataRequest158 CalendarDataRequest(const CalendarMonth& month, int32_t indexOfContainer)
159 : month(month), indexOfContainer(indexOfContainer)
160 {}
161 ~CalendarDataRequest() = default;
162
163 int32_t selected = 0;
164 CalendarMonth month;
165 MonthState state = MonthState::CUR_MONTH;
166 int32_t indexOfContainer = 0;
167 };
168
169 struct CardCalendarAttr {
170 int32_t startDayOfWeek = 0;
171 bool isV2Component = false;
172 bool showLunar = true;
173 bool showHoliday = true;
174 bool needSlide = false;
175 bool cardCalendar = false;
176 bool listenersReady = true;
177 Axis axis = Axis::HORIZONTAL;
178 std::string offDays;
179 std::string holidays;
180 std::string workDays;
181 EventMarker requestData;
182 RefPtr<CalendarTheme> calendarTheme;
183 TextDirection textDirection = TextDirection::LTR;
184 CalendarType type { CalendarType::NORMAL };
185 };
186
187 struct ObtainedMonth {
188 int32_t year = 0;
189 int32_t month = 0;
190 int32_t firstDayIndex = CALENDAR_INVALID;
191 std::vector<CalendarDay> days;
192 };
193
194 using PendingRequestQueue = std::queue<CalendarDataRequest>;
195 using RequestDataCompleteCallback = std::function<void()>;
196
197 class CalendarDataChangeListener : public AceType {
198 DECLARE_ACE_TYPE(CalendarDataChangeListener, AceType);
199
200 public:
201 virtual void OnDataChanged(const CalendarDaysOfMonth& daysOfMonth) = 0;
202 virtual void OnSelectedDay(int32_t selected) = 0;
203 virtual void OnFocusChanged(bool focusStatus) = 0;
204 virtual void UpdateCardCalendarAttr(CardCalendarAttr&& attr) = 0;
205 virtual void OnSwiperMove() = 0;
206 };
207
208 struct DataAdapterAction {
209 std::string bundleName;
210 std::string abilityName;
211 int32_t messageCode = 0;
212 std::string data;
213
GetActionDataAdapterAction214 std::string GetAction()
215 {
216 return "{\"element\":{\"bundleName\":\"" + bundleName +
217 "\",\"name\":\"" + abilityName + "\",\"type\":1},\"code\":" +
218 std::to_string(messageCode) + "}";
219 }
220 };
221
222 struct CalendarDataAdapterAction : public DataAdapterAction {
GetDataCalendarDataAdapterAction223 std::string GetData(int32_t year, int32_t month)
224 {
225 return "{\"year\":" + std::to_string(year) + ",\"month\":" + std::to_string(month) + "}";
226 }
227
GetActionCalendarDataAdapterAction228 std::vector<Framework::CodecData> GetAction(int32_t year, int32_t month)
229 {
230 std::vector<Framework::CodecData> args;
231 Framework::CodecData header(DataAdapterAction::GetAction());
232 args.push_back(header);
233 Framework::CodecData params(GetData(year, month));
234 args.push_back(params);
235
236 return args;
237 }
238 };
239
240 class CalendarDataAdapter : public AceType {
241 DECLARE_ACE_TYPE(CalendarDataAdapter, AceType);
242
243 public:
244 explicit CalendarDataAdapter(
245 const CalendarDataAdapterAction& dataAdapterAction, const WeakPtr<PipelineContext>& pipelineContext);
246 ~CalendarDataAdapter() override = default;
247
RegisterDataListener(const RefPtr<CalendarDataChangeListener> & listener)248 void RegisterDataListener(const RefPtr<CalendarDataChangeListener>& listener)
249 {
250 allListeners_.push_back(listener);
251 if (allListeners_.size() == CALENDAR_CACHE_PAGE && !calendarAttr_.listenersReady) {
252 calendarAttr_.listenersReady = true;
253 for (const auto& listen : allListeners_) {
254 listen->UpdateCardCalendarAttr(std::move(calendarAttr_));
255 }
256 }
257 }
258
AddPendingRequest(const CalendarMonth & month,const int32_t indexOfContainer)259 void AddPendingRequest(const CalendarMonth& month, const int32_t indexOfContainer)
260 {
261 requestQueue_.emplace(month, indexOfContainer);
262 indexMap_[indexOfContainer] = month;
263 }
264
AddPendingRequest(const CalendarDataRequest & request)265 void AddPendingRequest(const CalendarDataRequest& request)
266 {
267 requestQueue_.emplace(request);
268 indexMap_[request.indexOfContainer] = request.month;
269 }
270
271 void RequestData(const CalendarDataRequest& request);
272
NotifySelectedChanged()273 void NotifySelectedChanged() const
274 {
275 int32_t listenersSize = static_cast<int32_t>(allListeners_.size());
276 if (indexOfContainer_ >= 0 && indexOfContainer_ < listenersSize) {
277 auto& listener = allListeners_[indexOfContainer_];
278 listener->OnSelectedDay(selectedDay_);
279 }
280 }
281
GetToday()282 const CalendarDay& GetToday() const
283 {
284 return today_;
285 }
286
SetToday(const CalendarDay & today)287 void SetToday(const CalendarDay& today)
288 {
289 today_.day = today.day;
290 today_.month.month = today.month.month;
291 today_.month.year = today.month.year;
292 }
293
GetCalendarCache()294 const std::array<std::vector<std::string>, 3>& GetCalendarCache()
295 {
296 return calendarCache_;
297 }
298
SetSelectedChanged(int32_t selected,int32_t indexOfContainer)299 void SetSelectedChanged(int32_t selected, int32_t indexOfContainer)
300 {
301 selectedDay_ = selected;
302 indexOfContainer_ = indexOfContainer;
303 }
304
NotifyFocusChanged(bool focusStatus)305 void NotifyFocusChanged(bool focusStatus) const
306 {
307 for (const auto& listener : allListeners_) {
308 listener->OnFocusChanged(focusStatus);
309 }
310 }
311
SetRequestDataEvent(const EventMarker & requestData)312 void SetRequestDataEvent(const EventMarker& requestData)
313 {
314 if (requestData_ != requestData.GetData().eventId) {
315 requestData_ = requestData;
316 requestDataEvent_ =
317 AceAsyncEvent<void(const std::string&)>::Create(requestData, pipelineContext_);
318 }
319 }
320
SetCardCalendar(bool cardCalendar)321 void SetCardCalendar(bool cardCalendar)
322 {
323 cardCalendar_ = cardCalendar;
324 }
325
IsCardCalendar()326 bool IsCardCalendar() const
327 {
328 return cardCalendar_;
329 }
330
SetStartDayOfWeek(int32_t indexOfWeek)331 void SetStartDayOfWeek(int32_t indexOfWeek)
332 {
333 startDayOfWeek_ = indexOfWeek;
334 }
335
GetStartDayOfWeek()336 int32_t GetStartDayOfWeek() const
337 {
338 return startDayOfWeek_;
339 }
340
SetCachePath(const std::string & cachePath)341 static void SetCachePath(const std::string& cachePath)
342 {
343 cachePath_ = cachePath;
344 }
345
GetDayOfMonthCache()346 const std::array<CalendarDaysOfMonth, CALENDAR_CACHE_PAGE>& GetDayOfMonthCache()
347 {
348 return dayOfMonthCache_;
349 }
350
ShowLunar()351 bool ShowLunar() const
352 {
353 return showLunar_;
354 }
355
SetCurrentMonth(const CalendarMonth & currentMonth)356 void SetCurrentMonth(const CalendarMonth& currentMonth)
357 {
358 currentMonth_ = currentMonth;
359 }
360
SetOffDays(const std::string & offDays)361 void SetOffDays(const std::string& offDays)
362 {
363 offDays_ = offDays;
364 }
365
GetWorkDays()366 const std::string& GetWorkDays() const
367 {
368 return workDays_;
369 }
370
GetHolidays()371 const std::string& GetHolidays() const
372 {
373 return holidays_;
374 }
375
HasMoved()376 bool HasMoved() const
377 {
378 return hasMoved_;
379 }
380
SetHasMoved(bool hasMoved)381 void SetHasMoved(bool hasMoved)
382 {
383 hasMoved_ = hasMoved;
384 }
385
SetCrossMonth(bool isCrossMonth)386 void SetCrossMonth(bool isCrossMonth)
387 {
388 isCrossMonth_ = isCrossMonth;
389 }
390
IsCrossMonth()391 bool IsCrossMonth()
392 {
393 return isCrossMonth_;
394 }
395
396 void ParseCardCalendarData(const std::string& source);
397 void ParseCalendarData(std::queue<ObtainedMonth>&& months);
398 void UpdateCardCalendarAttr(CardCalendarAttr&& attr);
399 void SetOffDays(CalendarDay& dayInfo);
400
401 private:
402 bool ParseData(int32_t index, const std::string& source, CalendarDaysOfMonth& result);
403
404 void SaveCacheData(const CalendarDataRequest& request, const std::string& result);
405
406 bool GetCacheData(const CalendarDataRequest& request);
407
408 void ParseMonthData(const std::unique_ptr<JsonValue>& monthData);
409
410 void RequestDataInWatch(const CalendarDataRequest& request);
411
412 void NotifyDataChanged(const CalendarDaysOfMonth& data, int32_t indexOfContainer);
413
414 void FillMonthData(const CalendarDataRequest& request, CalendarDaysOfMonth& result);
415 void FillPreMonthData(
416 const CalendarMonth& currentMonth, int32_t indexOfContainer, int32_t& index, CalendarDaysOfMonth& result);
417 void FillCurrentMonthData(
418 const CalendarMonth& currentMonth, int32_t indexOfContainer, int32_t& index, CalendarDaysOfMonth& result);
419 void FillNextMonthData(
420 const CalendarMonth& currentMonth, int32_t indexOfContainer, int32_t& index, CalendarDaysOfMonth& result);
421
RequestNextData()422 void RequestNextData()
423 {
424 if (!requestQueue_.empty()) {
425 CalendarDataRequest request = requestQueue_.front();
426 RequestData(request);
427 requestQueue_.pop();
428 } else {
429 NotifySelectedChanged();
430 }
431 }
432
HandleDataRequestResult(const CalendarDataRequest & request,const std::string & result)433 void HandleDataRequestResult(const CalendarDataRequest& request, const std::string& result)
434 {
435 CalendarDaysOfMonth daysOfMonth;
436 daysOfMonth.month = request.month;
437 if (request.indexOfContainer >= 0 && request.indexOfContainer < CALENDAR_CACHE_PAGE) {
438 if (!ParseData(request.indexOfContainer, result, daysOfMonth)) {
439 return;
440 }
441 NotifyDataChanged(daysOfMonth, request.indexOfContainer);
442 RequestNextData();
443 }
444 }
445
446 bool cardCalendar_ = false;
447 bool showLunar_ = true;
448 bool firstLoad_ = true;
449 bool hasMoved_ = false;
450 bool isV2Component_ = false;
451 bool isCrossMonth_ = false;
452 int32_t selectedDay_ = 0;
453 int32_t indexOfContainer_ = 0;
454 int32_t startDayOfWeek_ = 0;
455 int32_t requestNextIndex_ = -1;
456 std::string offDays_;
457 std::string workDays_;
458 std::string holidays_;
459 CalendarDay today_;
460 EventMarker requestData_;
461 CalendarMonth currentMonth_;
462 PendingRequestQueue requestQueue_;
463 CalendarType type_ { CalendarType::NORMAL };
464 CardCalendarAttr calendarAttr_;
465 CalendarDataAdapterAction dataAdapterAction_;
466 WeakPtr<PipelineContext> pipelineContext_;
467 std::array<std::vector<std::string>, CALENDAR_CACHE_PAGE> calendarCache_;
468 std::array<CalendarDaysOfMonth, CALENDAR_CACHE_PAGE> dayOfMonthCache_;
469 std::vector<RefPtr<CalendarDataChangeListener>> allListeners_;
470 std::function<void(const std::string&)> requestDataEvent_;
471 std::unordered_map<int32_t, CalendarMonth> indexMap_;
472 std::unordered_map<CalendarMonth, std::string, HashFunc> monthCache_;
473
474 static std::string cachePath_;
475 };
476
477 namespace StringUtils {
478
StringToCalendarDay(const std::string & str,CalendarDay & day)479 inline bool StringToCalendarDay(const std::string& str, CalendarDay& day)
480 {
481 std::vector<int> date;
482 StringSplitter(str, '-', date);
483 if (date.size() == 3) {
484 day.month.year = date[0];
485 day.month.month = date[1] - 1;
486 day.day = date[2];
487 return true;
488 }
489 return false;
490 }
491
492 } // namespace StringUtils
493 } // namespace OHOS::Ace
494
495 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_CALENDAR_CALENDAR_DATA_ADAPTER_H
496