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