• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "core/pipeline_ng/pipeline_context.h"
29 
30 namespace OHOS::Ace::NG {
31 
32 enum class Direction {
33     PRE = 0,
34     NEXT,
35 };
36 using ChangeIndicatorEvent = std::function<void()>;
37 using IndicatorIndexChangeEvent = std::function<void(int32_t index)>;
38 using ChangeEvent = std::function<void(int32_t index)>;
39 using ChangeEventPtr = std::shared_ptr<ChangeEvent>;
40 using ChangeEventWithPreIndex = std::function<void(int32_t preIndex, int32_t currentIndex)>;
41 using ChangeEventWithPreIndexPtr = std::shared_ptr<ChangeEventWithPreIndex>;
42 using ChangeDoneEvent = std::function<void()>;
43 
44 class SwiperEventHub : public EventHub {
45     DECLARE_ACE_TYPE(SwiperEventHub, EventHub);
46 
47 public:
48     SwiperEventHub() = default;
49     ~SwiperEventHub() override = default;
50 
51     /* Using shared_ptr to enable event modification without adding again */
AddOnChangeEvent(const ChangeEventPtr & changeEvent)52     void AddOnChangeEvent(const ChangeEventPtr& changeEvent)
53     {
54         changeEvents_.emplace_back(changeEvent);
55     }
56 
AddOnChangeEventWithPreIndex(const ChangeEventWithPreIndexPtr & changeEventWithPreIndex)57     void AddOnChangeEventWithPreIndex(const ChangeEventWithPreIndexPtr& changeEventWithPreIndex)
58     {
59         changeEventsWithPreIndex_.emplace_back(changeEventWithPreIndex);
60     }
61 
SetIndicatorOnChange(ChangeIndicatorEvent && changeEvent)62     void SetIndicatorOnChange(ChangeIndicatorEvent&& changeEvent)
63     {
64         changeIndicatorEvent_ = std::move(changeEvent);
65     }
66 
SetIndicatorIndexChangeEvent(IndicatorIndexChangeEvent && indicatorIndexChangeEvent)67     void SetIndicatorIndexChangeEvent(IndicatorIndexChangeEvent&& indicatorIndexChangeEvent)
68     {
69         indicatorIndexChangeEvent_ = std::move(indicatorIndexChangeEvent);
70     }
71 
SetChangeDoneEvent(ChangeDoneEvent && changeDoneEvent)72     void SetChangeDoneEvent(ChangeDoneEvent&& changeDoneEvent)
73     {
74         changeDoneEvent_ = std::move(changeDoneEvent);
75     }
76 
AddAnimationStartEvent(const AnimationStartEventPtr & animationStartEvent)77     void AddAnimationStartEvent(const AnimationStartEventPtr& animationStartEvent)
78     {
79         animationStartEvents_.emplace_back(animationStartEvent);
80     }
81 
AddAnimationEndEvent(const AnimationEndEventPtr & animationEndEvent)82     void AddAnimationEndEvent(const AnimationEndEventPtr& animationEndEvent)
83     {
84         animationEndEvents_.emplace_back(animationEndEvent);
85     }
86 
SetGestureSwipeEvent(GestureSwipeEvent && gestureSwipeEvent)87     void SetGestureSwipeEvent(GestureSwipeEvent&& gestureSwipeEvent)
88     {
89         gestureSwipeEvent_ = std::move(gestureSwipeEvent);
90     }
91 
AddOnSlectedEvent(const ChangeEventPtr & changeEvent)92     void AddOnSlectedEvent(const ChangeEventPtr& changeEvent)
93     {
94         selectedEvents_.emplace_back(changeEvent);
95     }
96 
FireChangeDoneEvent(bool direction)97     void FireChangeDoneEvent(bool direction)
98     {
99         if (changeDoneEvent_) {
100             if (direction) {
101                 direction_ = Direction::NEXT;
102             } else {
103                 direction_ = Direction::PRE;
104             }
105             changeDoneEvent_();
106         }
107     }
108 
AddOnUnselectedEvent(const ChangeEventPtr & changeEvent)109     void AddOnUnselectedEvent(const ChangeEventPtr& changeEvent)
110     {
111         unselectedEvents_.emplace_back(changeEvent);
112     }
113 
FireUnselectedEvent(int32_t index)114     void FireUnselectedEvent(int32_t index)
115     {
116         auto frameNode = GetFrameNode();
117         TAG_LOGI(AceLogTag::ACE_SWIPER, "Swiper FireUnselectedEvent id:%{public}d, index:%{public}d",
118             frameNode ? frameNode->GetId() : -1, index);
119         ACE_SCOPED_TRACE("Swiper FireUnselectedEvent, id: %d, index: %d", frameNode ? frameNode->GetId() : -1, index);
120         if (!unselectedEvents_.empty()) {
121             std::for_each(unselectedEvents_.begin(), unselectedEvents_.end(),
122                 [index](const ChangeEventPtr& changeEvent) {
123                 if (!changeEvent || !(*changeEvent)) {
124                     return;
125                 }
126                 auto event = *changeEvent;
127                 event(index);
128             });
129         }
130     }
131 
AddOnScrollStateChangedEvent(const ChangeEventPtr & changeEvent)132     void AddOnScrollStateChangedEvent(const ChangeEventPtr& changeEvent)
133     {
134         scrollStateChangedEvent_ = changeEvent;
135     }
136 
FireScrollStateChangedEvent(ScrollState scrollState)137     void FireScrollStateChangedEvent(ScrollState scrollState)
138     {
139         if (!scrollStateChangedEvent_ || !(*scrollStateChangedEvent_)) {
140             return;
141         }
142         auto event = *scrollStateChangedEvent_;
143         event(static_cast<int32_t>(scrollState));
144     }
145 
FireChangeEvent(int32_t preIndex,int32_t currentIndex,bool isInLayout)146     void FireChangeEvent(int32_t preIndex, int32_t currentIndex, bool isInLayout)
147     {
148         if (isInLayout) {
149             auto frameNode = GetFrameNode();
150             CHECK_NULL_VOID(frameNode);
151             auto pipeline = frameNode->GetContext();
152             CHECK_NULL_VOID(pipeline);
153             pipeline->AddAfterLayoutTask([weak = WeakClaim(this), preIndex, currentIndex]() {
154                 auto eventHub = weak.Upgrade();
155                 CHECK_NULL_VOID(eventHub);
156                 eventHub->FireJSChangeEvent(preIndex, currentIndex);
157             });
158         } else {
159             FireJSChangeEvent(preIndex, currentIndex);
160         }
161 
162         if (!changeEventsWithPreIndex_.empty()) {
163             std::for_each(changeEventsWithPreIndex_.begin(), changeEventsWithPreIndex_.end(),
164                 [preIndex, currentIndex](const ChangeEventWithPreIndexPtr& changeEventWithPreIndex) {
165                     if (!changeEventWithPreIndex || !(*changeEventWithPreIndex)) {
166                         return;
167                     }
168                     auto event = *changeEventWithPreIndex;
169                     event(preIndex, currentIndex);
170                 });
171         }
172 
173         if (Recorder::EventRecorder::Get().IsComponentRecordEnable()) {
174             Recorder::EventParamsBuilder builder;
175             auto host = GetFrameNode();
176             if (host) {
177                 auto id = host->GetInspectorIdValue("");
178                 builder.SetId(id)
179                     .SetType(host->GetHostTag())
180                     .SetDescription(host->GetAutoEventParamValue(""))
181                     .SetHost(host);
182                 if (!id.empty()) {
183                     Recorder::NodeDataCache::Get().PutInt(host, id, currentIndex);
184                 }
185             }
186             builder.SetIndex(currentIndex);
187             Recorder::EventRecorder::Get().OnChange(std::move(builder));
188         }
189     }
190 
FireIndicatorChangeEvent(int32_t index)191     void FireIndicatorChangeEvent(int32_t index) const
192     {
193         if (changeIndicatorEvent_) {
194             changeIndicatorEvent_();
195         }
196     }
197 
FireIndicatorIndexChangeEvent(int32_t index)198     void FireIndicatorIndexChangeEvent(int32_t index) const
199     {
200         if (indicatorIndexChangeEvent_) {
201             indicatorIndexChangeEvent_(index);
202         }
203     }
204 
GetDirection()205     Direction GetDirection()
206     {
207         return direction_;
208     }
209 
FireAnimationStartEvent(int32_t index,int32_t targetIndex,const AnimationCallbackInfo & info)210     void FireAnimationStartEvent(int32_t index, int32_t targetIndex, const AnimationCallbackInfo& info)
211     {
212         TAG_LOGI(AceLogTag::ACE_SWIPER,
213             "FireAnimationStartEvent, index: %{public}d, targetIndex: %{public}d, id:%{public}d", index, targetIndex,
214             swiperId_);
215         ACE_SCOPED_TRACE(
216             "Swiper FireAnimationStartEvent, index: %d, targetIndex %d, id: %d", index, targetIndex, swiperId_);
217         if (!animationStartEvents_.empty()) {
218             std::for_each(animationStartEvents_.begin(), animationStartEvents_.end(),
219                 [index, targetIndex, info](const AnimationStartEventPtr& animationStartEvent) {
220                     if (!animationStartEvent || !(*animationStartEvent)) {
221                         return;
222                     }
223                     auto event = *animationStartEvent;
224                     event(index, targetIndex, info);
225                 });
226         }
227         // animationEnd callback need to be fired after animationStart callback, use flag for protection.
228         ++aniStartCalledCount_;
229         if (delayCallback_) {
230             auto frameNode = GetFrameNode();
231             TAG_LOGI(AceLogTag::ACE_SWIPER, "the timing of the animation callback has been corrected id:%{public}d",
232                 frameNode ? frameNode->GetId() : -1);
233             delayCallback_();
234             delayCallback_ = nullptr;
235         }
236     }
237 
FireAnimationEndEvent(int32_t index,const AnimationCallbackInfo & info)238     void FireAnimationEndEvent(int32_t index, const AnimationCallbackInfo& info)
239     {
240         if (aniStartCalledCount_ <= 0) {
241             delayCallback_ = [weak = WeakClaim(this), index, info]() {
242                 auto hub = weak.Upgrade();
243                 CHECK_NULL_VOID(hub);
244                 hub->FireAnimationEndEvent(index, info);
245             };
246             return;
247         }
248         TAG_LOGI(AceLogTag::ACE_SWIPER,
249             "FireAnimationEndEvent index: %{public}d, currentOffset: has_value %{public}d, value %{public}fvp, "
250             "isForce: %{public}d, aniStartCalledCount %{public}d, id:%{public}d",
251             index, info.currentOffset.has_value(), info.currentOffset.value_or(0.0), info.isForceStop,
252             aniStartCalledCount_, swiperId_);
253         ACE_SCOPED_TRACE("Swiper FireAnimationEndEvent, index: %d, id: %d", index, swiperId_);
254         if (!animationEndEvents_.empty()) {
255             std::for_each(animationEndEvents_.begin(), animationEndEvents_.end(),
256                 [index, info](const AnimationEndEventPtr& animationEndEvent) {
257                     if (!animationEndEvent || !(*animationEndEvent)) {
258                         return;
259                     }
260                     auto event = *animationEndEvent;
261                     event(index, info);
262                 });
263         }
264         --aniStartCalledCount_;
265     }
266 
FireAnimationEndOnForceEvent(int32_t index,const AnimationCallbackInfo & info)267     void FireAnimationEndOnForceEvent(int32_t index, const AnimationCallbackInfo& info)
268     {
269         TAG_LOGI(AceLogTag::ACE_SWIPER,
270             "FireAnimationEndOnForceEvent index: %{public}d, aniStartCalledCount %{public}d, id:%{public}d", index,
271             aniStartCalledCount_, swiperId_);
272         if (aniStartCalledCount_ <= 0) {
273             delayCallback_ = [weak = WeakClaim(this), index, info]() {
274                 auto hub = weak.Upgrade();
275                 CHECK_NULL_VOID(hub);
276                 hub->FireAnimationEndOnForceEvent(index, info);
277             };
278             return;
279         }
280         if (animationEndEvents_.empty()) {
281             --aniStartCalledCount_;
282             return;
283         }
284         auto context = GetFrameNode()->GetContext();
285         CHECK_NULL_VOID(context);
286         context->AddBuildFinishCallBack([this, index, info]() {
287             std::for_each(animationEndEvents_.begin(), animationEndEvents_.end(),
288                 [index, info](const AnimationEndEventPtr& animationEndEvent) {
289                     if (!animationEndEvent || !(*animationEndEvent)) {
290                         return;
291                     }
292                     auto event = *animationEndEvent;
293                     event(index, info);
294                 });
295         });
296         --aniStartCalledCount_;
297     }
298 
FireGestureSwipeEvent(int32_t index,const AnimationCallbackInfo & info)299     void FireGestureSwipeEvent(int32_t index, const AnimationCallbackInfo& info) const
300     {
301         if (gestureSwipeEvent_) {
302             // gestureSwipeEvent_ may be overwrite in its invoke, so copy it first
303             auto event = gestureSwipeEvent_;
304             event(index, info);
305         }
306     }
307 
FireSelectedEvent(int32_t index)308     void FireSelectedEvent(int32_t index)
309     {
310         auto frameNode = GetFrameNode();
311         ACE_SCOPED_TRACE("Swiper FireSelectedEvent, id: %d, index: %d", frameNode ? frameNode->GetId() : -1, index);
312         if (!selectedEvents_.empty()) {
313             std::for_each(selectedEvents_.begin(), selectedEvents_.end(), [index](const ChangeEventPtr& changeEvent) {
314                 if (!changeEvent || !(*changeEvent)) {
315                     return;
316                 }
317                 auto event = *changeEvent;
318                 event(index);
319             });
320         }
321     }
322 
SetSwiperId(int32_t swiperId)323     void SetSwiperId(int32_t swiperId)
324     {
325         swiperId_ = swiperId;
326     }
327 
328 private:
FireJSChangeEvent(int32_t preIndex,int32_t index)329     void FireJSChangeEvent(int32_t preIndex, int32_t index)
330     {
331         auto frameNode = GetFrameNode();
332         ACE_SCOPED_TRACE("Swiper FireChangeEvent, id: %d, preIndex: %d, index: %d", frameNode ? frameNode->GetId() : -1,
333             preIndex, index);
334         if (changeEvents_.empty()) {
335             return;
336         }
337         std::for_each(changeEvents_.begin(), changeEvents_.end(), [index](const ChangeEventPtr& changeEvent) {
338             if (!changeEvent || !(*changeEvent)) {
339                 return;
340             }
341             auto event = *changeEvent;
342             event(index);
343         });
344     }
345 
346     Direction direction_;
347     std::list<ChangeEventPtr> unselectedEvents_;
348     std::list<ChangeEventPtr> changeEvents_;
349     std::list<ChangeEventPtr> selectedEvents_;
350     std::list<ChangeEventWithPreIndexPtr> changeEventsWithPreIndex_;
351     ChangeEventPtr scrollStateChangedEvent_;
352     ChangeDoneEvent changeDoneEvent_;
353     ChangeIndicatorEvent changeIndicatorEvent_;
354     IndicatorIndexChangeEvent indicatorIndexChangeEvent_;
355     std::list<AnimationStartEventPtr> animationStartEvents_;
356     std::list<AnimationEndEventPtr> animationEndEvents_;
357     GestureSwipeEvent gestureSwipeEvent_;
358     int32_t aniStartCalledCount_ = 0;
359     std::function<void()> delayCallback_;
360     int32_t swiperId_ = -1;
361 };
362 
363 } // namespace OHOS::Ace::NG
364 
365 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_SWIPER_SWIPER_EVENT_HUB_H