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