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