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