1 /*
2  * Copyright (c) 2022 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 FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_JS_VIEW_JS_LAZY_FOREACH_COMPONENT_H
17 #define FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_JS_VIEW_JS_LAZY_FOREACH_COMPONENT_H
18 
19 #include <functional>
20 #include <set>
21 #include <string>
22 
23 #include "base/memory/ace_type.h"
24 #include "bridge/declarative_frontend/jsview/js_lazy_foreach_actuator.h"
25 #include "bridge/declarative_frontend/jsview/js_view.h"
26 #include "core/components_v2/foreach/lazy_foreach_component.h"
27 
28 namespace OHOS::Ace::Framework {
29 
30 class DefaultDataChangeListener : public V2::DataChangeListener {
DECLARE_ACE_TYPE(DefaultDataChangeListener,DataChangeListener)31     DECLARE_ACE_TYPE(DefaultDataChangeListener, DataChangeListener)
32 public:
33     explicit DefaultDataChangeListener(JSView* parentView) : parentView_(parentView) {}
34     ~DefaultDataChangeListener() override = default;
35 
OnDataReloaded()36     void OnDataReloaded() override
37     {
38         if (parentView_ != nullptr) {
39             parentView_->MarkNeedUpdate();
40         }
41     }
OnDataAdded(size_t index)42     void OnDataAdded(size_t index) override
43     {
44         if (parentView_ != nullptr) {
45             parentView_->MarkNeedUpdate();
46         }
47     }
OnDataBulkAdded(size_t index,size_t count)48     void OnDataBulkAdded(size_t index, size_t count) override
49     {
50         if (parentView_ != nullptr) {
51             parentView_->MarkNeedUpdate();
52         }
53     }
OnDataDeleted(size_t index)54     void OnDataDeleted(size_t index) override
55     {
56         if (parentView_ != nullptr) {
57             parentView_->MarkNeedUpdate();
58         }
59     }
OnDataBulkDeleted(size_t index,size_t count)60     void OnDataBulkDeleted(size_t index, size_t count) override
61     {
62         if (parentView_ != nullptr) {
63             parentView_->MarkNeedUpdate();
64         }
65     }
OnDataChanged(size_t index)66     void OnDataChanged(size_t index) override
67     {
68         if (parentView_ != nullptr) {
69             parentView_->MarkNeedUpdate();
70         }
71     }
OnDataMoved(size_t from,size_t to)72     void OnDataMoved(size_t from, size_t to) override
73     {
74         if (parentView_ != nullptr) {
75             parentView_->MarkNeedUpdate();
76         }
77     }
OnDatasetChange(const std::list<V2::Operation> & DataOperations)78     void OnDatasetChange(const std::list<V2::Operation>& DataOperations) override
79     {
80         if (parentView_ != nullptr) {
81             parentView_->MarkNeedUpdate();
82         }
83     }
84 
85 private:
86     JSView* parentView_ = nullptr;
87 
88     ACE_DISALLOW_COPY_AND_MOVE(DefaultDataChangeListener);
89 };
90 
91 class JSLazyForEachComponent : public V2::LazyForEachComponent, public JSLazyForEachActuator {
92     DECLARE_ACE_TYPE(JSLazyForEachComponent, V2::LazyForEachComponent, JSLazyForEachActuator);
93 
94 public:
JSLazyForEachComponent(const std::string & id)95     explicit JSLazyForEachComponent(const std::string& id) : V2::LazyForEachComponent(id) {}
96     ~JSLazyForEachComponent() override = default;
97 
OnGetTotalCount()98     size_t OnGetTotalCount() override
99     {
100         return static_cast<size_t>(GetTotalIndexCount());
101     }
102 
ExpandChildrenOnInitial()103     void ExpandChildrenOnInitial()
104     {
105         auto totalIndex = GetTotalIndexCount();
106         auto* stack = ViewStackProcessor::GetInstance();
107         JSRef<JSVal> params[2];
108         for (auto index = 0; index < totalIndex; index++) {
109             params[0] = CallJSFunction(getDataFunc_, dataSourceObj_, index);
110             params[1] = JSRef<JSVal>::Make(ToJSValue(index));
111             std::string key = keyGenFunc_(params[0], index);
112             auto multiComposed = AceType::MakeRefPtr<MultiComposedComponent>(key, "LazyForEach");
113             stack->Push(multiComposed);
114             stack->PushKey(key);
115             itemGenFunc_->Call(JSRef<JSObject>(), 2, params);
116             stack->PopContainer();
117             stack->PopKey();
118         }
119     }
120 
OnGetChildByIndex(size_t index)121     RefPtr<Component> OnGetChildByIndex(size_t index) override
122     {
123         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext_, nullptr);
124         if (getDataFunc_.IsEmpty()) {
125             return nullptr;
126         }
127 
128         JSRef<JSVal> params[2];
129         params[0] = CallJSFunction(getDataFunc_, dataSourceObj_, index);
130         params[1] = JSRef<JSVal>::Make(ToJSValue(index));
131         std::string key = keyGenFunc_(params[0], index);
132 
133         ScopedViewStackProcessor scopedViewStackProcessor;
134         auto* viewStack = ViewStackProcessor::GetInstance();
135         auto multiComposed = AceType::MakeRefPtr<MultiComposedComponent>(key, "LazyForEach");
136         viewStack->Push(multiComposed);
137         if (parentView_) {
138             parentView_->MarkLazyForEachProcess(key);
139         }
140         viewStack->PushKey(key);
141         itemGenFunc_->Call(JSRef<JSObject>(), 2, params);
142         viewStack->PopContainer();
143         viewStack->PopKey();
144         if (parentView_) {
145             parentView_->ResetLazyForEachProcess();
146         }
147         auto component = viewStack->Finish();
148         ACE_DCHECK(multiComposed == component);
149 
150         while (multiComposed) {
151             const auto& children = multiComposed->GetChildren();
152             if (children.empty()) {
153                 return AceType::MakeRefPtr<ComposedComponent>(key, "LazyForEachItem");
154             }
155 
156             component = children.front();
157             multiComposed = AceType::DynamicCast<MultiComposedComponent>(component);
158         }
159 
160         return AceType::MakeRefPtr<ComposedComponent>(key, "LazyForEachItem", component);
161     }
162 
ReleaseChildGroupByComposedId(const std::string & composedId)163     void ReleaseChildGroupByComposedId(const std::string& composedId) override
164     {
165         JSLazyForEachActuator::ReleaseChildGroupByComposedId(composedId);
166     }
167 
RegisterDataChangeListener(const RefPtr<V2::DataChangeListener> & listener)168     void RegisterDataChangeListener(const RefPtr<V2::DataChangeListener>& listener) override
169     {
170         JSLazyForEachActuator::RegisterListener(listener);
171     }
172 
UnregisterDataChangeListener(V2::DataChangeListener * listener)173     void UnregisterDataChangeListener(V2::DataChangeListener* listener) override
174     {
175         JSLazyForEachActuator::UnregisterListener(listener);
176     }
177 
178 private:
ExpandChildren()179     std::list<RefPtr<Component>>& ExpandChildren() override
180     {
181         // Register data change listener while expanding the lazy foreach component
182         if (!Expanded()) {
183             defaultListener_ = Referenced::MakeRefPtr<DefaultDataChangeListener>(parentView_);
184             RegisterDataChangeListener(defaultListener_);
185         }
186         return LazyForEachComponent::ExpandChildren();
187     }
188 
189     ACE_DISALLOW_COPY_AND_MOVE(JSLazyForEachComponent);
190 };
191 
192 } // namespace OHOS::Ace::Framework
193 
194 #endif // FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_JS_VIEW_JS_LAZY_FOREACH_COMPONENT_H
195