1  /*
2   * Copyright (c) 2022-2023 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_LIST_LIST_PATTERN_H
17  #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_LIST_LIST_PATTERN_H
18  
19  #include <tuple>
20  #include "core/animation/chain_animation.h"
21  #include "core/components_ng/pattern/list/list_accessibility_property.h"
22  #include "core/components_ng/pattern/list/list_children_main_size.h"
23  #include "core/components_ng/pattern/list/list_content_modifier.h"
24  #include "core/components_ng/pattern/list/list_event_hub.h"
25  #include "core/components_ng/pattern/list/list_item_pattern.h"
26  #include "core/components_ng/pattern/list/list_layout_algorithm.h"
27  #include "core/components_ng/pattern/list/list_layout_property.h"
28  #include "core/components_ng/pattern/list/list_paint_method.h"
29  #include "core/components_ng/pattern/list/list_position_map.h"
30  #include "core/components_ng/pattern/scroll/inner/scroll_bar.h"
31  #include "core/components_ng/pattern/scroll_bar/proxy/scroll_bar_proxy.h"
32  #include "core/components_ng/pattern/scrollable/scrollable_pattern.h"
33  #include "core/components_ng/render/render_context.h"
34  #include "core/pipeline_ng/pipeline_context.h"
35  
36  namespace OHOS::Ace::NG {
37  class InspectorFilter;
38  
39  struct ListItemGroupPara {
40      int32_t lanes = -1;
41      int32_t itemEndIndex = -1;
42      int32_t displayStartIndex = -1;
43      int32_t displayEndIndex = -1;
44  };
45  
46  struct ListScrollTarget {
47      int32_t index = -1;
48      float extraOffset = 0.0f;
49      ScrollAlign align = ScrollAlign::START;
50      float targetOffset;
51  };
52  
53  class ListPattern : public ScrollablePattern {
54      DECLARE_ACE_TYPE(ListPattern, ScrollablePattern);
55  
56  public:
ListPattern()57      ListPattern() : ScrollablePattern(EdgeEffect::SPRING, false) {}
58      ~ListPattern() override = default;
59  
60      RefPtr<NodePaintMethod> CreateNodePaintMethod() override;
61  
CreateLayoutProperty()62      RefPtr<LayoutProperty> CreateLayoutProperty() override
63      {
64          return MakeRefPtr<ListLayoutProperty>();
65      }
66  
CreateEventHub()67      RefPtr<EventHub> CreateEventHub() override
68      {
69          return MakeRefPtr<ListEventHub>();
70      }
71  
CreateAccessibilityProperty()72      RefPtr<AccessibilityProperty> CreateAccessibilityProperty() override
73      {
74          return MakeRefPtr<ListAccessibilityProperty>();
75      }
76  
UsResRegion()77      bool UsResRegion() override
78      {
79          return false;
80      }
81  
82      RefPtr<LayoutAlgorithm> CreateLayoutAlgorithm() override;
83  
84      void ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const override;
85  
86      void FromJson(const std::unique_ptr<JsonValue>& json) override;
87  
88      bool UpdateCurrentOffset(float offset, int32_t source) override;
89  
90      DisplayMode GetDefaultScrollBarDisplayMode() const override;
91  
GetStartIndex()92      int32_t GetStartIndex() const
93      {
94          return startIndex_;
95      }
96  
GetEndIndex()97      int32_t GetEndIndex() const
98      {
99          return endIndex_;
100      }
101  
GetMaxListItemIndex()102      int32_t GetMaxListItemIndex() const
103      {
104          return maxListItemIndex_;
105      }
106  
IsScrollable()107      bool IsScrollable() const override
108      {
109          return isScrollable_;
110      }
111  
SetMaintainVisibleContentPosition(bool enabled)112      void SetMaintainVisibleContentPosition(bool enabled)
113      {
114          maintainVisibleContentPosition_ = enabled;
115      }
116  
GetMaintainVisibleContentPosition()117      bool GetMaintainVisibleContentPosition()
118      {
119          return maintainVisibleContentPosition_;
120      }
121  
MarkNeedReEstimateOffset()122      void MarkNeedReEstimateOffset()
123      {
124          needReEstimateOffset_ = true;
125      }
126  
127      void NotifyDataChange(int32_t index, int32_t count) override;
128  
129      bool IsAtTop() const override;
130      bool IsAtBottom() const override;
131      void OnTouchDown(const TouchEventInfo& info) override;
132      OverScrollOffset GetOutBoundaryOffset(bool useCurrentDelta) const;
133      OverScrollOffset GetOverScrollOffset(double delta) const override;
134      float GetOffsetWithLimit(float offset) const override;
135      void HandleScrollBarOutBoundary();
136  
GetFocusPattern()137      FocusPattern GetFocusPattern() const override
138      {
139          return { FocusType::SCOPE, true };
140      }
141  
GetScopeFocusAlgorithm()142      ScopeFocusAlgorithm GetScopeFocusAlgorithm() override
143      {
144          auto property = GetLayoutProperty<ListLayoutProperty>();
145          if (!property) {
146              return {};
147          }
148          return ScopeFocusAlgorithm(property->GetListDirection().value_or(Axis::VERTICAL) == Axis::VERTICAL, true,
149              ScopeType::OTHERS,
150              [wp = WeakClaim(this)](
151                  FocusStep step, const WeakPtr<FocusHub>& currFocusNode, WeakPtr<FocusHub>& nextFocusNode) {
152                  auto list = wp.Upgrade();
153                  if (list) {
154                      nextFocusNode = list->GetNextFocusNode(step, currFocusNode);
155                  }
156              });
157      }
158  
159      ScrollOffsetAbility GetScrollOffsetAbility() override;
160  
161      std::function<bool(int32_t)> GetScrollIndexAbility() override;
162  
163      bool ScrollToNode(const RefPtr<FrameNode>& focusFrameNode) override;
164  
GetItemPosition()165      const ListLayoutAlgorithm::PositionMap& GetItemPosition() const
166      {
167          return itemPosition_;
168      }
169  
GetTotalOffset()170      float GetTotalOffset() const override
171      {
172          return currentOffset_;
173      }
174  
GetPositionController()175      RefPtr<ScrollControllerBase> GetPositionController() const
176      {
177          return positionController_;
178      }
179  
180      int32_t ProcessAreaVertical(double& x, double& y, Rect& groupRect, int32_t& index,
181          RefPtr<ListItemGroupPattern> groupItemPattern) const;
182      int32_t ProcessAreaHorizontal(double& x, double& y, Rect& groupRect, int32_t& index,
183          RefPtr<ListItemGroupPattern> groupItemPattern) const;
184      void TriggerModifyDone();
185  
186      float GetTotalHeight() const override;
187  
188      // scroller
189      void ScrollTo(float position) override;
190      void ScrollToIndex(int32_t index, bool smooth = false, ScrollAlign align = ScrollAlign::START,
191          std::optional<float> extraOffset = std::nullopt) override;
192      void ScrollToItemInGroup(int32_t index, int32_t indexInGroup, bool smooth = false,
193          ScrollAlign align = ScrollAlign::START);
194      bool CheckTargetValid(int32_t index, int32_t indexInGroup);
195      void ScrollPage(bool reverse, bool smooth = false,
196          AccessibilityScrollType scrollType = AccessibilityScrollType::SCROLL_FULL) override;
197      void ScrollBy(float offset);
198      bool AnimateToTarget(int32_t index, std::optional<int32_t> indexInGroup, ScrollAlign align);
199      Offset GetCurrentOffset() const;
200      Rect GetItemRect(int32_t index) const override;
201      int32_t GetItemIndex(double x, double y) const override;
202      Rect GetItemRectInGroup(int32_t index, int32_t indexInGroup) const;
203      ListItemIndex GetItemIndexInGroup(double x, double y) const;
204      bool GetGroupItemIndex(double x, double y, RefPtr<FrameNode> itemFrameNode, int32_t& index,
205          ListItemIndex& itemIndex) const;
206      void OnAnimateStop() override;
GetMainContentSize()207      float GetMainContentSize() const override
208      {
209          return contentMainSize_;
210      }
GetLanes()211      int32_t GetLanes() const
212      {
213          return lanes_;
214      }
215  
216      void UpdatePosMapStart(float delta);
217      void UpdatePosMapEnd();
218      void CalculateCurrentOffset(float delta, const ListLayoutAlgorithm::PositionMap& recycledItemPosition);
219      void UpdateScrollBarOffset() override;
220      // chain animation
221      void SetChainAnimation();
222      void SetChainAnimationOptions(const ChainAnimationOptions& options);
223      float FlushChainAnimation(float dragOffset);
224      void ProcessDragStart(float startPosition);
225      void ProcessDragUpdate(float dragOffset, int32_t source);
226      float GetChainDelta(int32_t index) const;
227  
228      // multiSelectable
SetMultiSelectable(bool multiSelectable)229      void SetMultiSelectable(bool multiSelectable)
230      {
231          multiSelectable_ = multiSelectable;
232      }
233  
234      void SetSwiperItem(WeakPtr<ListItemPattern> swiperItem);
GetSwiperItem()235      WeakPtr<ListItemPattern> GetSwiperItem()
236      {
237          if (!swiperItem_.Upgrade()) {
238              return nullptr;
239          }
240          return swiperItem_;
241      }
SetSwiperItemEnd(WeakPtr<ListItemPattern> swiperItem)242      void SetSwiperItemEnd(WeakPtr<ListItemPattern> swiperItem)
243      {
244          if (swiperItem == swiperItem_) {
245              canReplaceSwiperItem_ = true;
246          }
247      }
IsCurrentSwiperItem(WeakPtr<ListItemPattern> swiperItem)248      bool IsCurrentSwiperItem(WeakPtr<ListItemPattern> swiperItem)
249      {
250          if (!swiperItem_.Upgrade()) {
251              return true;
252          }
253          return swiperItem == swiperItem_;
254      }
CanReplaceSwiperItem()255      bool CanReplaceSwiperItem()
256      {
257          auto listItemPattern = swiperItem_.Upgrade();
258          if (!listItemPattern) {
259              canReplaceSwiperItem_ = true;
260              return canReplaceSwiperItem_;
261          }
262          auto host = listItemPattern->GetHost();
263          if (!host || !host->IsOnMainTree()) {
264              canReplaceSwiperItem_ = true;
265              return canReplaceSwiperItem_;
266          }
267          return canReplaceSwiperItem_;
268      }
269  
SetPredictSnapOffset(float predictSnapOffset)270      void SetPredictSnapOffset(float predictSnapOffset)
271      {
272          predictSnapOffset_ = predictSnapOffset;
273      }
274      bool OnScrollSnapCallback(double targetOffset, double velocity) override;
275  
276      int32_t GetItemIndexByPosition(float xOffset, float yOffset);
277  
SetPredictLayoutParam(std::optional<ListPredictLayoutParam> param)278      void SetPredictLayoutParam(std::optional<ListPredictLayoutParam> param)
279      {
280          predictLayoutParam_ = param;
281      }
GetPredictLayoutParam()282      std::optional<ListPredictLayoutParam> GetPredictLayoutParam() const
283      {
284          return predictLayoutParam_;
285      }
286  
SetPredictLayoutParamV2(std::optional<ListPredictLayoutParamV2> param)287      void SetPredictLayoutParamV2(std::optional<ListPredictLayoutParamV2> param)
288      {
289          predictLayoutParamV2_ = param;
290      }
291  
GetPredictLayoutParamV2()292      std::optional<ListPredictLayoutParamV2> GetPredictLayoutParamV2() const
293      {
294          return predictLayoutParamV2_;
295      }
296  
297      void CloseAllSwipeActions(OnFinishFunc&&);
298  
299      std::string ProvideRestoreInfo() override;
300      void OnRestoreInfo(const std::string& restoreInfo) override;
301      void DumpAdvanceInfo() override;
302  
SetNeedToUpdateListDirectionInCardStyle(bool isNeedToUpdateListDirection)303      void SetNeedToUpdateListDirectionInCardStyle(bool isNeedToUpdateListDirection)
304      {
305          isNeedToUpdateListDirection_ = isNeedToUpdateListDirection;
306      }
307  
IsNeedToUpdateListDirectionInCardStyle()308      bool IsNeedToUpdateListDirectionInCardStyle() const
309      {
310          return isNeedToUpdateListDirection_;
311      }
312  
313      std::vector<RefPtr<FrameNode>> GetVisibleSelectedItems() override;
314  
SetItemPressed(bool isPressed,int32_t id)315      void SetItemPressed(bool isPressed, int32_t id)
316      {
317          if (isPressed) {
318              pressedItem_.emplace(id);
319          } else {
320              pressedItem_.erase(id);
321          }
322      }
323  
324      RefPtr<ListChildrenMainSize> GetOrCreateListChildrenMainSize();
325      void SetListChildrenMainSize(float defaultSize, const std::vector<float>& mainSize);
326      void OnChildrenSizeChanged(std::tuple<int32_t, int32_t, int32_t> change, ListChangeFlag flag);
327      void ResetChildrenSize();
ListChildrenSizeExist()328      bool ListChildrenSizeExist()
329      {
330          return static_cast<bool>(childrenSize_);
331      }
CanOverScroll(int32_t source)332      bool CanOverScroll(int32_t source) override
333      {
334          auto canOverScroll = (IsScrollableSpringEffect() && source != SCROLL_FROM_AXIS && source != SCROLL_FROM_BAR &&
335              IsScrollable() && (!ScrollableIdle() || animateOverScroll_ || animateCanOverScroll_) &&
336              (IsAtBottom() || IsAtTop()));
337          if (canOverScroll != lastCanOverScroll_) {
338              lastCanOverScroll_ = canOverScroll;
339              AddScrollableFrameInfo(source);
340          }
341          return canOverScroll;
342      }
343      void UpdateChildPosInfo(int32_t index, float delta, float sizeChange);
344  
345      SizeF GetChildrenExpandedSize() override;
346  private:
347  
IsNeedInitClickEventRecorder()348      bool IsNeedInitClickEventRecorder() const override
349      {
350          return true;
351      }
352  
353      void OnScrollEndCallback() override;
354      void FireOnReachStart(const OnReachEvent& onReachStart) override;
355      void FireOnReachEnd(const OnReachEvent& onReachEnd) override;
356      void FireOnScrollIndex(bool indexChanged, const OnScrollIndexEvent& onScrollIndex);
357      void OnModifyDone() override;
358      void ChangeAxis(RefPtr<UINode> node);
359      bool OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config) override;
360      float CalculateTargetPos(float startPos, float endPos);
361  
362      void InitOnKeyEvent(const RefPtr<FocusHub>& focusHub);
363      bool OnKeyEvent(const KeyEvent& event);
364      bool HandleDirectionKey(const KeyEvent& event);
365      WeakPtr<FocusHub> GetNextFocusNode(FocusStep step, const WeakPtr<FocusHub>& currentFocusNode);
366      WeakPtr<FocusHub> GetChildFocusNodeByIndex(int32_t tarMainIndex, int32_t tarGroupIndex);
367      WeakPtr<FocusHub> ScrollAndFindFocusNode(int32_t nextIndex, int32_t curIndex, int32_t& nextIndexInGroup,
368          int32_t curIndexInGroup, int32_t moveStep, FocusStep step);
369      bool ScrollListForFocus(int32_t nextIndex, int32_t curIndex, int32_t nextIndexInGroup);
370      bool ScrollListItemGroupForFocus(int32_t nextIndex, int32_t& nextIndexInGroup, int32_t curIndexInGroup,
371          int32_t moveStep, FocusStep step, bool isScrollIndex);
372  
373      void MarkDirtyNodeSelf();
374      SizeF GetContentSize() const;
375      void ProcessEvent(bool indexChanged, float finalOffset, bool isJump);
376      void CheckScrollable();
377      bool IsOutOfBoundary(bool useCurrentDelta = true) override;
378      bool OnScrollCallback(float offset, int32_t source) override;
379      void SetEdgeEffectCallback(const RefPtr<ScrollEdgeEffect>& scrollEffect) override;
380      void HandleScrollEffect(float offset);
381      void StartDefaultOrCustomSpringMotion(float start, float end, const RefPtr<InterpolatingSpring>& curve);
382      bool IsScrollSnapAlignCenter() const;
383      void SetChainAnimationCallback();
384      void SetChainAnimationToPosMap();
385      void SetChainAnimationLayoutAlgorithm(
386          RefPtr<ListLayoutAlgorithm> listLayoutAlgorithm, RefPtr<ListLayoutProperty> listLayoutProperty);
387      bool NeedScrollSnapAlignEffect() const;
388      ScrollAlign GetScrollAlignByScrollSnapAlign() const;
389      bool GetListItemAnimatePos(float startPos, float endPos, ScrollAlign align, float& targetPos);
390      bool GetListItemGroupAnimatePosWithoutIndexInGroup(int32_t index, float startPos, float endPos,
391          ScrollAlign align, float& targetPos);
392      bool GetListItemGroupAnimatePosWithIndexInGroup(int32_t index, int32_t indexInGroup, float startPos,
393          ScrollAlign align, float& targetPos);
394  
395      // multiSelectable
396      void ClearMultiSelect() override;
397      bool IsItemSelected(const GestureEvent& info) override;
398      void MultiSelectWithoutKeyboard(const RectF& selectedZone) override;
399      void HandleCardModeSelectedEvent(
400          const RectF& selectedZone, const RefPtr<FrameNode>& itemGroupNode, float itemGroupTop);
401  
402      void DrivenRender(const RefPtr<LayoutWrapper>& layoutWrapper);
403      ListItemGroupPara GetListItemGroupParameter(const RefPtr<FrameNode>& node);
404      bool IsListItemGroup(int32_t listIndex, RefPtr<FrameNode>& node);
405      void GetListItemGroupEdge(bool& groupAtStart, bool& groupAtEnd) const;
406      void RefreshLanesItemRange();
407      void UpdateListDirectionInCardStyle();
408      bool UpdateStartListItemIndex();
409      bool UpdateEndListItemIndex();
410      float GetStartOverScrollOffset(float offset, float startMainPos) const;
411      float GetEndOverScrollOffset(float offset, float endMainPos, float startMainPos) const;
412      float UpdateTotalOffset(const RefPtr<ListLayoutAlgorithm>& listLayoutAlgorithm, bool isJump);
413      RefPtr<ListContentModifier> listContentModifier_;
414  
415      int32_t maxListItemIndex_ = 0;
416      int32_t startIndex_ = -1;
417      int32_t endIndex_ = -1;
418      int32_t centerIndex_ = -1;
419      float startMainPos_ = 0.0f;
420      float endMainPos_ = 0.0f;
421      float prevStartOffset_ = 0.f;
422      float prevEndOffset_ = 0.f;
423      float currentOffset_ = 0.0f;
424      float spaceWidth_ = 0.0f;
425      float contentMainSize_ = 0.0f;
426      float contentStartOffset_ = 0.0f;
427      float contentEndOffset_ = 0.0f;
428      bool maintainVisibleContentPosition_ = false;
429  
430      float currentDelta_ = 0.0f;
431      bool crossMatchChild_ = false;
432      bool smooth_ = false;
433      float scrollSnapVelocity_ = 0.0f;
434      bool snapTrigOnScrollStart_ = false;
435  
436      std::optional<int32_t> jumpIndex_;
437      std::optional<int32_t> jumpIndexInGroup_;
438      std::optional<int32_t> targetIndex_;
439      std::optional<int32_t> targetIndexInGroup_;
440      std::optional<ListScrollTarget> scrollTarget_;
441      std::optional<float> predictSnapOffset_;
442      std::optional<float> predictSnapEndPos_;
443      ScrollAlign scrollAlign_ = ScrollAlign::START;
444      bool isScrollable_ = true;
445      bool paintStateFlag_ = false;
446      bool isFramePaintStateValid_ = false;
447      bool isNeedCheckOffset_ = false;
448  
449      ListLayoutAlgorithm::PositionMap itemPosition_;
450      ListLayoutAlgorithm::PositionMap cachedItemPosition_;
451      RefPtr<ListPositionMap> posMap_;
452      RefPtr<ListChildrenMainSize> childrenSize_;
453      float listTotalHeight_ = 0.0f;
454  
455      std::map<int32_t, int32_t> lanesItemRange_;
456      std::set<int32_t> pressedItem_;
457      int32_t lanes_ = 1;
458      float laneGutter_ = 0.0f;
459      // chain animation
460      RefPtr<ChainAnimation> chainAnimation_;
461      bool dragFromSpring_ = false;
462      RefPtr<SpringProperty> springProperty_;
463      std::optional<ChainAnimationOptions> chainAnimationOptions_;
464  
465      bool isOritationListenerRegisted_ = false;
466  
467      // ListItem swiperAction
468      WeakPtr<ListItemPattern> swiperItem_;
469      bool canReplaceSwiperItem_ = true;
470  
471      RefPtr<SpringMotion> scrollToIndexMotion_;
472      RefPtr<SpringMotion> scrollSnapMotion_;
473      RefPtr<Scrollable> scrollable_;
474  
475      bool isScrollEnd_ = false;
476      bool needReEstimateOffset_ = false;
477      std::optional<ListPredictLayoutParam> predictLayoutParam_;
478      std::optional<ListPredictLayoutParamV2> predictLayoutParamV2_;
479  
480      bool isNeedToUpdateListDirection_ = false;
481      bool startIndexChanged_ = false;
482      bool endIndexChanged_ = false;
483  
484      ListItemIndex startInfo_ = {-1, -1, -1};
485      ListItemIndex endInfo_ = {-1, -1, -1};
486  };
487  } // namespace OHOS::Ace::NG
488  
489  #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_LIST_LIST_PATTERN_H
490