• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 "frameworks/bridge/declarative_frontend/jsview/js_indicator.h"
17 
18 #include "bridge/declarative_frontend/engine/jsi/js_ui_index.h"
19 #include "core/components/swiper/swiper_indicator_theme.h"
20 #include "core/components_ng/base/view_stack_processor.h"
21 #include "core/components_ng/pattern/swiper_indicator/indicator_common/indicator_model.h"
22 #include "core/components_ng/pattern/swiper_indicator/indicator_common/indicator_model_ng.h"
23 
24 namespace OHOS::Ace {
25 namespace {
26 constexpr int32_t DEFAULT_INDICATOR_COUNT = 2;
27 } // namespace
28 std::unique_ptr<IndicatorModel> IndicatorModel::instance_ = nullptr;
29 std::mutex IndicatorModel::mutex_;
30 
GetInstance()31 IndicatorModel* IndicatorModel::GetInstance()
32 {
33     if (!instance_) {
34         std::lock_guard<std::mutex> lock(mutex_);
35         if (!instance_) {
36             instance_.reset(new NG::IndicatorModelNG());
37         }
38     }
39     return instance_.get();
40 }
41 
42 } // namespace OHOS::Ace
43 namespace OHOS::Ace::Framework {
44 namespace {
SwiperChangeEventToJSValue(const SwiperChangeEvent & eventInfo)45 JSRef<JSVal> SwiperChangeEventToJSValue(const SwiperChangeEvent& eventInfo)
46 {
47     return JSRef<JSVal>::Make(ToJSValue(eventInfo.GetIndex()));
48 }
49 
50 } // namespace
51 
Create(const JSCallbackInfo & info)52 void JSIndicator::Create(const JSCallbackInfo& info)
53 {
54     auto indicatorController = IndicatorModel::GetInstance()->Create();
55     if (info[0]->IsObject()) {
56         auto* jsController = JSRef<JSObject>::Cast(info[0])->Unwrap<JSIndicatorController>();
57         if (jsController) {
58             jsController->SetInstanceId(Container::CurrentId());
59             WeakPtr<NG::UINode> indicatorNode =
60                 AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
61             jsController->SetController(indicatorController, indicatorNode);
62         }
63     }
64 }
65 
JSBind(BindingTarget globalObj)66 void JSIndicator::JSBind(BindingTarget globalObj)
67 {
68     JSClass<JSIndicator>::Declare("IndicatorComponent");
69     MethodOptions opt = MethodOptions::NONE;
70     JSClass<JSIndicator>::StaticMethod("create", &JSIndicator::Create, opt);
71     JSClass<JSIndicator>::StaticMethod("count", &JSIndicator::SetCount, opt);
72     JSClass<JSIndicator>::StaticMethod("loop", &JSIndicator::SetLoop, opt);
73     JSClass<JSIndicator>::StaticMethod("vertical", &JSIndicator::SetVertical, opt);
74     JSClass<JSIndicator>::StaticMethod("style", &JSIndicator::SetStyle, opt);
75     JSClass<JSIndicator>::StaticMethod("initialIndex", &JSIndicator::SetInitialIndex, opt);
76     JSClass<JSIndicator>::StaticMethod("onChange", &JSIndicator::SetOnChange);
77     JSClass<JSIndicator>::InheritAndBind<JSViewAbstract>(globalObj);
78 }
79 
SetCount(const JSCallbackInfo & info)80 void JSIndicator::SetCount(const JSCallbackInfo& info)
81 {
82     if (!info[0]->IsNumber()) {
83         IndicatorModel::GetInstance()->SetCount(DEFAULT_INDICATOR_COUNT);
84         return;
85     }
86 
87     auto count = std::max(DEFAULT_INDICATOR_COUNT, info[0]->ToNumber<int32_t>());
88     IndicatorModel::GetInstance()->SetCount(count);
89 }
90 
SetLoop(const JSCallbackInfo & info)91 void JSIndicator::SetLoop(const JSCallbackInfo& info)
92 {
93     if (!info[0]->IsBoolean()) {
94         IndicatorModel::GetInstance()->SetLoop(true);
95         return;
96     }
97 
98     IndicatorModel::GetInstance()->SetLoop(info[0]->ToBoolean());
99 }
100 
SetVertical(const JSCallbackInfo & info)101 void JSIndicator::SetVertical(const JSCallbackInfo& info)
102 {
103     if (!info[0]->IsBoolean()) {
104         IndicatorModel::GetInstance()->SetDirection(Axis::HORIZONTAL);
105         return;
106     }
107 
108     IndicatorModel::GetInstance()->SetDirection(info[0]->ToBoolean() ? Axis::VERTICAL : Axis::HORIZONTAL);
109 }
110 
GetFontContent(const JSRef<JSVal> & font,bool isSelected,SwiperDigitalParameters & digitalParameters)111 void JSIndicator::GetFontContent(const JSRef<JSVal>& font, bool isSelected, SwiperDigitalParameters& digitalParameters)
112 {
113     JSRef<JSVal> size;
114     JSRef<JSVal> weight;
115     if (font->IsObject()) {
116         JSRef<JSObject> obj = JSRef<JSObject>::Cast(font);
117         size = obj->GetProperty("size");
118         weight = obj->GetProperty("weight");
119     }
120 
121     auto pipelineContext = PipelineBase::GetCurrentContext();
122     CHECK_NULL_VOID(pipelineContext);
123     auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
124     CHECK_NULL_VOID(swiperIndicatorTheme);
125     // set font size, unit FP
126     CalcDimension fontSize;
127     if (!size->IsUndefined() && !size->IsNull() && ParseJsDimensionFpNG(size, fontSize)) {
128         if (LessOrEqual(fontSize.Value(), 0.0) || LessOrEqual(size->ToNumber<double>(), 0.0) ||
129             fontSize.Unit() == DimensionUnit::PERCENT) {
130             fontSize = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontSize();
131         }
132     } else {
133         fontSize = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontSize();
134     }
135     if (isSelected) {
136         digitalParameters.selectedFontSize = fontSize;
137     } else {
138         digitalParameters.fontSize = fontSize;
139     }
140 
141     if (!weight->IsNull()) {
142         std::string weightValue;
143         if (weight->IsNumber()) {
144             weightValue = std::to_string(weight->ToNumber<int32_t>());
145         } else {
146             ParseJsString(weight, weightValue);
147         }
148         if (isSelected) {
149             digitalParameters.selectedFontWeight = ConvertStrToFontWeight(weightValue);
150         } else {
151             digitalParameters.fontWeight = ConvertStrToFontWeight(weightValue);
152         }
153     } else {
154         if (isSelected) {
155             digitalParameters.selectedFontWeight = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontWeight();
156         } else {
157             digitalParameters.fontWeight = swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetFontWeight();
158         }
159     }
160 }
161 
ParseIndicatorDimension(const JSRef<JSVal> & value)162 std::optional<Dimension> JSIndicator::ParseIndicatorDimension(const JSRef<JSVal>& value)
163 {
164     std::optional<Dimension> indicatorDimension;
165     if (value->IsUndefined()) {
166         return indicatorDimension;
167     }
168     CalcDimension dimPosition;
169     auto parseOk = ParseJsDimensionVpNG(value, dimPosition);
170     indicatorDimension = parseOk && dimPosition.ConvertToPx() >= 0.0f ? dimPosition : 0.0_vp;
171     return indicatorDimension;
172 }
173 
GetDotIndicatorInfo(const JSRef<JSObject> & obj)174 SwiperParameters JSIndicator::GetDotIndicatorInfo(const JSRef<JSObject>& obj)
175 {
176     JSRef<JSVal> leftValue = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::LEFT_VALUE));
177     JSRef<JSVal> topValue = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::TOP_VALUE));
178     JSRef<JSVal> rightValue = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::RIGHT_VALUE));
179     JSRef<JSVal> bottomValue = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::BOTTOM_VALUE));
180     JSRef<JSVal> startValue = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::START_VALUE));
181     JSRef<JSVal> endValue = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::END_VALUE));
182     JSRef<JSVal> itemWidthValue = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::ITEM_WIDTH_VALUE));
183     JSRef<JSVal> itemHeightValue = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::ITEM_HEIGHT_VALUE));
184     JSRef<JSVal> selectedItemWidthValue = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::SELECTED_ITEM_WIDTH_VALUE));
185     JSRef<JSVal> selectedItemHeightValue =
186         obj->GetProperty(static_cast<int32_t>(ArkUIIndex::SELECTED_ITEM_HEIGHT_VALUE));
187     auto pipelineContext = PipelineBase::GetCurrentContext();
188     CHECK_NULL_RETURN(pipelineContext, SwiperParameters());
189     auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
190     CHECK_NULL_RETURN(swiperIndicatorTheme, SwiperParameters());
191     SwiperParameters swiperParameters;
192     swiperParameters.dimLeft = ParseIndicatorDimension(leftValue);
193     swiperParameters.dimTop = ParseIndicatorDimension(topValue);
194     swiperParameters.dimRight = ParseIndicatorDimension(rightValue);
195     swiperParameters.dimBottom = ParseIndicatorDimension(bottomValue);
196     CalcDimension dimStart;
197     CalcDimension dimEnd;
198     std::optional<Dimension> indicatorDimension;
199     swiperParameters.dimStart = ParseLengthMetricsToDimension(startValue, dimStart) ? dimStart : indicatorDimension;
200     swiperParameters.dimEnd = ParseLengthMetricsToDimension(endValue, dimEnd) ? dimEnd : indicatorDimension;
201 
202     CalcDimension dimPosition;
203     bool parseItemWOk =
204         ParseJsDimensionVpNG(itemWidthValue, dimPosition) && (dimPosition.Unit() != DimensionUnit::PERCENT);
205     auto defaultSize = swiperIndicatorTheme->GetSize();
206     swiperParameters.itemWidth = parseItemWOk && dimPosition > 0.0_vp ? dimPosition : defaultSize;
207     bool parseItemHOk =
208         ParseJsDimensionVpNG(itemHeightValue, dimPosition) && (dimPosition.Unit() != DimensionUnit::PERCENT);
209     swiperParameters.itemHeight = parseItemHOk && dimPosition > 0.0_vp ? dimPosition : defaultSize;
210     bool parseSelectedItemWOk =
211         ParseJsDimensionVpNG(selectedItemWidthValue, dimPosition) && (dimPosition.Unit() != DimensionUnit::PERCENT);
212     swiperParameters.selectedItemWidth = parseSelectedItemWOk && dimPosition > 0.0_vp ? dimPosition : defaultSize;
213     bool parseSelectedItemHOk =
214         ParseJsDimensionVpNG(selectedItemHeightValue, dimPosition) && (dimPosition.Unit() != DimensionUnit::PERCENT);
215     swiperParameters.selectedItemHeight = parseSelectedItemHOk && dimPosition > 0.0_vp ? dimPosition : defaultSize;
216     IndicatorModel::GetInstance()->SetIsIndicatorCustomSize(
217         parseSelectedItemWOk || parseSelectedItemHOk || parseItemWOk || parseItemHOk);
218     SetDotIndicatorInfo(obj, swiperParameters, swiperIndicatorTheme);
219     return swiperParameters;
220 }
SetDotIndicatorInfo(const JSRef<JSObject> & obj,SwiperParameters & swiperParameters,const RefPtr<SwiperIndicatorTheme> & swiperIndicatorTheme)221 void JSIndicator::SetDotIndicatorInfo(const JSRef<JSObject>& obj, SwiperParameters& swiperParameters,
222     const RefPtr<SwiperIndicatorTheme>& swiperIndicatorTheme)
223 {
224     JSRef<JSVal> maskValue = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::MASK_VALUE));
225     JSRef<JSVal> colorValue = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::COLOR_VALUE));
226     JSRef<JSVal> selectedColorValue = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::SELECTED_COLOR_VALUE));
227     JSRef<JSVal> maxDisplayCountVal = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::MAX_DISPLAY_COUNT_VALUE));
228     if (maskValue->IsBoolean()) {
229         auto mask = maskValue->ToBoolean();
230         swiperParameters.maskValue = mask;
231     }
232     Color colorVal;
233     auto parseOk = ParseJsColor(colorValue, colorVal);
234     swiperParameters.colorVal = parseOk ? colorVal : swiperIndicatorTheme->GetColor();
235     parseOk = ParseJsColor(selectedColorValue, colorVal);
236     swiperParameters.selectedColorVal = parseOk ? colorVal : swiperIndicatorTheme->GetSelectedColor();
237     if (maxDisplayCountVal->IsUndefined()) {
238         return;
239     }
240     uint32_t result = 0;
241     auto setMaxDisplayCountVal = ParseJsInteger(maxDisplayCountVal, result);
242     swiperParameters.maxDisplayCountVal = setMaxDisplayCountVal && result > 0 ? result : 0;
243 }
244 
GetDigitIndicatorInfo(const JSRef<JSObject> & obj)245 SwiperDigitalParameters JSIndicator::GetDigitIndicatorInfo(const JSRef<JSObject>& obj)
246 {
247     JSRef<JSVal> dotLeftValue = obj->GetProperty("leftValue");
248     JSRef<JSVal> dotTopValue = obj->GetProperty("topValue");
249     JSRef<JSVal> dotRightValue = obj->GetProperty("rightValue");
250     JSRef<JSVal> dotBottomValue = obj->GetProperty("bottomValue");
251     JSRef<JSVal> fontColorValue = obj->GetProperty("fontColorValue");
252     JSRef<JSVal> selectedFontColorValue = obj->GetProperty("selectedFontColorValue");
253     JSRef<JSVal> digitFontValue = obj->GetProperty("digitFontValue");
254     JSRef<JSVal> selectedDigitFontValue = obj->GetProperty("selectedDigitFontValue");
255     auto pipelineContext = PipelineBase::GetCurrentContext();
256     CHECK_NULL_RETURN(pipelineContext, SwiperDigitalParameters());
257     auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
258     CHECK_NULL_RETURN(swiperIndicatorTheme, SwiperDigitalParameters());
259     SwiperDigitalParameters digitalParameters;
260     digitalParameters.dimLeft = ParseIndicatorDimension(dotLeftValue);
261     digitalParameters.dimTop = ParseIndicatorDimension(dotTopValue);
262     digitalParameters.dimRight = ParseIndicatorDimension(dotRightValue);
263     digitalParameters.dimBottom = ParseIndicatorDimension(dotBottomValue);
264     Color fontColor;
265     auto parseOk = JSViewAbstract::ParseJsColor(fontColorValue, fontColor);
266     digitalParameters.fontColor =
267         parseOk ? fontColor : swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetTextColor();
268     parseOk = JSViewAbstract::ParseJsColor(selectedFontColorValue, fontColor);
269     digitalParameters.selectedFontColor =
270         parseOk ? fontColor : swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetTextColor();
271     if (!digitFontValue->IsNull() && digitFontValue->IsObject()) {
272         GetFontContent(digitFontValue, false, digitalParameters);
273     }
274     if (!selectedDigitFontValue->IsNull() && selectedDigitFontValue->IsObject()) {
275         GetFontContent(selectedDigitFontValue, true, digitalParameters);
276     }
277     return digitalParameters;
278 }
279 
SetStyle(const JSCallbackInfo & info)280 void JSIndicator::SetStyle(const JSCallbackInfo& info)
281 {
282     if (info[0]->IsObject()) {
283         auto obj = JSRef<JSObject>::Cast(info[0]);
284 
285         JSRef<JSVal> typeParam = obj->GetProperty("type");
286         if (typeParam->IsString()) {
287             auto type = typeParam->ToString();
288             if (type == "DigitIndicator") {
289                 SwiperDigitalParameters digitalParameters = GetDigitIndicatorInfo(obj);
290                 IndicatorModel::GetInstance()->SetDigitIndicatorStyle(digitalParameters);
291                 IndicatorModel::GetInstance()->SetIndicatorType(SwiperIndicatorType::DIGIT);
292             } else {
293                 SwiperParameters swiperParameters = GetDotIndicatorInfo(obj);
294                 IndicatorModel::GetInstance()->SetDotIndicatorStyle(swiperParameters);
295                 IndicatorModel::GetInstance()->SetIndicatorType(SwiperIndicatorType::DOT);
296             }
297         } else {
298             SwiperParameters swiperParameters = GetDotIndicatorInfo(obj);
299             IndicatorModel::GetInstance()->SetDotIndicatorStyle(swiperParameters);
300             IndicatorModel::GetInstance()->SetIndicatorType(SwiperIndicatorType::DOT);
301         }
302     } else {
303         SwiperParameters swiperParameters = GetDotIndicatorInfo(JSRef<JSObject>::New());
304         IndicatorModel::GetInstance()->SetDotIndicatorStyle(swiperParameters);
305         IndicatorModel::GetInstance()->SetIndicatorType(SwiperIndicatorType::DOT);
306     }
307 }
308 
SetOnChange(const JSCallbackInfo & info)309 void JSIndicator::SetOnChange(const JSCallbackInfo& info)
310 {
311     if (!info[0]->IsFunction()) {
312         return;
313     }
314     auto changeHandler = AceType::MakeRefPtr<JsEventFunction<SwiperChangeEvent, 1>>(
315         JSRef<JSFunc>::Cast(info[0]), SwiperChangeEventToJSValue);
316     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
317     auto onChange = [executionContext = info.GetExecutionContext(), func = std::move(changeHandler), node = targetNode](
318                         const BaseEventInfo* info) {
319         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
320         const auto* swiperInfo = TypeInfoHelper::DynamicCast<SwiperChangeEvent>(info);
321         if (!swiperInfo) {
322             return;
323         }
324         PipelineContext::SetCallBackNode(node);
325         func->Execute(*swiperInfo);
326     };
327 
328     IndicatorModel::GetInstance()->SetOnChange(std::move(onChange));
329 }
330 
SetInitialIndex(const JSCallbackInfo & info)331 void JSIndicator::SetInitialIndex(const JSCallbackInfo& info)
332 {
333     if (!info[0]->IsNumber()) {
334         IndicatorModel::GetInstance()->SetInitialIndex(0);
335         return;
336     }
337 
338     auto index = std::max(0, info[0]->ToNumber<int32_t>());
339     IndicatorModel::GetInstance()->SetInitialIndex(index);
340 }
341 
JSBind(BindingTarget globalObj)342 void JSIndicatorController::JSBind(BindingTarget globalObj)
343 {
344     JSClass<JSIndicatorController>::Declare("IndicatorComponentController");
345     JSClass<JSIndicatorController>::CustomMethod("showNext", &JSIndicatorController::ShowNext);
346     JSClass<JSIndicatorController>::CustomMethod("showPrevious", &JSIndicatorController::ShowPrevious);
347     JSClass<JSIndicatorController>::CustomMethod("changeIndex", &JSIndicatorController::ChangeIndex);
348 
349     JSClass<JSIndicatorController>::Bind(
350         globalObj, JSIndicatorController::Constructor, JSIndicatorController::Destructor);
351 }
352 
Constructor(const JSCallbackInfo & args)353 void JSIndicatorController::Constructor(const JSCallbackInfo& args)
354 {
355     auto scroller = Referenced::MakeRefPtr<JSIndicatorController>();
356     scroller->IncRefCount();
357     args.SetReturnValue(Referenced::RawPtr(scroller));
358 }
359 
Destructor(JSIndicatorController * scroller)360 void JSIndicatorController::Destructor(JSIndicatorController* scroller)
361 {
362     if (scroller != nullptr) {
363         scroller->DecRefCount();
364     }
365 }
366 
ChangeIndex(const JSCallbackInfo & args)367 void JSIndicatorController::ChangeIndex(const JSCallbackInfo& args)
368 {
369     if (!controller_) {
370         return;
371     }
372     if (!args[0]->IsNumber()) {
373         return;
374     }
375     bool useAnimation = false;
376     if (args.Length() > 1 && args[1]->IsBoolean()) {
377         useAnimation = args[1]->ToBoolean();
378     }
379     auto index = args[0]->ToNumber<int32_t>();
380     controller_->ChangeIndex(index, useAnimation);
381 }
382 
383 } // namespace OHOS::Ace::Framework
384