1 /*
2  * Copyright (c) 2022-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/declarative_frontend/jsview/js_water_flow.h"
17 
18 #include <cstdint>
19 #include <vector>
20 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
21 #include "interfaces/inner_api/ui_session/ui_session_manager.h"
22 #endif
23 
24 #include "bridge/declarative_frontend/jsview/js_scrollable.h"
25 #include "bridge/declarative_frontend/jsview/js_scroller.h"
26 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
27 #include "bridge/declarative_frontend/jsview/js_water_flow_sections.h"
28 #include "bridge/declarative_frontend/jsview/models/water_flow_model_impl.h"
29 #include "core/common/container.h"
30 #include "core/components_ng/pattern/waterflow/water_flow_model.h"
31 #include "core/components_ng/pattern/waterflow/water_flow_model_ng.h"
32 #include "core/components_ng/pattern/waterflow/water_flow_sections.h"
33 
34 namespace OHOS::Ace {
35 std::unique_ptr<WaterFlowModel> WaterFlowModel::instance_ = nullptr;
36 std::mutex WaterFlowModel::mutex_;
37 
GetInstance()38 WaterFlowModel* WaterFlowModel::GetInstance()
39 {
40     if (!instance_) {
41         std::lock_guard<std::mutex> lock(mutex_);
42         if (!instance_) {
43 #ifdef NG_BUILD
44             instance_.reset(new NG::WaterFlowModelNG());
45 #else
46             if (Container::IsCurrentUseNewPipeline()) {
47                 instance_.reset(new NG::WaterFlowModelNG());
48             } else {
49                 instance_.reset(new Framework::WaterFlowModelImpl());
50             }
51 #endif
52         }
53     }
54     return instance_.get();
55 }
56 } // namespace OHOS::Ace
57 namespace OHOS::Ace::Framework {
58 namespace {
59 const std::vector<FlexDirection> LAYOUT_DIRECTION = { FlexDirection::ROW, FlexDirection::COLUMN,
60     FlexDirection::ROW_REVERSE, FlexDirection::COLUMN_REVERSE };
61 
62 namespace {
ParseChanges(const JSCallbackInfo & args,const JSRef<JSArray> & changeArray,RefPtr<NG::WaterFlowSections> & waterFlowSections)63 void ParseChanges(
64     const JSCallbackInfo& args, const JSRef<JSArray>& changeArray, RefPtr<NG::WaterFlowSections>& waterFlowSections)
65 {
66     auto length = changeArray->Length();
67     for (size_t i = 0; i < length; ++i) {
68         auto change = changeArray->GetValueAt(i);
69         if (!change->IsObject()) {
70             continue;
71         }
72         auto changeObject = JSRef<JSObject>::Cast(change);
73         auto sectionValue = changeObject->GetProperty("sections");
74         if (!sectionValue->IsArray()) {
75             continue;
76         }
77         auto sectionArray = JSRef<JSArray>::Cast(sectionValue);
78         auto sectionsCount = sectionArray->Length();
79         std::vector<NG::WaterFlowSections::Section> newSections;
80         for (size_t j = 0; j < sectionsCount; ++j) {
81             NG::WaterFlowSections::Section section;
82             auto newSection = sectionArray->GetValueAt(j);
83             if (JSWaterFlowSections::ParseSectionOptions(args, newSection, section)) {
84                 newSections.emplace_back(section);
85             }
86         }
87         waterFlowSections->ChangeData(changeObject->GetProperty("start")->ToNumber<int32_t>(),
88             changeObject->GetProperty("deleteCount")->ToNumber<int32_t>(), newSections);
89     }
90 }
91 
ParseSections(const JSCallbackInfo & args,const JSRef<JSArray> & sectionArray,RefPtr<NG::WaterFlowSections> & waterFlowSections)92 void ParseSections(
93     const JSCallbackInfo& args, const JSRef<JSArray>& sectionArray, RefPtr<NG::WaterFlowSections>& waterFlowSections)
94 {
95     auto length = sectionArray->Length();
96     std::vector<NG::WaterFlowSections::Section> newSections;
97     for (size_t j = 0; j < length; ++j) {
98         NG::WaterFlowSections::Section section;
99         auto newSection = sectionArray->GetValueAt(j);
100         if (JSWaterFlowSections::ParseSectionOptions(args, newSection, section)) {
101             newSections.emplace_back(section);
102         }
103     }
104     waterFlowSections->ChangeData(0, waterFlowSections->GetSectionInfo().size(), newSections);
105 }
106 
ParseScroller(const JSRef<JSObject> & obj)107 void ParseScroller(const JSRef<JSObject>& obj)
108 {
109     auto scroller = obj->GetProperty("scroller");
110     if (scroller->IsObject()) {
111         auto* jsScroller = JSRef<JSObject>::Cast(scroller)->Unwrap<JSScroller>();
112         CHECK_NULL_VOID(jsScroller);
113         jsScroller->SetInstanceId(Container::CurrentId());
114         auto positionController = WaterFlowModel::GetInstance()->CreateScrollController();
115         jsScroller->SetController(positionController);
116 
117         // Init scroll bar proxy.
118         auto proxy = jsScroller->GetScrollBarProxy();
119         if (!proxy) {
120             proxy = WaterFlowModel::GetInstance()->CreateScrollBarProxy();
121             jsScroller->SetScrollBarProxy(proxy);
122         }
123         WaterFlowModel::GetInstance()->SetScroller(positionController, proxy);
124     }
125 }
126 } // namespace
127 } // namespace
128 
UpdateSections(const JSCallbackInfo & args,const JSRef<JSVal> & sections,RefPtr<NG::WaterFlowSections> & waterFlowSections)129 void UpdateSections(
130     const JSCallbackInfo& args, const JSRef<JSVal>& sections, RefPtr<NG::WaterFlowSections>& waterFlowSections)
131 {
132     CHECK_NULL_VOID(waterFlowSections);
133     auto sectionsObject = JSRef<JSObject>::Cast(sections);
134     auto changes = sectionsObject->GetProperty("changeArray");
135     CHECK_NULL_VOID(changes->IsArray());
136     auto changeArray = JSRef<JSArray>::Cast(changes);
137     ParseChanges(args, changeArray, waterFlowSections);
138 
139     auto lengthFunc = sectionsObject->GetProperty("length");
140     CHECK_NULL_VOID(lengthFunc->IsFunction());
141     auto sectionLength = (JSRef<JSFunc>::Cast(lengthFunc))->Call(sectionsObject);
142     if (waterFlowSections->GetSectionInfo().size() != sectionLength->ToNumber<uint32_t>()) {
143         auto allSections = sectionsObject->GetProperty("sectionArray");
144         CHECK_NULL_VOID(allSections->IsArray());
145         ParseSections(args, JSRef<JSArray>::Cast(allSections), waterFlowSections);
146     }
147 
148     auto clearFunc = sectionsObject->GetProperty("clearChanges");
149     CHECK_NULL_VOID(clearFunc->IsFunction());
150     auto func = JSRef<JSFunc>::Cast(clearFunc);
151     func->Call(sectionsObject);
152 }
153 
UpdateWaterFlowSections(const JSCallbackInfo & args,const JSRef<JSVal> & sections)154 void UpdateWaterFlowSections(const JSCallbackInfo& args, const JSRef<JSVal>& sections)
155 {
156     auto waterFlowSections = WaterFlowModel::GetInstance()->GetOrCreateWaterFlowSections();
157     CHECK_NULL_VOID(waterFlowSections);
158     UpdateSections(args, sections, waterFlowSections);
159 }
160 
UpdateWaterFlowSectionsByFrameNode(NG::FrameNode * frameNode,const JSCallbackInfo & args,const JSRef<JSVal> & sections)161 void JSWaterFlow::UpdateWaterFlowSectionsByFrameNode(
162     NG::FrameNode* frameNode, const JSCallbackInfo& args, const JSRef<JSVal>& sections)
163 {
164     auto waterFlowSections = NG::WaterFlowModelNG::GetOrCreateWaterFlowSections(frameNode);
165     CHECK_NULL_VOID(waterFlowSections);
166     UpdateSections(args, sections, waterFlowSections);
167 }
168 
Create(const JSCallbackInfo & args)169 void JSWaterFlow::Create(const JSCallbackInfo& args)
170 {
171     if (args.Length() > 1) {
172         LOGW("Arg is wrong, it is supposed to have at most one argument");
173         return;
174     }
175 
176     WaterFlowModel::GetInstance()->Create();
177 
178     if (args.Length() == 0) {
179         return;
180     }
181 
182     if (!args[0]->IsObject()) {
183         LOGE("The arg must be object");
184         return;
185     }
186     JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
187 
188     // set layout mode first. SetFooter is dependent to it
189     using LayoutMode = NG::WaterFlowLayoutMode;
190     auto mode = LayoutMode::TOP_DOWN;
191     auto jsMode = obj->GetProperty("layoutMode");
192     if (jsMode->IsNumber()) {
193         mode = static_cast<LayoutMode>(jsMode->ToNumber<int32_t>());
194         if (mode < LayoutMode::TOP_DOWN || mode > LayoutMode::SLIDING_WINDOW) {
195             mode = LayoutMode::TOP_DOWN;
196         }
197     }
198     WaterFlowModel::GetInstance()->SetLayoutMode(mode);
199 
200     ParseScroller(obj);
201 
202     auto sections = obj->GetProperty("sections");
203     auto footerObject = obj->GetProperty("footer");
204     if (sections->IsObject()) {
205         UpdateWaterFlowSections(args, sections);
206     } else {
207         WaterFlowModel::GetInstance()->ResetSections();
208 
209         if (footerObject->IsFunction()) {
210             // ignore footer if sections are present
211             auto builderFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(footerObject));
212             auto footerAction = [builderFunc]() { builderFunc->Execute(); };
213             WaterFlowModel::GetInstance()->SetFooter(footerAction);
214         }
215     }
216 }
217 
JSBind(BindingTarget globalObj)218 void JSWaterFlow::JSBind(BindingTarget globalObj)
219 {
220     JSClass<JSWaterFlow>::Declare("WaterFlow");
221 
222     MethodOptions opt = MethodOptions::NONE;
223     JSClass<JSWaterFlow>::StaticMethod("create", &JSWaterFlow::Create, opt);
224     JSClass<JSWaterFlow>::StaticMethod("columnsGap", &JSWaterFlow::SetColumnsGap, opt);
225     JSClass<JSWaterFlow>::StaticMethod("rowsGap", &JSWaterFlow::SetRowsGap, opt);
226     JSClass<JSWaterFlow>::StaticMethod("layoutDirection", &JSWaterFlow::SetLayoutDirection, opt);
227     JSClass<JSWaterFlow>::StaticMethod("columnsTemplate", &JSWaterFlow::SetColumnsTemplate, opt);
228     JSClass<JSWaterFlow>::StaticMethod("itemConstraintSize", &JSWaterFlow::SetItemConstraintSize, opt);
229     JSClass<JSWaterFlow>::StaticMethod("rowsTemplate", &JSWaterFlow::SetRowsTemplate, opt);
230     JSClass<JSWaterFlow>::StaticMethod("nestedScroll", &JSWaterFlow::SetNestedScroll);
231     JSClass<JSWaterFlow>::StaticMethod("enableScrollInteraction", &JSWaterFlow::SetScrollEnabled);
232     JSClass<JSWaterFlow>::StaticMethod("onReachStart", &JSWaterFlow::ReachStartCallback);
233     JSClass<JSWaterFlow>::StaticMethod("onReachEnd", &JSWaterFlow::ReachEndCallback);
234     JSClass<JSWaterFlow>::StaticMethod("onScrollFrameBegin", &JSWaterFlow::ScrollFrameBeginCallback);
235     JSClass<JSWaterFlow>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
236     JSClass<JSWaterFlow>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
237     JSClass<JSWaterFlow>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
238     JSClass<JSWaterFlow>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
239     JSClass<JSWaterFlow>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
240     JSClass<JSWaterFlow>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
241     JSClass<JSWaterFlow>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
242     JSClass<JSWaterFlow>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
243     JSClass<JSWaterFlow>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
244     JSClass<JSWaterFlow>::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage);
245     JSClass<JSWaterFlow>::StaticMethod("friction", &JSWaterFlow::SetFriction);
246     JSClass<JSWaterFlow>::StaticMethod("clip", &JSScrollable::JsClip);
247     JSClass<JSWaterFlow>::StaticMethod("cachedCount", &JSWaterFlow::SetCachedCount);
248     JSClass<JSWaterFlow>::StaticMethod("edgeEffect", &JSWaterFlow::SetEdgeEffect);
249 
250     JSClass<JSWaterFlow>::StaticMethod("onScroll", &JSWaterFlow::JsOnScroll);
251     JSClass<JSWaterFlow>::StaticMethod("onScrollStart", &JSWaterFlow::JsOnScrollStart);
252     JSClass<JSWaterFlow>::StaticMethod("onScrollStop", &JSWaterFlow::JsOnScrollStop);
253     JSClass<JSWaterFlow>::StaticMethod("onScrollIndex", &JSWaterFlow::JsOnScrollIndex);
254 
255     JSClass<JSWaterFlow>::StaticMethod("scrollBar", &JSWaterFlow::SetScrollBar, opt);
256     JSClass<JSWaterFlow>::StaticMethod("scrollBarWidth", &JSWaterFlow::SetScrollBarWidth, opt);
257     JSClass<JSWaterFlow>::StaticMethod("scrollBarColor", &JSWaterFlow::SetScrollBarColor, opt);
258 
259     JSClass<JSWaterFlow>::InheritAndBind<JSScrollableBase>(globalObj);
260 }
261 
SetColumnsGap(const JSCallbackInfo & info)262 void JSWaterFlow::SetColumnsGap(const JSCallbackInfo& info)
263 {
264     if (info.Length() < 1) {
265         return;
266     }
267     CalcDimension colGap;
268     if (!ParseJsDimensionVp(info[0], colGap) || colGap.Value() < 0) {
269         colGap.SetValue(0.0);
270     }
271     WaterFlowModel::GetInstance()->SetColumnsGap(colGap);
272 }
273 
SetRowsGap(const JSCallbackInfo & info)274 void JSWaterFlow::SetRowsGap(const JSCallbackInfo& info)
275 {
276     if (info.Length() < 1) {
277         return;
278     }
279     CalcDimension rowGap;
280     if (!ParseJsDimensionVp(info[0], rowGap) || rowGap.Value() < 0) {
281         rowGap.SetValue(0.0);
282     }
283     WaterFlowModel::GetInstance()->SetRowsGap(rowGap);
284 }
285 
SetLayoutDirection(const JSCallbackInfo & info)286 void JSWaterFlow::SetLayoutDirection(const JSCallbackInfo& info)
287 {
288     if (info.Length() < 1) {
289         return;
290     }
291     auto value = static_cast<int32_t>(FlexDirection::COLUMN);
292     auto jsValue = info[0];
293     if (!jsValue->IsUndefined()) {
294         ParseJsInteger<int32_t>(jsValue, value);
295     }
296     if (value >= 0 && value < static_cast<int32_t>(LAYOUT_DIRECTION.size())) {
297         WaterFlowModel::GetInstance()->SetLayoutDirection(LAYOUT_DIRECTION[value]);
298     } else {
299         WaterFlowModel::GetInstance()->SetLayoutDirection(FlexDirection::COLUMN);
300     }
301 }
302 
SetColumnsTemplate(const std::string & value)303 void JSWaterFlow::SetColumnsTemplate(const std::string& value)
304 {
305     WaterFlowModel::GetInstance()->SetColumnsTemplate(value);
306 }
307 
SetItemConstraintSize(const JSCallbackInfo & info)308 void JSWaterFlow::SetItemConstraintSize(const JSCallbackInfo& info)
309 {
310     if (info.Length() < 1 || !info[0]->IsObject()) {
311         return;
312     }
313 
314     JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
315 
316     JSRef<JSVal> minWidthValue = sizeObj->GetProperty("minWidth");
317     CalcDimension minWidth;
318     if (ParseJsDimensionVp(minWidthValue, minWidth)) {
319         WaterFlowModel::GetInstance()->SetItemMinWidth(minWidth);
320     }
321 
322     JSRef<JSVal> maxWidthValue = sizeObj->GetProperty("maxWidth");
323     CalcDimension maxWidth;
324     if (ParseJsDimensionVp(maxWidthValue, maxWidth)) {
325         WaterFlowModel::GetInstance()->SetItemMaxWidth(maxWidth);
326     }
327 
328     JSRef<JSVal> minHeightValue = sizeObj->GetProperty("minHeight");
329     CalcDimension minHeight;
330     if (ParseJsDimensionVp(minHeightValue, minHeight)) {
331         WaterFlowModel::GetInstance()->SetItemMinHeight(minHeight);
332     }
333 
334     JSRef<JSVal> maxHeightValue = sizeObj->GetProperty("maxHeight");
335     CalcDimension maxHeight;
336     if (ParseJsDimensionVp(maxHeightValue, maxHeight)) {
337         WaterFlowModel::GetInstance()->SetItemMaxHeight(maxHeight);
338     }
339 }
340 
SetRowsTemplate(const std::string & value)341 void JSWaterFlow::SetRowsTemplate(const std::string& value)
342 {
343     WaterFlowModel::GetInstance()->SetRowsTemplate(value);
344 }
345 
SetNestedScroll(const JSCallbackInfo & args)346 void JSWaterFlow::SetNestedScroll(const JSCallbackInfo& args)
347 {
348     NestedScrollOptions nestedOpt = {
349         .forward = NestedScrollMode::SELF_ONLY,
350         .backward = NestedScrollMode::SELF_ONLY,
351     };
352     if (args.Length() < 1 || !args[0]->IsObject()) {
353         WaterFlowModel::GetInstance()->SetNestedScroll(nestedOpt);
354         LOGW("Invalid params");
355         return;
356     }
357     JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
358     int32_t froward = 0;
359     JSViewAbstract::ParseJsInt32(obj->GetProperty("scrollForward"), froward);
360     if (froward < static_cast<int32_t>(NestedScrollMode::SELF_ONLY) ||
361         froward > static_cast<int32_t>(NestedScrollMode::PARALLEL)) {
362         LOGW("ScrollFroward params invalid");
363         froward = 0;
364     }
365     int32_t backward = 0;
366     JSViewAbstract::ParseJsInt32(obj->GetProperty("scrollBackward"), backward);
367     if (backward < static_cast<int32_t>(NestedScrollMode::SELF_ONLY) ||
368         backward > static_cast<int32_t>(NestedScrollMode::PARALLEL)) {
369         LOGW("ScrollFroward params invalid");
370         backward = 0;
371     }
372     nestedOpt.forward = static_cast<NestedScrollMode>(froward);
373     nestedOpt.backward = static_cast<NestedScrollMode>(backward);
374     WaterFlowModel::GetInstance()->SetNestedScroll(nestedOpt);
375     args.ReturnSelf();
376 }
377 
SetScrollEnabled(const JSCallbackInfo & args)378 void JSWaterFlow::SetScrollEnabled(const JSCallbackInfo& args)
379 {
380     WaterFlowModel::GetInstance()->SetScrollEnabled(args[0]->IsBoolean() ? args[0]->ToBoolean() : true);
381 }
382 
SetFriction(const JSCallbackInfo & info)383 void JSWaterFlow::SetFriction(const JSCallbackInfo& info)
384 {
385     double friction = -1.0;
386     if (!JSViewAbstract::ParseJsDouble(info[0], friction)) {
387         LOGW("Friction params invalid,can not convert to double");
388         friction = -1.0;
389     }
390     WaterFlowModel::GetInstance()->SetFriction(friction);
391 }
392 
ReachStartCallback(const JSCallbackInfo & args)393 void JSWaterFlow::ReachStartCallback(const JSCallbackInfo& args)
394 {
395     if (args[0]->IsFunction()) {
396         auto onReachStart = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
397             func->Call(JSRef<JSObject>());
398 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
399             UiSessionManager::GetInstance().ReportComponentChangeEvent("event", "onReachStart");
400 #endif
401             return;
402         };
403         WaterFlowModel::GetInstance()->SetOnReachStart(std::move(onReachStart));
404     }
405     args.ReturnSelf();
406 }
407 
ReachEndCallback(const JSCallbackInfo & args)408 void JSWaterFlow::ReachEndCallback(const JSCallbackInfo& args)
409 {
410     if (args[0]->IsFunction()) {
411         auto onReachEnd = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
412             func->Call(JSRef<JSObject>());
413 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
414             UiSessionManager::GetInstance().ReportComponentChangeEvent("event", "onReachEnd");
415 #endif
416             return;
417         };
418         WaterFlowModel::GetInstance()->SetOnReachEnd(std::move(onReachEnd));
419     }
420     args.ReturnSelf();
421 }
422 
ScrollFrameBeginCallback(const JSCallbackInfo & args)423 void JSWaterFlow::ScrollFrameBeginCallback(const JSCallbackInfo& args)
424 {
425     if (args[0]->IsFunction()) {
426         auto onScrollBegin = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
427                                  const Dimension& offset, const ScrollState& state) -> ScrollFrameResult {
428             ScrollFrameResult scrollRes { .offset = offset };
429             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx, scrollRes);
430             auto params = ConvertToJSValues(offset, state);
431             auto result = func->Call(JSRef<JSObject>(), params.size(), params.data());
432             if (result.IsEmpty()) {
433                 LOGE("Error calling onScrollFrameBegin, result is empty.");
434                 return scrollRes;
435             }
436 
437             if (!result->IsObject()) {
438                 LOGE("Error calling onScrollFrameBegin, result is not object.");
439                 return scrollRes;
440             }
441 
442             auto resObj = JSRef<JSObject>::Cast(result);
443             auto dxRemainValue = resObj->GetProperty("offsetRemain");
444             if (dxRemainValue->IsNumber()) {
445                 scrollRes.offset = Dimension(dxRemainValue->ToNumber<float>(), DimensionUnit::VP);
446             }
447             return scrollRes;
448         };
449         WaterFlowModel::GetInstance()->SetOnScrollFrameBegin(std::move(onScrollBegin));
450     }
451 }
452 
SetCachedCount(const JSCallbackInfo & info)453 void JSWaterFlow::SetCachedCount(const JSCallbackInfo& info)
454 {
455     int32_t cachedCount = 1;
456     auto jsValue = info[0];
457 
458     if (!jsValue->IsUndefined() && jsValue->IsNumber()) {
459         ParseJsInt32(jsValue, cachedCount);
460         if (cachedCount < 0) {
461             cachedCount = 1;
462         }
463     }
464     bool show = false;
465     if (info.Length() > 1) {
466         show = info[1]->ToBoolean();
467     }
468     WaterFlowModel::GetInstance()->SetCachedCount(cachedCount, show);
469 }
470 
SetEdgeEffect(const JSCallbackInfo & info)471 void JSWaterFlow::SetEdgeEffect(const JSCallbackInfo& info)
472 {
473     auto edgeEffect = WaterFlowModel::GetInstance()->GetEdgeEffect();
474     if (info.Length() > 0) {
475         edgeEffect = JSScrollable::ParseEdgeEffect(info[0], edgeEffect);
476     }
477     auto alwaysEnabled = WaterFlowModel::GetInstance()->GetAlwaysEnableEdgeEffect();
478     if (info.Length() > 1) {
479         alwaysEnabled =
480             JSScrollable::ParseAlwaysEnable(info[1], alwaysEnabled);
481     }
482     WaterFlowModel::GetInstance()->SetEdgeEffect(edgeEffect, alwaysEnabled);
483 }
484 
JsOnScroll(const JSCallbackInfo & args)485 void JSWaterFlow::JsOnScroll(const JSCallbackInfo& args)
486 {
487     if (args[0]->IsFunction()) {
488         auto onScroll = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
489                             const CalcDimension& scrollOffset, const ScrollState& scrollState) {
490             auto params = ConvertToJSValues(scrollOffset, scrollState);
491             func->Call(JSRef<JSObject>(), params.size(), params.data());
492             return;
493         };
494         WaterFlowModel::GetInstance()->SetOnScroll(std::move(onScroll));
495     }
496     args.ReturnSelf();
497 }
498 
JsOnScrollStart(const JSCallbackInfo & args)499 void JSWaterFlow::JsOnScrollStart(const JSCallbackInfo& args)
500 {
501     if (args[0]->IsFunction()) {
502         auto onScrollStart = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
503             func->Call(JSRef<JSObject>());
504             return;
505         };
506         WaterFlowModel::GetInstance()->SetOnScrollStart(std::move(onScrollStart));
507     }
508     args.ReturnSelf();
509 }
510 
JsOnScrollStop(const JSCallbackInfo & args)511 void JSWaterFlow::JsOnScrollStop(const JSCallbackInfo& args)
512 {
513     if (args[0]->IsFunction()) {
514         auto onScrollStop = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
515             func->Call(JSRef<JSObject>());
516             return;
517         };
518         WaterFlowModel::GetInstance()->SetOnScrollStop(std::move(onScrollStop));
519     }
520     args.ReturnSelf();
521 }
522 
JsOnScrollIndex(const JSCallbackInfo & args)523 void JSWaterFlow::JsOnScrollIndex(const JSCallbackInfo& args)
524 {
525     if (args[0]->IsFunction()) {
526         auto onScrollIndex = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])](
527                                  const int32_t first, const int32_t last) {
528             JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
529             auto params = ConvertToJSValues(first, last);
530             func->Call(JSRef<JSObject>(), params.size(), params.data());
531 #if !defined(PREVIEW) && defined(OHOS_PLATFORM)
532             UiSessionManager::GetInstance().ReportComponentChangeEvent("event", "onScrollIndex");
533 #endif
534             return;
535         };
536         WaterFlowModel::GetInstance()->SetOnScrollIndex(std::move(onScrollIndex));
537     }
538     args.ReturnSelf();
539 }
540 
SetScrollBar(const JSCallbackInfo & info)541 void JSWaterFlow::SetScrollBar(const JSCallbackInfo& info)
542 {
543     auto displayMode = JSScrollable::ParseDisplayMode(info, WaterFlowModel::GetDisplayMode());
544     WaterFlowModel::GetInstance()->SetScrollBarMode(displayMode);
545 }
546 
SetScrollBarColor(const JSCallbackInfo & info)547 void JSWaterFlow::SetScrollBarColor(const JSCallbackInfo& info)
548 {
549     auto scrollBarColor = JSScrollable::ParseBarColor(info);
550     if (!scrollBarColor.empty()) {
551         WaterFlowModel::GetInstance()->SetScrollBarColor(scrollBarColor);
552     }
553 }
554 
SetScrollBarWidth(const JSCallbackInfo & scrollWidth)555 void JSWaterFlow::SetScrollBarWidth(const JSCallbackInfo& scrollWidth)
556 {
557     auto scrollBarWidth = JSScrollable::ParseBarWidth(scrollWidth);
558     if (!scrollBarWidth.empty()) {
559         WaterFlowModel::GetInstance()->SetScrollBarWidth(scrollBarWidth);
560     }
561 }
562 } // namespace OHOS::Ace::Framework
563