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