• 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     JSRef<JSVal> spaceValue = obj->GetProperty(static_cast<int32_t>(ArkUIIndex::SPACE_VALUE));
229     if (maskValue->IsBoolean()) {
230         auto mask = maskValue->ToBoolean();
231         swiperParameters.maskValue = mask;
232     }
233     Color colorVal;
234     auto parseOk = ParseJsColor(colorValue, colorVal);
235     swiperParameters.colorVal = parseOk ? colorVal : swiperIndicatorTheme->GetColor();
236     parseOk = ParseJsColor(selectedColorValue, colorVal);
237     swiperParameters.selectedColorVal = parseOk ? colorVal : swiperIndicatorTheme->GetSelectedColor();
238     auto defalutSpace = swiperIndicatorTheme->GetIndicatorDotItemSpace();
239     CalcDimension dimSpace;
240     auto parseSpaceOk = ParseLengthMetricsToDimension(spaceValue, dimSpace) &&
241         (dimSpace.Unit() != DimensionUnit::PERCENT);
242     swiperParameters.dimSpace =  (parseSpaceOk && !(dimSpace < 0.0_vp)) ? dimSpace : defalutSpace;
243     if (maxDisplayCountVal->IsUndefined()) {
244         return;
245     }
246     uint32_t result = 0;
247     auto setMaxDisplayCountVal = ParseJsInteger(maxDisplayCountVal, result);
248     swiperParameters.maxDisplayCountVal = setMaxDisplayCountVal && result > 0 ? result : 0;
249 }
250 
GetDigitIndicatorInfo(const JSRef<JSObject> & obj)251 SwiperDigitalParameters JSIndicator::GetDigitIndicatorInfo(const JSRef<JSObject>& obj)
252 {
253     JSRef<JSVal> dotLeftValue = obj->GetProperty("leftValue");
254     JSRef<JSVal> dotTopValue = obj->GetProperty("topValue");
255     JSRef<JSVal> dotRightValue = obj->GetProperty("rightValue");
256     JSRef<JSVal> dotBottomValue = obj->GetProperty("bottomValue");
257     JSRef<JSVal> fontColorValue = obj->GetProperty("fontColorValue");
258     JSRef<JSVal> selectedFontColorValue = obj->GetProperty("selectedFontColorValue");
259     JSRef<JSVal> digitFontValue = obj->GetProperty("digitFontValue");
260     JSRef<JSVal> selectedDigitFontValue = obj->GetProperty("selectedDigitFontValue");
261     auto pipelineContext = PipelineBase::GetCurrentContext();
262     CHECK_NULL_RETURN(pipelineContext, SwiperDigitalParameters());
263     auto swiperIndicatorTheme = pipelineContext->GetTheme<SwiperIndicatorTheme>();
264     CHECK_NULL_RETURN(swiperIndicatorTheme, SwiperDigitalParameters());
265     SwiperDigitalParameters digitalParameters;
266     digitalParameters.dimLeft = ParseIndicatorDimension(dotLeftValue);
267     digitalParameters.dimTop = ParseIndicatorDimension(dotTopValue);
268     digitalParameters.dimRight = ParseIndicatorDimension(dotRightValue);
269     digitalParameters.dimBottom = ParseIndicatorDimension(dotBottomValue);
270     Color fontColor;
271     auto parseOk = JSViewAbstract::ParseJsColor(fontColorValue, fontColor);
272     digitalParameters.fontColor =
273         parseOk ? fontColor : swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetTextColor();
274     parseOk = JSViewAbstract::ParseJsColor(selectedFontColorValue, fontColor);
275     digitalParameters.selectedFontColor =
276         parseOk ? fontColor : swiperIndicatorTheme->GetDigitalIndicatorTextStyle().GetTextColor();
277     if (!digitFontValue->IsNull() && digitFontValue->IsObject()) {
278         GetFontContent(digitFontValue, false, digitalParameters);
279     }
280     if (!selectedDigitFontValue->IsNull() && selectedDigitFontValue->IsObject()) {
281         GetFontContent(selectedDigitFontValue, true, digitalParameters);
282     }
283     return digitalParameters;
284 }
285 
SetStyle(const JSCallbackInfo & info)286 void JSIndicator::SetStyle(const JSCallbackInfo& info)
287 {
288     if (info[0]->IsObject()) {
289         auto obj = JSRef<JSObject>::Cast(info[0]);
290 
291         JSRef<JSVal> typeParam = obj->GetProperty("type");
292         if (typeParam->IsString()) {
293             auto type = typeParam->ToString();
294             if (type == "DigitIndicator") {
295                 SwiperDigitalParameters digitalParameters = GetDigitIndicatorInfo(obj);
296                 IndicatorModel::GetInstance()->SetDigitIndicatorStyle(digitalParameters);
297                 IndicatorModel::GetInstance()->SetIndicatorType(SwiperIndicatorType::DIGIT);
298             } else {
299                 SwiperParameters swiperParameters = GetDotIndicatorInfo(obj);
300                 IndicatorModel::GetInstance()->SetDotIndicatorStyle(swiperParameters);
301                 IndicatorModel::GetInstance()->SetIndicatorType(SwiperIndicatorType::DOT);
302             }
303         } else {
304             SwiperParameters swiperParameters = GetDotIndicatorInfo(obj);
305             IndicatorModel::GetInstance()->SetDotIndicatorStyle(swiperParameters);
306             IndicatorModel::GetInstance()->SetIndicatorType(SwiperIndicatorType::DOT);
307         }
308     } else {
309         SwiperParameters swiperParameters = GetDotIndicatorInfo(JSRef<JSObject>::New());
310         IndicatorModel::GetInstance()->SetDotIndicatorStyle(swiperParameters);
311         IndicatorModel::GetInstance()->SetIndicatorType(SwiperIndicatorType::DOT);
312     }
313 }
314 
SetOnChange(const JSCallbackInfo & info)315 void JSIndicator::SetOnChange(const JSCallbackInfo& info)
316 {
317     if (!info[0]->IsFunction()) {
318         return;
319     }
320     auto changeHandler = AceType::MakeRefPtr<JsEventFunction<SwiperChangeEvent, 1>>(
321         JSRef<JSFunc>::Cast(info[0]), SwiperChangeEventToJSValue);
322     WeakPtr<NG::FrameNode> targetNode = AceType::WeakClaim(NG::ViewStackProcessor::GetInstance()->GetMainFrameNode());
323     auto onChange = [executionContext = info.GetExecutionContext(), func = std::move(changeHandler), node = targetNode](
324                         const BaseEventInfo* info) {
325         JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(executionContext);
326         const auto* swiperInfo = TypeInfoHelper::DynamicCast<SwiperChangeEvent>(info);
327         if (!swiperInfo) {
328             return;
329         }
330         PipelineContext::SetCallBackNode(node);
331         func->Execute(*swiperInfo);
332     };
333 
334     IndicatorModel::GetInstance()->SetOnChange(std::move(onChange));
335 }
336 
SetInitialIndex(const JSCallbackInfo & info)337 void JSIndicator::SetInitialIndex(const JSCallbackInfo& info)
338 {
339     if (!info[0]->IsNumber()) {
340         IndicatorModel::GetInstance()->SetInitialIndex(0);
341         return;
342     }
343 
344     auto index = std::max(0, info[0]->ToNumber<int32_t>());
345     IndicatorModel::GetInstance()->SetInitialIndex(index);
346 }
347 
JSBind(BindingTarget globalObj)348 void JSIndicatorController::JSBind(BindingTarget globalObj)
349 {
350     JSClass<JSIndicatorController>::Declare("IndicatorComponentController");
351     JSClass<JSIndicatorController>::CustomMethod("showNext", &JSIndicatorController::ShowNext);
352     JSClass<JSIndicatorController>::CustomMethod("showPrevious", &JSIndicatorController::ShowPrevious);
353     JSClass<JSIndicatorController>::CustomMethod("changeIndex", &JSIndicatorController::ChangeIndex);
354 
355     JSClass<JSIndicatorController>::Bind(
356         globalObj, JSIndicatorController::Constructor, JSIndicatorController::Destructor);
357 }
358 
Constructor(const JSCallbackInfo & args)359 void JSIndicatorController::Constructor(const JSCallbackInfo& args)
360 {
361     auto scroller = Referenced::MakeRefPtr<JSIndicatorController>();
362     scroller->IncRefCount();
363     args.SetReturnValue(Referenced::RawPtr(scroller));
364 }
365 
Destructor(JSIndicatorController * scroller)366 void JSIndicatorController::Destructor(JSIndicatorController* scroller)
367 {
368     if (scroller != nullptr) {
369         scroller->DecRefCount();
370     }
371 }
372 
ChangeIndex(const JSCallbackInfo & args)373 void JSIndicatorController::ChangeIndex(const JSCallbackInfo& args)
374 {
375     if (!controller_) {
376         return;
377     }
378     if (!args[0]->IsNumber()) {
379         return;
380     }
381     bool useAnimation = false;
382     if (args.Length() > 1 && args[1]->IsBoolean()) {
383         useAnimation = args[1]->ToBoolean();
384     }
385     auto index = args[0]->ToNumber<int32_t>();
386     controller_->ChangeIndex(index, useAnimation);
387 }
388 
389 } // namespace OHOS::Ace::Framework
390