1 /*
2  * Copyright (c) 2024 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 #include "frameworks/core/components_ng/pattern/waterflow/water_flow_sections.h"
17 
18 namespace OHOS::Ace::NG {
19 // push: start, 0, newSection
20 // update: start, 0, newSection
21 // splice: start, deleteCount, newSections
ChangeData(size_t start,size_t deleteCount,const std::vector<WaterFlowSections::Section> & newSections)22 void WaterFlowSections::ChangeData(
23     size_t start, size_t deleteCount, const std::vector<WaterFlowSections::Section>& newSections)
24 {
25     start = std::min(start, sections_.size());
26     deleteCount = std::min(deleteCount, sections_.size() - start);
27     prevSections_ = sections_;
28 
29     TAG_LOGI(AceLogTag::ACE_WATERFLOW,
30         "section changed, start:%{public}zu, deleteCount:%{public}zu, newSections:%{public}zu", start, deleteCount,
31         newSections.size());
32     NotifySectionChange(start, deleteCount, newSections);
33 
34     if (start < sections_.size()) {
35         auto it = sections_.begin() + static_cast<int32_t>(start);
36         sections_.erase(it, it + static_cast<int32_t>(deleteCount));
37         sections_.insert(it, newSections.begin(), newSections.end());
38     } else {
39         sections_.insert(sections_.end(), newSections.begin(), newSections.end());
40     }
41 
42     // perform diff to get actual [start]
43     for (; start < sections_.size(); ++start) {
44         if (start >= prevSections_.size()) {
45             break;
46         }
47         if (sections_[start] != prevSections_[start]) {
48             // can skip re-init the first modified section with only an itemCount diff
49             // to optimize the common scenario when developers add/remove items at the end
50             if (sections_[start].OnlyCountDiff(prevSections_[start])) {
51                 ++start;
52             }
53             break;
54         }
55     }
56 
57     if (onSectionDataChange_) {
58         onSectionDataChange_(static_cast<int32_t>(start));
59     }
60 }
61 
ReplaceFrom(size_t start,const std::vector<WaterFlowSections::Section> & newSections)62 void WaterFlowSections::ReplaceFrom(size_t start, const std::vector<WaterFlowSections::Section>& newSections)
63 {
64     ChangeData(start, sections_.size(), newSections);
65 }
66 
NotifySectionChange(int32_t start,int32_t deleteCount,const std::vector<WaterFlowSections::Section> & newSections)67 void WaterFlowSections::NotifySectionChange(
68     int32_t start, int32_t deleteCount, const std::vector<WaterFlowSections::Section>& newSections)
69 {
70     if (deleteCount == 1 && newSections.size() == 1) {
71         return;
72     }
73     int32_t addItemCount = 0;
74     int32_t n = static_cast<int32_t>(sections_.size());
75     for (int32_t i = 0; i < static_cast<int32_t>(newSections.size()) - 1; i++) {
76         addItemCount += newSections[i].itemsCount;
77     }
78     int32_t deleteItemCount = 0;
79     for (int32_t i = start; i < std::min(start + deleteCount - 1, n); i++) {
80         deleteItemCount += sections_[i].itemsCount;
81     }
82     int32_t itemCount = 0;
83     for (int32_t i = 0; i < std::min(start, n); i++) {
84         itemCount += sections_[i].itemsCount;
85     }
86     if (notifyDataChange_) {
87         notifyDataChange_(itemCount + std::max(addItemCount, deleteItemCount), 0);
88     }
89 }
90 } // namespace OHOS::Ace::NG
91