• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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_toggle.h"
17 
18 #include <cstddef>
19 #include <string>
20 
21 #include "base/log/ace_scoring_log.h"
22 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
23 #include "bridge/declarative_frontend/jsview/models/toggle_model_impl.h"
24 #include "core/common/container.h"
25 #include "core/components/common/properties/color.h"
26 #include "core/components/toggle/toggle_theme.h"
27 #include "core/components_ng/pattern/button/toggle_button_model_ng.h"
28 #include "core/components_ng/pattern/toggle/toggle_model_ng.h"
29 
30 namespace OHOS::Ace {
31 
32 std::unique_ptr<ToggleModel> ToggleModel::instance_ = nullptr;
33 std::mutex ToggleModel::mutex_;
34 
GetInstance()35 ToggleModel* ToggleModel::GetInstance()
36 {
37     if (!instance_) {
38         std::lock_guard<std::mutex> lock(mutex_);
39         if (!instance_) {
40 #ifdef NG_BUILD
41             instance_.reset(new NG::ToggleModelNG());
42 #else
43             if (Container::IsCurrentUseNewPipeline()) {
44                 instance_.reset(new NG::ToggleModelNG());
45             } else {
46                 instance_.reset(new Framework::ToggleModelImpl());
47             }
48 #endif
49         }
50     }
51     return instance_.get();
52 }
53 
54 } // namespace OHOS::Ace
55 
56 namespace OHOS::Ace::Framework {
57 int32_t JSToggle::toggleType_ = 1;
58 const static int32_t PLATFORM_VERSION_TEN = 10;
JSBind(BindingTarget globalObj)59 void JSToggle::JSBind(BindingTarget globalObj)
60 {
61     JSClass<JSToggle>::Declare("Toggle");
62     JSClass<JSToggle>::StaticMethod("create", &JSToggle::Create);
63     JSClass<JSToggle>::StaticMethod("onChange", &JSToggle::OnChange);
64     JSClass<JSToggle>::StaticMethod("selectedColor", &JSToggle::SelectedColor);
65     JSClass<JSToggle>::StaticMethod("width", &JSToggle::JsWidth);
66     JSClass<JSToggle>::StaticMethod("height", &JSToggle::JsHeight);
67     JSClass<JSToggle>::StaticMethod("responseRegion", &JSToggle::JsResponseRegion);
68     JSClass<JSToggle>::StaticMethod("size", &JSToggle::JsSize);
69     JSClass<JSToggle>::StaticMethod("padding", &JSToggle::JsPadding);
70     JSClass<JSToggle>::StaticMethod("switchPointColor", &JSToggle::SwitchPointColor);
71     JSClass<JSToggle>::StaticMethod("backgroundColor", &JSToggle::SetBackgroundColor);
72 
73     JSClass<JSToggle>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
74     JSClass<JSToggle>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
75     JSClass<JSToggle>::StaticMethod("onHover", &JSInteractableView::JsOnHover);
76     JSClass<JSToggle>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
77     JSClass<JSToggle>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
78     JSClass<JSToggle>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
79     JSClass<JSToggle>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
80     JSClass<JSToggle>::InheritAndBind<JSViewAbstract>(globalObj);
81 }
82 
ParseToggleIsOnObject(const JSCallbackInfo & info,const JSRef<JSVal> & changeEventVal)83 void ParseToggleIsOnObject(const JSCallbackInfo& info, const JSRef<JSVal>& changeEventVal)
84 {
85     CHECK_NULL_VOID(changeEventVal->IsFunction());
86 
87     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(changeEventVal));
88     auto onChangeEvent = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](bool isOn) {
89         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
90         ACE_SCORING_EVENT("Toggle.onChangeEvent");
91         auto newJSVal = JSRef<JSVal>::Make(ToJSValue(isOn));
92         func->ExecuteJS(1, &newJSVal);
93     };
94     ToggleModel::GetInstance()->OnChangeEvent(std::move(onChangeEvent));
95 }
96 
Create(const JSCallbackInfo & info)97 void JSToggle::Create(const JSCallbackInfo& info)
98 {
99     if (info.Length() < 1 || !info[0]->IsObject()) {
100         LOGE("toggle create error, info is non-valid");
101         return;
102     }
103 
104     auto paramObject = JSRef<JSObject>::Cast(info[0]);
105     auto type = paramObject->GetProperty("type");
106     int32_t toggleTypeInt = 1;
107     if (type->IsNumber()) {
108         toggleTypeInt = type->ToNumber<int32_t>();
109     }
110     if (toggleTypeInt < 0 || toggleTypeInt > 2) {
111         toggleTypeInt = 1;
112     }
113     toggleType_ = toggleTypeInt;
114     auto tempIsOn = paramObject->GetProperty("isOn");
115     bool isOn = false;
116     JSRef<JSVal> changeEventVal;
117     if (tempIsOn->IsObject()) {
118         JSRef<JSObject> isOnObj = JSRef<JSObject>::Cast(tempIsOn);
119         changeEventVal = isOnObj->GetProperty("changeEvent");
120         auto isOnProperty = isOnObj->GetProperty("value");
121         isOn = isOnProperty->IsBoolean() ? isOnProperty->ToBoolean() : false;
122     } else {
123         isOn = tempIsOn->IsBoolean() ? tempIsOn->ToBoolean() : false;
124     }
125 
126     ToggleModel::GetInstance()->Create(NG::ToggleType(toggleTypeInt), isOn);
127     if (!changeEventVal->IsUndefined() && changeEventVal->IsFunction()) {
128         ParseToggleIsOnObject(info, changeEventVal);
129     }
130 }
131 
JsWidth(const JSCallbackInfo & info)132 void JSToggle::JsWidth(const JSCallbackInfo& info)
133 {
134     if (info.Length() < 1) {
135         LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
136         return;
137     }
138 
139     JsWidth(info[0]);
140 }
141 
JsWidth(const JSRef<JSVal> & jsValue)142 void JSToggle::JsWidth(const JSRef<JSVal>& jsValue)
143 {
144     auto switchTheme = GetTheme<SwitchTheme>();
145     CHECK_NULL_VOID(switchTheme);
146     auto defaultWidth = switchTheme->GetWidth();
147     auto horizontalPadding = switchTheme->GetHotZoneHorizontalPadding();
148     auto width = defaultWidth - horizontalPadding * 2;
149     if (toggleType_ == 0) {
150         auto checkboxTheme = GetTheme<CheckboxTheme>();
151         CHECK_NULL_VOID(checkboxTheme);
152         defaultWidth = checkboxTheme->GetDefaultWidth();
153         horizontalPadding = checkboxTheme->GetHotZoneHorizontalPadding();
154         width = defaultWidth - horizontalPadding * 2;
155     }
156     CalcDimension value(width);
157     ParseJsDimensionVp(jsValue, value);
158     if (value.IsNegative()) {
159         value = width;
160     }
161     ToggleModel::GetInstance()->SetWidth(value);
162 }
163 
JsHeight(const JSCallbackInfo & info)164 void JSToggle::JsHeight(const JSCallbackInfo& info)
165 {
166     if (info.Length() < 1) {
167         LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
168         return;
169     }
170 
171     JsHeight(info[0]);
172 }
173 
JsHeight(const JSRef<JSVal> & jsValue)174 void JSToggle::JsHeight(const JSRef<JSVal>& jsValue)
175 {
176     auto pipeline = PipelineBase::GetCurrentContext();
177     CHECK_NULL_VOID(pipeline);
178     auto switchTheme = pipeline->GetTheme<SwitchTheme>();
179     CHECK_NULL_VOID(switchTheme);
180     auto defaultHeight = switchTheme->GetHeight();
181     auto verticalPadding = switchTheme->GetHotZoneVerticalPadding();
182     auto height = defaultHeight - verticalPadding * 2;
183     CalcDimension value(height);
184     if (PipelineBase::GetCurrentContext() &&
185         PipelineBase::GetCurrentContext()->GetMinPlatformVersion() >= PLATFORM_VERSION_TEN) {
186         if (!ParseJsDimensionVpNG(jsValue, value)) {
187             value = height;
188         }
189     } else {
190         ParseJsDimensionVp(jsValue, value);
191         if (value.IsNegative()) {
192             value = height;
193         }
194     }
195     ToggleModel::GetInstance()->SetHeight(value);
196 }
197 
JsResponseRegion(const JSCallbackInfo & info)198 void JSToggle::JsResponseRegion(const JSCallbackInfo& info)
199 {
200     if (!Container::IsCurrentUseNewPipeline()) {
201         JSViewAbstract::JsResponseRegion(info);
202         return;
203     }
204     std::vector<DimensionRect> result;
205     if (!JSViewAbstract::ParseJsResponseRegionArray(info[0], result)) {
206         return;
207     }
208     ToggleModel::GetInstance()->SetResponseRegion(result);
209 }
210 
JsSize(const JSCallbackInfo & info)211 void JSToggle::JsSize(const JSCallbackInfo& info)
212 {
213     if (info.Length() < 1) {
214         LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
215         return;
216     }
217 
218     if (!info[0]->IsObject()) {
219         LOGE("arg is not Object or String.");
220         return;
221     }
222 
223     JSRef<JSObject> sizeObj = JSRef<JSObject>::Cast(info[0]);
224     JsWidth(sizeObj->GetProperty("width"));
225     JsHeight(sizeObj->GetProperty("height"));
226 }
227 
OnChange(const JSCallbackInfo & args)228 void JSToggle::OnChange(const JSCallbackInfo& args)
229 {
230     if (args.Length() < 1 || !args[0]->IsFunction()) {
231         LOGE("The arg is wrong, it is supposed to have atleast 1 argument.");
232         return;
233     }
234     auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(args[0]));
235     auto onChange = [execCtx = args.GetExecutionContext(), func = std::move(jsFunc)](bool isOn) {
236         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
237         ACE_SCORING_EVENT("Toggle.onChange");
238         auto newJSVal = JSRef<JSVal>::Make(ToJSValue(isOn));
239         func->ExecuteJS(1, &newJSVal);
240     };
241     ToggleModel::GetInstance()->OnChange(std::move(onChange));
242     args.ReturnSelf();
243 }
244 
SelectedColor(const JSCallbackInfo & info)245 void JSToggle::SelectedColor(const JSCallbackInfo& info)
246 {
247     if (info.Length() < 1) {
248         LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
249         return;
250     }
251     Color color;
252     std::optional<Color> selectedColor;
253     if (ParseJsColor(info[0], color)) {
254         selectedColor = color;
255     }
256 
257     ToggleModel::GetInstance()->SetSelectedColor(selectedColor);
258 }
259 
SwitchPointColor(const JSCallbackInfo & info)260 void JSToggle::SwitchPointColor(const JSCallbackInfo& info)
261 {
262     if (info.Length() < 1) {
263         LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
264         return;
265     }
266     Color color;
267     if (!ParseJsColor(info[0], color)) {
268         auto theme = GetTheme<SwitchTheme>();
269         if (theme) {
270             color = theme->GetPointColor();
271         }
272     }
273 
274     ToggleModel::GetInstance()->SetSwitchPointColor(color);
275 }
276 
JsPadding(const JSCallbackInfo & info)277 void JSToggle::JsPadding(const JSCallbackInfo& info)
278 {
279     if (info.Length() < 1) {
280         LOGE("The arg is wrong, it is supposed to have atleast 1 arguments");
281         return;
282     }
283     NG::PaddingPropertyF oldPadding = GetOldPadding(info);
284     NG::PaddingProperty newPadding = GetNewPadding(info);
285     ToggleModel::GetInstance()->SetPadding(oldPadding, newPadding);
286 }
287 
GetOldPadding(const JSCallbackInfo & info)288 NG::PaddingPropertyF JSToggle::GetOldPadding(const JSCallbackInfo& info)
289 {
290     NG::PaddingPropertyF padding({ 0.0f, 0.0f, 0.0f, 0.0f });
291     if (info[0]->IsObject()) {
292         auto argsPtrItem = JsonUtil::ParseJsonString(info[0]->ToString());
293         if (!argsPtrItem || argsPtrItem->IsNull()) {
294             LOGE("Js Parse object failed. argsPtr is null. %s", info[0]->ToString().c_str());
295             return padding;
296         }
297         if (argsPtrItem->Contains("top") || argsPtrItem->Contains("bottom") || argsPtrItem->Contains("left") ||
298             argsPtrItem->Contains("right")) {
299             CalcDimension topDimen = CalcDimension(0.0, DimensionUnit::VP);
300             CalcDimension leftDimen = CalcDimension(0.0, DimensionUnit::VP);
301             CalcDimension rightDimen = CalcDimension(0.0, DimensionUnit::VP);
302             CalcDimension bottomDimen = CalcDimension(0.0, DimensionUnit::VP);
303             ParseJsonDimensionVp(argsPtrItem->GetValue("top"), topDimen);
304             ParseJsonDimensionVp(argsPtrItem->GetValue("left"), leftDimen);
305             ParseJsonDimensionVp(argsPtrItem->GetValue("right"), rightDimen);
306             ParseJsonDimensionVp(argsPtrItem->GetValue("bottom"), bottomDimen);
307             if (leftDimen == 0.0_vp) {
308                 leftDimen = rightDimen;
309             }
310             if (topDimen == 0.0_vp) {
311                 topDimen = bottomDimen;
312             }
313             if (leftDimen == 0.0_vp) {
314                 leftDimen = topDimen;
315             }
316 
317             padding.left = leftDimen.ConvertToPx();
318             padding.right = rightDimen.ConvertToPx();
319             padding.top = topDimen.ConvertToPx();
320             padding.bottom = bottomDimen.ConvertToPx();
321             return padding;
322         }
323     }
324 
325     CalcDimension length;
326     if (!ParseJsDimensionVp(info[0], length)) {
327         return padding;
328     }
329 
330     padding.left = length.ConvertToPx();
331     padding.right = length.ConvertToPx();
332     padding.top = length.ConvertToPx();
333     padding.bottom = length.ConvertToPx();
334     return padding;
335 }
336 
GetNewPadding(const JSCallbackInfo & info)337 NG::PaddingProperty JSToggle::GetNewPadding(const JSCallbackInfo& info)
338 {
339     NG::PaddingProperty padding(
340         { NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp) });
341     if (info[0]->IsObject()) {
342         std::optional<CalcDimension> left;
343         std::optional<CalcDimension> right;
344         std::optional<CalcDimension> top;
345         std::optional<CalcDimension> bottom;
346         JSRef<JSObject> paddingObj = JSRef<JSObject>::Cast(info[0]);
347 
348         CalcDimension leftDimen;
349         if (ParseJsDimensionVp(paddingObj->GetProperty("left"), leftDimen)) {
350             left = leftDimen;
351         }
352         CalcDimension rightDimen;
353         if (ParseJsDimensionVp(paddingObj->GetProperty("right"), rightDimen)) {
354             right = rightDimen;
355         }
356         CalcDimension topDimen;
357         if (ParseJsDimensionVp(paddingObj->GetProperty("top"), topDimen)) {
358             top = topDimen;
359         }
360         CalcDimension bottomDimen;
361         if (ParseJsDimensionVp(paddingObj->GetProperty("bottom"), bottomDimen)) {
362             bottom = bottomDimen;
363         }
364         if (left.has_value() || right.has_value() || top.has_value() || bottom.has_value()) {
365             padding = GetPadding(top, bottom, left, right);
366             return padding;
367         }
368     }
369     CalcDimension length;
370     if (!ParseJsDimensionVp(info[0], length)) {
371         length.Reset();
372     }
373 
374     padding.SetEdges(NG::CalcLength(length.IsNonNegative() ? length : CalcDimension()));
375     return padding;
376 }
377 
GetPadding(const std::optional<CalcDimension> & top,const std::optional<CalcDimension> & bottom,const std::optional<CalcDimension> & left,const std::optional<CalcDimension> & right)378 NG::PaddingProperty JSToggle::GetPadding(const std::optional<CalcDimension>& top,
379     const std::optional<CalcDimension>& bottom, const std::optional<CalcDimension>& left,
380     const std::optional<CalcDimension>& right)
381 {
382     NG::PaddingProperty padding(
383         { NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp), NG::CalcLength(0.0_vp) });
384     if (left.has_value() && left.value().IsNonNegative()) {
385         padding.left = NG::CalcLength(left.value());
386     }
387     if (right.has_value() && right.value().IsNonNegative()) {
388         padding.right = NG::CalcLength(right.value());
389     }
390     if (top.has_value() && top.value().IsNonNegative()) {
391         padding.top = NG::CalcLength(top.value());
392     }
393     if (bottom.has_value() && bottom.value().IsNonNegative()) {
394         padding.bottom = NG::CalcLength(bottom.value());
395     }
396     return padding;
397 }
398 
SetBackgroundColor(const JSCallbackInfo & info)399 void JSToggle::SetBackgroundColor(const JSCallbackInfo& info)
400 {
401     if (info.Length() < 1) {
402         LOGE("The argv is wrong, it is supposed to have at least 1 argument");
403         return;
404     }
405     Color backgroundColor;
406     if (!ParseJsColor(info[0], backgroundColor)) {
407         return;
408     }
409 
410     if (!Container::IsCurrentUseNewPipeline()) {
411         JSViewAbstract::JsBackgroundColor(info);
412         return;
413     }
414     ToggleModel::GetInstance()->SetBackgroundColor(backgroundColor);
415 }
416 
417 } // namespace OHOS::Ace::Framework
418