1 /*
2 * Copyright (c) 2022-2023 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 "frameworks/bridge/declarative_frontend/jsview/js_water_flow.h"
17
18 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
19 #include "frameworks/bridge/declarative_frontend/jsview/js_interactable_view.h"
20 #include "frameworks/bridge/declarative_frontend/jsview/js_scroller.h"
21 #include "frameworks/bridge/declarative_frontend/jsview/models/water_flow_model_impl.h"
22 #include "frameworks/bridge/declarative_frontend/view_stack_processor.h"
23 #include "frameworks/core/components_ng/pattern/waterflow/water_flow_model_ng.h"
24
25 namespace OHOS::Ace {
26 std::unique_ptr<WaterFlowModel> WaterFlowModel::instance_ = nullptr;
27
GetInstance()28 WaterFlowModel* WaterFlowModel::GetInstance()
29 {
30 if (!instance_) {
31 #ifdef NG_BUILD
32 instance_.reset(new NG::WaterFlowModelNG());
33 #else
34 if (Container::IsCurrentUseNewPipeline()) {
35 instance_.reset(new NG::WaterFlowModelNG());
36 } else {
37 instance_.reset(new Framework::WaterFlowModelImpl());
38 }
39 #endif
40 }
41 return instance_.get();
42 }
43 } // namespace OHOS::Ace
44 namespace OHOS::Ace::Framework {
45 namespace {
46 const std::vector<FlexDirection> LAYOUT_DIRECTION = { FlexDirection::ROW, FlexDirection::COLUMN,
47 FlexDirection::ROW_REVERSE, FlexDirection::COLUMN_REVERSE };
48 } // namespace
49
Create(const JSCallbackInfo & args)50 void JSWaterFlow::Create(const JSCallbackInfo& args)
51 {
52 LOGI("Create component: WaterFLow");
53 if (args.Length() > 1) {
54 LOGW("Arg is wrong, it is supposed to have at most one argument");
55 return;
56 }
57
58 WaterFlowModel::GetInstance()->Create();
59
60 if (args.Length() == 1) {
61 if (!args[0]->IsObject()) {
62 LOGE("The arg must be object");
63 return;
64 }
65 JSRef<JSObject> obj = JSRef<JSObject>::Cast(args[0]);
66 auto footerObject = obj->GetProperty("footer");
67 if (footerObject->IsFunction()) {
68 auto builderFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSFunc>::Cast(footerObject));
69 auto footerAction = [builderFunc]() { builderFunc->Execute(); };
70 WaterFlowModel::GetInstance()->SetFooter(footerAction);
71 }
72 auto scroller = obj->GetProperty("scroller");
73 if (scroller->IsObject()) {
74 auto* jsScroller = JSRef<JSObject>::Cast(scroller)->Unwrap<JSScroller>();
75 CHECK_NULL_VOID(jsScroller);
76 auto positionController = WaterFlowModel::GetInstance()->CreateScrollController();
77 jsScroller->SetController(positionController);
78
79 // Init scroll bar proxy.
80 auto proxy = jsScroller->GetScrollBarProxy();
81 if (!proxy) {
82 proxy = WaterFlowModel::GetInstance()->CreateScrollBarProxy();
83 jsScroller->SetScrollBarProxy(proxy);
84 }
85 WaterFlowModel::GetInstance()->SetScroller(positionController, proxy);
86 }
87 }
88 }
89
JSBind(BindingTarget globalObj)90 void JSWaterFlow::JSBind(BindingTarget globalObj)
91 {
92 LOGD("JSWaterFlow:JSBind");
93 JSClass<JSWaterFlow>::Declare("WaterFlow");
94
95 MethodOptions opt = MethodOptions::NONE;
96 JSClass<JSWaterFlow>::StaticMethod("create", &JSWaterFlow::Create, opt);
97 JSClass<JSWaterFlow>::StaticMethod("columnsGap", &JSWaterFlow::SetColumnsGap, opt);
98 JSClass<JSWaterFlow>::StaticMethod("rowsGap", &JSWaterFlow::SetRowsGap, opt);
99 JSClass<JSWaterFlow>::StaticMethod("layoutDirection", &JSWaterFlow::SetLayoutDirection, opt);
100 JSClass<JSWaterFlow>::StaticMethod("columnsTemplate", &JSWaterFlow::SetColumnsTemplate, opt);
101 JSClass<JSWaterFlow>::StaticMethod("itemConstraintSize", &JSWaterFlow::SetItemConstraintSize, opt);
102 JSClass<JSWaterFlow>::StaticMethod("rowsTemplate", &JSWaterFlow::SetRowsTemplate, opt);
103 JSClass<JSWaterFlow>::StaticMethod("onReachStart", &JSWaterFlow::ReachStartCallback);
104 JSClass<JSWaterFlow>::StaticMethod("onReachEnd", &JSWaterFlow::ReachEndCallback);
105 JSClass<JSWaterFlow>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
106 JSClass<JSWaterFlow>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
107 JSClass<JSWaterFlow>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
108 JSClass<JSWaterFlow>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
109 JSClass<JSWaterFlow>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
110 JSClass<JSWaterFlow>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
111 JSClass<JSWaterFlow>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
112 JSClass<JSWaterFlow>::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage);
113
114 JSClass<JSWaterFlow>::Inherit<JSContainerBase>();
115 JSClass<JSWaterFlow>::Inherit<JSViewAbstract>();
116 JSClass<JSWaterFlow>::Bind<>(globalObj);
117 }
118
SetColumnsGap(const JSCallbackInfo & info)119 void JSWaterFlow::SetColumnsGap(const JSCallbackInfo& info)
120 {
121 if (info.Length() < 1) {
122 LOGW("Arg is wrong, it is supposed to have at least 1 argument");
123 return;
124 }
125 Dimension colGap;
126 if (!ParseJsDimensionVp(info[0], colGap) || colGap.Value() < 0) {
127 colGap.SetValue(0.0);
128 }
129 WaterFlowModel::GetInstance()->SetColumnsGap(colGap);
130 }
131
SetRowsGap(const JSCallbackInfo & info)132 void JSWaterFlow::SetRowsGap(const JSCallbackInfo& info)
133 {
134 if (info.Length() < 1) {
135 LOGW("Arg is wrong, it is supposed to have at least 1 argument");
136 return;
137 }
138 Dimension rowGap;
139 if (!ParseJsDimensionVp(info[0], rowGap) || rowGap.Value() < 0) {
140 rowGap.SetValue(0.0);
141 }
142 WaterFlowModel::GetInstance()->SetRowsGap(rowGap);
143 }
144
SetLayoutDirection(const JSCallbackInfo & info)145 void JSWaterFlow::SetLayoutDirection(const JSCallbackInfo& info)
146 {
147 if (info.Length() < 1) {
148 LOGE("The arg is wrong, it is supposed to have at least 1 arguments");
149 return;
150 }
151 auto value = static_cast<int32_t>(FlexDirection::COLUMN);
152 auto jsValue = info[0];
153 if (!jsValue->IsUndefined()) {
154 ParseJsInteger<int32_t>(jsValue, value);
155 }
156 if (value >= 0 && value < static_cast<int32_t>(LAYOUT_DIRECTION.size())) {
157 WaterFlowModel::GetInstance()->SetLayoutDirection(LAYOUT_DIRECTION[value]);
158 } else {
159 WaterFlowModel::GetInstance()->SetLayoutDirection(FlexDirection::COLUMN);
160 }
161 }
162
SetColumnsTemplate(const std::string & value)163 void JSWaterFlow::SetColumnsTemplate(const std::string& value)
164 {
165 WaterFlowModel::GetInstance()->SetColumnsTemplate(value);
166 }
167
SetItemConstraintSize(const JSCallbackInfo & info)168 void JSWaterFlow::SetItemConstraintSize(const JSCallbackInfo& info)
169 {
170 if (info.Length() < 1 || !info[0]->IsObject()) {
171 LOGI("waterflow create error, info is invalid");
172 return;
173 }
174
175 JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
176
177 JSRef<JSVal> minWidthValue = sizeObj->GetProperty("minWidth");
178 Dimension minWidth;
179 if (ParseJsDimensionVp(minWidthValue, minWidth)) {
180 WaterFlowModel::GetInstance()->SetItemMinWidth(minWidth);
181 }
182
183 JSRef<JSVal> maxWidthValue = sizeObj->GetProperty("maxWidth");
184 Dimension maxWidth;
185 if (ParseJsDimensionVp(maxWidthValue, maxWidth)) {
186 WaterFlowModel::GetInstance()->SetItemMaxWidth(maxWidth);
187 }
188
189 JSRef<JSVal> minHeightValue = sizeObj->GetProperty("minHeight");
190 Dimension minHeight;
191 if (ParseJsDimensionVp(minHeightValue, minHeight)) {
192 WaterFlowModel::GetInstance()->SetItemMinHeight(minHeight);
193 }
194
195 JSRef<JSVal> maxHeightValue = sizeObj->GetProperty("maxHeight");
196 Dimension maxHeight;
197 if (ParseJsDimensionVp(maxHeightValue, maxHeight)) {
198 WaterFlowModel::GetInstance()->SetItemMaxHeight(maxHeight);
199 }
200 }
201
SetRowsTemplate(const std::string & value)202 void JSWaterFlow::SetRowsTemplate(const std::string& value)
203 {
204 WaterFlowModel::GetInstance()->SetRowsTemplate(value);
205 }
206
ReachStartCallback(const JSCallbackInfo & args)207 void JSWaterFlow::ReachStartCallback(const JSCallbackInfo& args)
208 {
209 if (args[0]->IsFunction()) {
210 auto onReachStart = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
211 func->Call(JSRef<JSObject>());
212 return;
213 };
214 WaterFlowModel::GetInstance()->SetOnReachStart(std::move(onReachStart));
215 }
216 args.ReturnSelf();
217 }
218
ReachEndCallback(const JSCallbackInfo & args)219 void JSWaterFlow::ReachEndCallback(const JSCallbackInfo& args)
220 {
221 if (args[0]->IsFunction()) {
222 auto onReachEnd = [execCtx = args.GetExecutionContext(), func = JSRef<JSFunc>::Cast(args[0])]() {
223 func->Call(JSRef<JSObject>());
224 return;
225 };
226 WaterFlowModel::GetInstance()->SetOnReachEnd(std::move(onReachEnd));
227 }
228 args.ReturnSelf();
229 }
230 } // namespace OHOS::Ace::Framework
231