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