• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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