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 "bridge/cj_frontend/cppview/lazy_foreach.h"
17 
18 #include <functional>
19 #include <set>
20 #include <string>
21 
22 #include "base/utils/utils.h"
23 #include "bridge/cj_frontend/cppview/data_change_listener.h"
24 #include "bridge/cj_frontend/cppview/native_view.h"
25 #include "core/common/container_scope.h"
26 #include "core/components_v2/foreach/lazy_foreach_component.h"
27 #include "core/components_ng/base/view_stack_model.h"
28 
29 using namespace OHOS::Ace;
30 using namespace OHOS::FFI;
31 using namespace OHOS::Ace::Framework;
32 
33 namespace OHOS::Ace::Framework {
34 
OnExpandChildrenOnInitialInNG()35 void CJLazyForEachBuilder::OnExpandChildrenOnInitialInNG()
36 {
37     auto totalIndex = cjBuilder_->GetTotalCount();
38     for (auto index = 0; index < totalIndex; index++) {
39         auto key = cjBuilder_->GenerateKey(index);
40         ViewStackModel::GetInstance()->PushKey(key);
41         cjBuilder_->GenerateItem(index);
42         ViewStackModel::GetInstance()->PopKey();
43     }
44 }
45 
OnGetChildByIndex(int32_t index,std::unordered_map<std::string,std::pair<int32_t,RefPtr<NG::UINode>>> & cachedItems)46 std::pair<std::string, RefPtr<NG::UINode>> CJLazyForEachBuilder::OnGetChildByIndex(
47     int32_t index, std::unordered_map<std::string, std::pair<int32_t, RefPtr<NG::UINode>>>& cachedItems)
48 {
49     std::pair<std::string, RefPtr<NG::UINode>> result;
50     auto key = cjBuilder_->GenerateKey(index);
51     auto cachedIter = cachedItems.find(key);
52     if (cachedIter != cachedItems.end()) {
53         result.first = key;
54         result.second = cachedIter->second.second;
55         return result;
56     }
57     NG::ScopedViewStackProcessor scopedViewStackProcessor;
58     auto* viewStack = ViewStackModel::GetInstance();
59     cjBuilder_->MarkLazyForEachProcess(key);
60     viewStack->PushKey(key);
61     cjBuilder_->GenerateItem(index);
62     viewStack->PopKey();
63     cjBuilder_->ResetLazyForEachProcess();
64     result.first = key;
65     auto view = ViewStackModel::GetInstance()->Finish();
66     result.second = AceType::DynamicCast<NG::UINode>(view);
67 
68     return result;
69 }
70 
OnGetChildByIndexNew(int32_t index,std::map<int32_t,NG::LazyForEachChild> & cachedItems,std::unordered_map<std::string,NG::LazyForEachCacheChild> & expiringItems)71 std::pair<std::string, RefPtr<NG::UINode>> CJLazyForEachBuilder::OnGetChildByIndexNew(int32_t index,
72     std::map<int32_t, NG::LazyForEachChild>& cachedItems,
73     std::unordered_map<std::string, NG::LazyForEachCacheChild>& expiringItems)
74 {
75     std::pair<std::string, RefPtr<NG::UINode>> result;
76     auto key = cjBuilder_->GenerateKey(index);
77     auto cachedIter = cachedItems.find(index);
78     if (cachedIter != cachedItems.end()) {
79         result.first = key;
80         result.second = cachedIter->second.second;
81         return result;
82     }
83     auto expiringIter = expiringItems.find(key);
84     if (expiringIter != expiringItems.end()) {
85         result.first = key;
86         result.second = expiringIter->second.second;
87         expiringItems.erase(expiringIter);
88         return result;
89     }
90     NG::ScopedViewStackProcessor scopedViewStackProcessor;
91     auto* viewStack = ViewStackModel::GetInstance();
92     cjBuilder_->MarkLazyForEachProcess(key);
93     viewStack->PushKey(key);
94     cjBuilder_->GenerateItem(index);
95     viewStack->PopKey();
96     cjBuilder_->ResetLazyForEachProcess();
97     result.first = key;
98     auto view = ViewStackModel::GetInstance()->Finish();
99     result.second = AceType::DynamicCast<NG::UINode>(view);
100 
101     return result;
102 }
103 
ReleaseChildGroupById(const std::string & id)104 void CJLazyForEachBuilder::ReleaseChildGroupById(const std::string& id)
105 {
106     cjBuilder_->RemoveChildGroupById(id);
107 }
108 
RegisterDataChangeListener(const RefPtr<V2::DataChangeListener> & listener)109 void CJLazyForEachBuilder::RegisterDataChangeListener(const RefPtr<V2::DataChangeListener>& listener)
110 {
111     if (!listener) {
112         return;
113     }
114     auto listenerManager = weakListenerManager_.promote();
115     if (listenerManager) {
116         listenerManager->AddListener(listener);
117         return;
118     }
119     listenerManager = FFIData::Create<CJDataChangeListener>();
120     listenerManager->AddListener(listener);
121     weakListenerManager_ = listenerManager;
122     cjBuilder_->RegisterListenerFunc(listenerManager);
123 }
124 
UnregisterDataChangeListener(V2::DataChangeListener * listener)125 void CJLazyForEachBuilder::UnregisterDataChangeListener(V2::DataChangeListener* listener)
126 {
127     if (!listener) {
128         LOGW("CJLazyForEachBuilder listener is null");
129         return;
130     }
131     auto listenerManager = weakListenerManager_.promote();
132     if (!listenerManager) {
133         // this would happen before first RegisterDataChangeListener called
134         // this would happen after cj released listenerManager
135         LOGW("LazyForEach::UnregisterDataChangeListener fail, listenerManager is null.");
136         return;
137     }
138     listenerManager->RemoveListener(WeakClaim(listener));
139 }
140 
141 } // namespace OHOS::Ace::Framework
142