1 /*
2  * Copyright (c) 2022 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_NG_PATTERNS_SWIPER_SWIPER_EVENT_HUB_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_SWIPER_SWIPER_EVENT_HUB_H
18 
19 #include <algorithm>
20 #include <memory>
21 
22 #include "base/memory/ace_type.h"
23 #include "core/common/recorder/event_recorder.h"
24 #include "core/common/recorder/node_data_cache.h"
25 #include "core/components_ng/base/frame_node.h"
26 #include "core/components_ng/event/event_hub.h"
27 #include "core/components_ng/pattern/swiper/swiper_model.h"
28 
29 namespace OHOS::Ace::NG {
30 
31 enum class Direction {
32     PRE = 0,
33     NEXT,
34 };
35 using ChangeIndicatorEvent = std::function<void()>;
36 using ChangeEvent = std::function<void(int32_t index)>;
37 using ChangeEventPtr = std::shared_ptr<ChangeEvent>;
38 using ChangeEventWithPreIndex = std::function<void(int32_t preIndex, int32_t currentIndex)>;
39 using ChangeEventWithPreIndexPtr = std::shared_ptr<ChangeEventWithPreIndex>;
40 using ChangeDoneEvent = std::function<void()>;
41 
42 class SwiperEventHub : public EventHub {
43     DECLARE_ACE_TYPE(SwiperEventHub, EventHub)
44 
45 public:
46     SwiperEventHub() = default;
47     ~SwiperEventHub() override = default;
48 
49     /* Using shared_ptr to enable event modification without adding again */
AddOnChangeEvent(const ChangeEventPtr & changeEvent)50     void AddOnChangeEvent(const ChangeEventPtr& changeEvent)
51     {
52         changeEvents_.emplace_back(changeEvent);
53     }
54 
AddOnChangeEventWithPreIndex(const ChangeEventWithPreIndexPtr & changeEventWithPreIndex)55     void AddOnChangeEventWithPreIndex(const ChangeEventWithPreIndexPtr& changeEventWithPreIndex)
56     {
57         changeEventsWithPreIndex_.emplace_back(changeEventWithPreIndex);
58     }
59 
SetIndicatorOnChange(ChangeIndicatorEvent && changeEvent)60     void SetIndicatorOnChange(ChangeIndicatorEvent&& changeEvent)
61     {
62         changeIndicatorEvent_ = std::move(changeEvent);
63     }
64 
SetChangeDoneEvent(ChangeDoneEvent && changeDoneEvent)65     void SetChangeDoneEvent(ChangeDoneEvent&& changeDoneEvent)
66     {
67         changeDoneEvent_ = std::move(changeDoneEvent);
68     }
69 
AddAnimationStartEvent(const AnimationStartEventPtr & animationStartEvent)70     void AddAnimationStartEvent(const AnimationStartEventPtr& animationStartEvent)
71     {
72         animationStartEvents_.emplace_back(animationStartEvent);
73     }
74 
AddAnimationEndEvent(const AnimationEndEventPtr & animationEndEvent)75     void AddAnimationEndEvent(const AnimationEndEventPtr& animationEndEvent)
76     {
77         animationEndEvents_.emplace_back(animationEndEvent);
78     }
79 
SetGestureSwipeEvent(GestureSwipeEvent && gestureSwipeEvent)80     void SetGestureSwipeEvent(GestureSwipeEvent&& gestureSwipeEvent)
81     {
82         gestureSwipeEvent_ = std::move(gestureSwipeEvent);
83     }
84 
FireChangeDoneEvent(bool direction)85     void FireChangeDoneEvent(bool direction)
86     {
87         if (changeDoneEvent_) {
88             if (direction) {
89                 direction_ = Direction::NEXT;
90             } else {
91                 direction_ = Direction::PRE;
92             }
93             changeDoneEvent_();
94         }
95     }
96 
FireChangeEvent(int32_t preIndex,int32_t currentIndex)97     void FireChangeEvent(int32_t preIndex, int32_t currentIndex) const
98     {
99         ACE_SCOPED_TRACE("Swiper FireChangeEvent, preIndex: %d currentIndex: %d eventSize: %zu",
100             preIndex, currentIndex, changeEvents_.size() + changeEventsWithPreIndex_.size());
101         if (!changeEvents_.empty()) {
102             std::for_each(
103                 changeEvents_.begin(), changeEvents_.end(), [currentIndex](const ChangeEventPtr& changeEvent) {
104                     auto event = *changeEvent;
105                     event(currentIndex);
106                 });
107         }
108         if (!changeEventsWithPreIndex_.empty()) {
109             std::for_each(changeEventsWithPreIndex_.begin(), changeEventsWithPreIndex_.end(),
110                 [preIndex, currentIndex](const ChangeEventWithPreIndexPtr& changeEventWithPreIndex) {
111                     auto event = *changeEventWithPreIndex;
112                     event(preIndex, currentIndex);
113                 });
114         }
115 
116         if (Recorder::EventRecorder::Get().IsComponentRecordEnable()) {
117             Recorder::EventParamsBuilder builder;
118             auto host = GetFrameNode();
119             if (host) {
120                 auto id = host->GetInspectorIdValue("");
121                 builder.SetId(id).SetType(host->GetHostTag()).SetDescription(host->GetAutoEventParamValue(""));
122                 if (!id.empty()) {
123                     Recorder::NodeDataCache::Get().PutInt(host, id, currentIndex);
124                 }
125             }
126             builder.SetIndex(currentIndex);
127             Recorder::EventRecorder::Get().OnChange(std::move(builder));
128         }
129     }
130 
FireIndicatorChangeEvent(int32_t index)131     void FireIndicatorChangeEvent(int32_t index) const
132     {
133         if (changeIndicatorEvent_) {
134             changeIndicatorEvent_();
135         }
136     }
137 
GetDirection()138     Direction GetDirection()
139     {
140         return direction_;
141     }
142 
FireAnimationStartEvent(int32_t index,int32_t targetIndex,const AnimationCallbackInfo & info)143     void FireAnimationStartEvent(int32_t index, int32_t targetIndex, const AnimationCallbackInfo& info)
144     {
145         if (!animationStartEvents_.empty()) {
146             std::for_each(animationStartEvents_.begin(), animationStartEvents_.end(),
147                 [index, targetIndex, info](const AnimationStartEventPtr& animationStartEvent) {
148                     auto event = *animationStartEvent;
149                     event(index, targetIndex, info);
150                 });
151         }
152         // animationEnd callback need to be fired after animationStart callback, use flag for protection.
153         ++aniStartCalledCount_;
154         if (delayCallback_) {
155             TAG_LOGI(AceLogTag::ACE_SWIPER, "the timing of the animation callback has been corrected");
156             delayCallback_();
157             delayCallback_ = nullptr;
158         }
159     }
160 
FireAnimationEndEvent(int32_t index,const AnimationCallbackInfo & info)161     void FireAnimationEndEvent(int32_t index, const AnimationCallbackInfo& info)
162     {
163         if (aniStartCalledCount_ <= 0) {
164             delayCallback_ = [weak = WeakClaim(this), index, info]() {
165                 auto hub = weak.Upgrade();
166                 CHECK_NULL_VOID(hub);
167                 hub->FireAnimationEndEvent(index, info);
168             };
169             return;
170         }
171         if (!animationEndEvents_.empty()) {
172             std::for_each(animationEndEvents_.begin(), animationEndEvents_.end(),
173                 [index, info](const AnimationEndEventPtr& animationEndEvent) {
174                     auto event = *animationEndEvent;
175                     event(index, info);
176                 });
177         }
178         --aniStartCalledCount_;
179     }
180 
FireAnimationEndOnForceEvent(int32_t index,const AnimationCallbackInfo & info)181     void FireAnimationEndOnForceEvent(int32_t index, const AnimationCallbackInfo& info)
182     {
183         if (aniStartCalledCount_ <= 0) {
184             delayCallback_ = [weak = WeakClaim(this), index, info]() {
185                 auto hub = weak.Upgrade();
186                 CHECK_NULL_VOID(hub);
187                 hub->FireAnimationEndOnForceEvent(index, info);
188             };
189             return;
190         }
191         if (!animationEndEvents_.empty()) {
192             auto context = GetFrameNode()->GetContext();
193             CHECK_NULL_VOID(context);
194             context->AddBuildFinishCallBack([this, index, info]() {
195                 std::for_each(animationEndEvents_.begin(), animationEndEvents_.end(),
196                     [index, info](const AnimationEndEventPtr& animationEndEvent) {
197                         auto event = *animationEndEvent;
198                         event(index, info);
199                     });
200             });
201         }
202         --aniStartCalledCount_;
203     }
204 
FireGestureSwipeEvent(int32_t index,const AnimationCallbackInfo & info)205     void FireGestureSwipeEvent(int32_t index, const AnimationCallbackInfo& info) const
206     {
207         if (gestureSwipeEvent_) {
208             // gestureSwipeEvent_ may be overwrite in its invoke, so copy it first
209             auto event = gestureSwipeEvent_;
210             event(index, info);
211         }
212     }
213 
214 private:
215     Direction direction_;
216     std::list<ChangeEventPtr> changeEvents_;
217     std::list<ChangeEventWithPreIndexPtr> changeEventsWithPreIndex_;
218     ChangeDoneEvent changeDoneEvent_;
219     ChangeIndicatorEvent changeIndicatorEvent_;
220     std::list<AnimationStartEventPtr> animationStartEvents_;
221     std::list<AnimationEndEventPtr> animationEndEvents_;
222     GestureSwipeEvent gestureSwipeEvent_;
223     int32_t aniStartCalledCount_ = 0;
224     std::function<void()> delayCallback_;
225 };
226 
227 } // namespace OHOS::Ace::NG
228 
229 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_SWIPER_SWIPER_EVENT_HUB_H