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