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_ITEM_GROUP_PATTERN_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_LIST_LIST_ITEM_GROUP_PATTERN_H
18 
19 #include "base/memory/referenced.h"
20 #include "base/utils/noncopyable.h"
21 #include "base/utils/utils.h"
22 #include "core/components_ng/pattern/list/list_item_group_accessibility_property.h"
23 #include "core/components_ng/pattern/list/list_children_main_size.h"
24 #include "core/components_ng/pattern/list/list_item_group_layout_algorithm.h"
25 #include "core/components_ng/pattern/list/list_item_group_layout_property.h"
26 #include "core/components_ng/pattern/list/list_layout_property.h"
27 #include "core/components_ng/pattern/list/list_position_map.h"
28 #include "core/components_ng/pattern/pattern.h"
29 #include "core/components_ng/syntax/shallow_builder.h"
30 
31 namespace OHOS::Ace::NG {
32 
33 struct ListItemGroupPaintInfo {
34     TextDirection layoutDirection = TextDirection::LTR;
35     float mainSize = 0.0f;
36     bool vertical = false;
37     int32_t lanes = 1;
38     float spaceWidth = 0.0f;
39     float laneGutter = 0.0f;
40     int32_t totalItemCount = 0;
41 };
42 
43 enum ListItemGroupArea {
44     NONE_AREA,
45     IN_LIST_ITEM_AREA,
46     IN_HEADER_AREA,
47     IN_FOOTER_AREA
48 };
49 
50 struct VisibleContentInfo {
51     int32_t area = -1;
52     int32_t indexInGroup = -1;
53 };
54 
55 struct ListMainSizeValues {
56     float startPos = 0.0f;
57     float endPos = 0.0f;
58     std::optional<int32_t> jumpIndexInGroup;
59     float prevContentMainSize = 0.0f;
60     ScrollAlign scrollAlign = ScrollAlign::START;
61     std::optional<float> layoutStartMainPos;
62     std::optional<float> layoutEndMainPos;
63     float referencePos = 0.0f;
64     float contentStartOffset = 0.0f;
65     float contentEndOffset = 0.0f;
66     bool forward = true;
67     bool backward = false;
68 };
69 
70 class ACE_EXPORT ListItemGroupPattern : public Pattern {
71     DECLARE_ACE_TYPE(ListItemGroupPattern, Pattern);
72 
73 public:
ListItemGroupPattern(const RefPtr<ShallowBuilder> & shallowBuilder,V2::ListItemGroupStyle listItemGroupStyle)74     explicit ListItemGroupPattern(
75         const RefPtr<ShallowBuilder>& shallowBuilder, V2::ListItemGroupStyle listItemGroupStyle)
76         : shallowBuilder_(shallowBuilder), listItemGroupStyle_(listItemGroupStyle)
77     {}
78     ~ListItemGroupPattern() override = default;
79 
80     void DumpAdvanceInfo() override;
IsAtomicNode()81     bool IsAtomicNode() const override
82     {
83         return false;
84     }
85 
86     void NotifyDataChange(int32_t index, int32_t count) override;
87 
CreateLayoutProperty()88     RefPtr<LayoutProperty> CreateLayoutProperty() override
89     {
90         return MakeRefPtr<ListItemGroupLayoutProperty>();
91     }
92 
CreateAccessibilityProperty()93     RefPtr<AccessibilityProperty> CreateAccessibilityProperty() override
94     {
95         return MakeRefPtr<ListItemGroupAccessibilityProperty>();
96     }
97 
98     RefPtr<LayoutAlgorithm> CreateLayoutAlgorithm() override;
99 
100     RefPtr<NodePaintMethod> CreateNodePaintMethod() override;
101 
AddHeader(const RefPtr<NG::UINode> & header)102     void AddHeader(const RefPtr<NG::UINode>& header)
103     {
104         auto host = GetHost();
105         CHECK_NULL_VOID(host);
106         auto prevHeader = header_.Upgrade();
107         if (!prevHeader) {
108             host->AddChild(header, 0);
109             host->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST);
110         } else {
111             if (header != prevHeader) {
112                 host->ReplaceChild(prevHeader, header);
113                 host->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST);
114             }
115         }
116         header_ = header;
117     }
118 
AddFooter(const RefPtr<NG::UINode> & footer)119     void AddFooter(const RefPtr<NG::UINode>& footer)
120     {
121         auto host = GetHost();
122         CHECK_NULL_VOID(host);
123         auto prevFooter = footer_.Upgrade();
124         auto prevHeader = header_.Upgrade();
125         if (!prevFooter) {
126             if (prevHeader) {
127                 host->AddChildAfter(footer, prevHeader);
128             } else {
129                 host->AddChild(footer, 0);
130             }
131             host->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST);
132         } else {
133             if (footer != prevFooter) {
134                 host->ReplaceChild(prevFooter, footer);
135                 host->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST);
136             }
137         }
138         footer_ = footer;
139     }
140 
RemoveHeader()141     void RemoveHeader()
142     {
143         auto host = GetHost();
144         CHECK_NULL_VOID(host);
145         auto prevHeader = header_.Upgrade();
146         if (prevHeader && isHeaderComponentContentExist_) {
147             host->RemoveChild(prevHeader);
148             host->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST);
149             header_ = nullptr;
150             isHeaderComponentContentExist_ = false;
151         }
152     }
153 
RemoveFooter()154     void RemoveFooter()
155     {
156         auto host = GetHost();
157         CHECK_NULL_VOID(host);
158         auto prevFooter = footer_.Upgrade();
159         if (prevFooter && isFooterComponentContentExist_) {
160             host->RemoveChild(prevFooter);
161             host->MarkDirtyNode(PROPERTY_UPDATE_BY_CHILD_REQUEST);
162             footer_ = nullptr;
163             isFooterComponentContentExist_ = false;
164         }
165     }
166 
IsHasHeader()167     bool IsHasHeader()
168     {
169         auto headerNode = DynamicCast<FrameNode>(header_.Upgrade());
170         return headerNode ? true : false;
171     }
172 
IsHasFooter()173     bool IsHasFooter()
174     {
175         auto footerGroup = DynamicCast<FrameNode>(footer_.Upgrade());
176         return footerGroup ? true : false;
177     }
178 
GetItemPosition()179     const ListItemGroupLayoutAlgorithm::PositionMap& GetItemPosition()
180     {
181         return itemPosition_;
182     }
183 
SetIndexInList(int32_t index)184     void SetIndexInList(int32_t index)
185     {
186         indexInList_ = index;
187     }
188 
SetHeaderComponentContentExist(bool isHeaderComponentContentExist)189     void SetHeaderComponentContentExist(bool isHeaderComponentContentExist)
190     {
191         isHeaderComponentContentExist_ = isHeaderComponentContentExist;
192     }
193 
SetFooterComponentContentExist(bool isFooterComponentContentExist)194     void SetFooterComponentContentExist(bool isFooterComponentContentExist)
195     {
196         isFooterComponentContentExist_ = isFooterComponentContentExist;
197     }
198 
GetIndexInList()199     int32_t GetIndexInList() const
200     {
201         return indexInList_;
202     }
203 
GetDisplayEndIndexInGroup()204     int32_t GetDisplayEndIndexInGroup() const
205     {
206         return itemDisplayEndIndex_;
207     }
208 
GetDisplayStartIndexInGroup()209     int32_t GetDisplayStartIndexInGroup() const
210     {
211         return itemDisplayStartIndex_;
212     }
213 
GetItemStartIndex()214     int32_t GetItemStartIndex() const
215     {
216         return itemStartIndex_;
217     }
218 
GetEndIndexInGroup()219     int32_t GetEndIndexInGroup() const
220     {
221         return (itemTotalCount_ - 1);
222     }
223 
GetTotalItemCount()224     int32_t GetTotalItemCount() const
225     {
226         return itemTotalCount_;
227     }
228 
IsDisplayStart()229     bool IsDisplayStart() const
230     {
231         return itemDisplayStartIndex_ == 0;
232     }
233 
IsDisplayEnd()234     int32_t IsDisplayEnd() const
235     {
236         return itemTotalCount_ == 0 || itemDisplayEndIndex_ == (itemTotalCount_ - 1);
237     }
238 
GetLanesInGroup()239     int32_t GetLanesInGroup() const
240     {
241         return lanes_;
242     }
243 
SetLanes(int32_t num)244     void SetLanes(int32_t num)
245     {
246         lanes_ = num;
247     }
248 
GetListItemGroupStyle()249     V2::ListItemGroupStyle GetListItemGroupStyle()
250     {
251         return listItemGroupStyle_;
252     }
253 
GetHeaderMainSize()254     float GetHeaderMainSize() const
255     {
256         return headerMainSize_;
257     }
258 
GetFooterMainSize()259     float GetFooterMainSize() const
260     {
261         return footerMainSize_;
262     }
263 
264     float GetEstimateOffset(float height, const std::pair<float, float>& targetPos) const;
265     float GetEstimateHeight(float& averageHeight) const;
HasLayoutedItem()266     bool HasLayoutedItem() const
267     {
268         return layouted_ && (layoutedItemInfo_.has_value() || itemTotalCount_ == 0);
269     }
270 
SetItemPressed(bool isPressed,int32_t id)271     void SetItemPressed(bool isPressed, int32_t id)
272     {
273         if (isPressed) {
274             pressedItem_.emplace(id);
275         } else {
276             pressedItem_.erase(id);
277         }
278     }
279 
280     void SetListItemGroupStyle(V2::ListItemGroupStyle style);
281     RefPtr<ListChildrenMainSize> GetOrCreateListChildrenMainSize();
282     void SetListChildrenMainSize(float defaultSize, const std::vector<float>& mainSize);
283     void OnChildrenSizeChanged(std::tuple<int32_t, int32_t, int32_t> change, ListChangeFlag flag);
284     bool ListChildrenSizeExist();
285     RefPtr<FrameNode> GetListFrameNode() const;
286     VisibleContentInfo GetStartListItemIndex();
287     VisibleContentInfo GetEndListItemIndex();
288     void ResetChildrenSize();
289 
290     void ClearItemPosition();
291     void ClearCachedItemPosition();
292     void CalculateItemStartIndex();
293     bool NeedCacheForward(const LayoutWrapper* listWrapper) const;
294     CachedIndexInfo UpdateCachedIndex(bool outOfView, bool reCache, int32_t forwardCache, int32_t backwardCache);
295     int32_t UpdateCachedIndexForward(bool outOfView, bool show, int32_t cacheCount);
296     int32_t UpdateCachedIndexBackward(bool outOfView, bool show, int32_t cacheCount);
297     std::pair<int32_t, int32_t> UpdateCachedIndexOmni(int32_t forwardCache, int32_t backwardCache);
298     void UpdateActiveChildRange(bool forward, int32_t cacheCount, bool show);
299     void UpdateActiveChildRange(bool show);
300     void SyncItemsToCachedItemPosition();
SetRecache(bool value)301     void SetRecache(bool value)
302     {
303         reCache_ = value;
304     }
305     void LayoutCache(const LayoutConstraintF& constraint, int64_t deadline, int32_t forwardCached,
306         int32_t backwardCached, ListMainSizeValues listSizeValues);
307 
308 private:
IsNeedInitClickEventRecorder()309     bool IsNeedInitClickEventRecorder() const override
310     {
311         return true;
312     }
313 
314     bool OnDirtyLayoutWrapperSwap(const RefPtr<LayoutWrapper>& dirty, const DirtySwapConfig& config) override;
315     void OnAttachToFrameNode() override;
316     void SetListItemGroupDefaultAttributes(const RefPtr<FrameNode>& itemGroupNode);
317     void OnColorConfigurationUpdate() override;
318     void CheckListDirectionInCardStyle();
319     float GetPaddingAndMargin() const;
320     float GetListPaddingOffset(const RefPtr<FrameNode>& listNode) const;
321     bool FirstItemFullVisible(const RefPtr<FrameNode>& listNode) const;
322     bool CheckDataChangeOutOfStart(int32_t index, int32_t count, int32_t startIndex);
323 
324     RefPtr<ShallowBuilder> shallowBuilder_;
325     RefPtr<ListPositionMap> posMap_;
326     RefPtr<ListChildrenMainSize> childrenSize_;
327     V2::ListItemGroupStyle listItemGroupStyle_ = V2::ListItemGroupStyle::NONE;
328 
329     int32_t indexInList_ = 0;
330 
331     WeakPtr<UINode> header_;
332     WeakPtr<UINode> footer_;
333     bool isHeaderComponentContentExist_ = false;
334     bool isFooterComponentContentExist_ = false;
335     int32_t itemStartIndex_ = 0;
336     int32_t headerIndex_ = -1;
337     int32_t footerIndex_ = -1;
338     int32_t itemTotalCount_ = -1;
339     int32_t itemDisplayEndIndex_ = -1;
340     int32_t itemDisplayStartIndex_ = -1;
341     float_t headerMainSize_ = 0.0f;
342     float_t footerMainSize_ = 0.0f;
343 
344     std::optional<LayoutedItemInfo> layoutedItemInfo_;
345     std::set<int32_t> pressedItem_;
346     bool layouted_ = false;
347     LayoutConstraintF layoutConstraint_;
348 
349     bool reCache_ = false;
350     int32_t backwardCachedIndex_ = INT_MAX;
351     int32_t forwardCachedIndex_ = -1;
352     ListItemGroupLayoutAlgorithm::PositionMap cachedItemPosition_;
353     float adjustRefPos_ = 0.0f;
354     float adjustTotalSize_ = 0.0f;
355 
356     ListItemGroupLayoutAlgorithm::PositionMap itemPosition_;
357     float spaceWidth_ = 0.0f;
358     Axis axis_ = Axis::VERTICAL;
359     int32_t lanes_ = 1;
360     float laneGutter_ = 0.0f;
361     float startHeaderPos_ = 0.0f;
362     float endFooterPos_ = 0.0f;
363     TextDirection layoutDirection_ = TextDirection::LTR;
364     float mainSize_ = 0.0f;
365     ACE_DISALLOW_COPY_AND_MOVE(ListItemGroupPattern);
366 };
367 } // namespace OHOS::Ace::NG
368 
369 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_NG_PATTERNS_LIST_LIST_ITEM_PATTERN_H
370