• 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 "bridge/declarative_frontend/jsview/js_tabs_controller.h"
17 
18 #include "base/log/event_report.h"
19 #include "bridge/common/utils/engine_helper.h"
20 #include "bridge/declarative_frontend/engine/bindings.h"
21 #include "bridge/declarative_frontend/engine/js_converter.h"
22 #include "bridge/declarative_frontend/engine/jsi/js_ui_index.h"
23 #include "bridge/declarative_frontend/jsview/js_utils.h"
24 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
25 
26 namespace OHOS::Ace::Framework {
27 namespace {
28 
29 #ifndef NG_BUILD
30 // dismiss unused warning in NG_BUILD
31 int32_t g_tabControllerId = 0;
32 #endif
33 
34 struct TabsControllerAsyncContext {
35     napi_env env = nullptr;
36     napi_deferred deferred = nullptr;
37 };
38 
CreateErrorValue(napi_env env,int32_t errCode,const std::string & errMsg="")39 napi_value CreateErrorValue(napi_env env, int32_t errCode, const std::string& errMsg = "")
40 {
41     napi_value code = nullptr;
42     std::string codeStr = std::to_string(errCode);
43     napi_create_string_utf8(env, codeStr.c_str(), codeStr.length(), &code);
44     napi_value msg = nullptr;
45     napi_create_string_utf8(env, errMsg.c_str(), errMsg.length(), &msg);
46     napi_value error = nullptr;
47     napi_create_error(env, code, msg, &error);
48     return error;
49 }
50 
HandleDeferred(const shared_ptr<TabsControllerAsyncContext> & asyncContext,int32_t errorCode,std::string message)51 void HandleDeferred(const shared_ptr<TabsControllerAsyncContext>& asyncContext, int32_t errorCode, std::string message)
52 {
53     auto env = asyncContext->env;
54     CHECK_NULL_VOID(env);
55     auto deferred = asyncContext->deferred;
56     CHECK_NULL_VOID(deferred);
57 
58     napi_handle_scope scope = nullptr;
59     auto status = napi_open_handle_scope(env, &scope);
60     if (status != napi_ok) {
61         return;
62     }
63 
64     napi_value result = nullptr;
65     if (errorCode == ERROR_CODE_NO_ERROR) {
66         napi_get_null(env, &result);
67         napi_resolve_deferred(env, deferred, result);
68     } else {
69         result = CreateErrorValue(env, errorCode, message);
70         napi_reject_deferred(env, deferred, result);
71     }
72     napi_close_handle_scope(env, scope);
73 }
74 
ReturnPromise(const JSCallbackInfo & info,napi_value result)75 void ReturnPromise(const JSCallbackInfo& info, napi_value result)
76 {
77     CHECK_NULL_VOID(result);
78     auto jsPromise = JsConverter::ConvertNapiValueToJsVal(result);
79     if (!jsPromise->IsObject()) {
80         return;
81     }
82     info.SetReturnValue(JSRef<JSObject>::Cast(jsPromise));
83 }
84 } // namespace
85 
JSTabsController()86 JSTabsController::JSTabsController()
87 {
88     controller_ = CreateController();
89 }
90 
JSBind(BindingTarget globalObj)91 void JSTabsController::JSBind(BindingTarget globalObj)
92 {
93     JSClass<JSTabsController>::Declare("TabsController");
94     JSClass<JSTabsController>::Method("changeIndex", &JSTabsController::ChangeIndex);
95     JSClass<JSTabsController>::CustomMethod("preloadItems", &JSTabsController::PreloadItems);
96     JSClass<JSTabsController>::CustomMethod("setTabBarTranslate", &JSTabsController::SetTabBarTranslate);
97     JSClass<JSTabsController>::CustomMethod("setTabBarOpacity", &JSTabsController::SetTabBarOpacity);
98     JSClass<JSTabsController>::Bind(globalObj, JSTabsController::Constructor, JSTabsController::Destructor);
99 }
100 
Constructor(const JSCallbackInfo & args)101 void JSTabsController::Constructor(const JSCallbackInfo& args)
102 {
103     auto jsCalendarController = Referenced::MakeRefPtr<JSTabsController>();
104     jsCalendarController->IncRefCount();
105     args.SetReturnValue(Referenced::RawPtr(jsCalendarController));
106 }
107 
Destructor(JSTabsController * controller)108 void JSTabsController::Destructor(JSTabsController* controller)
109 {
110     if (controller != nullptr) {
111         controller->DecRefCount();
112     }
113 }
114 
CreateController()115 RefPtr<TabController> JSTabsController::CreateController()
116 {
117 #ifdef NG_BUILD
118     return nullptr;
119 #else
120     return TabController::GetController(++g_tabControllerId);
121 #endif
122 }
123 
ChangeIndex(int32_t index)124 void JSTabsController::ChangeIndex(int32_t index)
125 {
126     ContainerScope scope(instanceId_);
127     auto tabsController = tabsControllerWeak_.Upgrade();
128     if (tabsController) {
129         const auto& updateCubicCurveCallback = tabsController->GetUpdateCubicCurveCallback();
130         if (updateCubicCurveCallback != nullptr) {
131             updateCubicCurveCallback();
132         }
133         TAG_LOGI(AceLogTag::ACE_TABS, "changeIndex %{public}d", index);
134         tabsController->SwipeTo(index);
135     } else {
136         EventReport::ReportScrollableErrorEvent(
137             "Tabs", ScrollableErrorType::CONTROLLER_NOT_BIND, "changeIndex: Tabs controller not bind.");
138     }
139 
140 #ifndef NG_BUILD
141     if (controller_) {
142         controller_->SetIndexByController(index, false);
143     }
144 #endif
145 }
146 
PreloadItems(const JSCallbackInfo & args)147 void JSTabsController::PreloadItems(const JSCallbackInfo& args)
148 {
149     ContainerScope scope(instanceId_);
150     auto engine = EngineHelper::GetCurrentEngine();
151     CHECK_NULL_VOID(engine);
152     NativeEngine* nativeEngine = engine->GetNativeEngine();
153     auto env = reinterpret_cast<napi_env>(nativeEngine);
154     auto asyncContext = std::make_shared<TabsControllerAsyncContext>();
155     asyncContext->env = env;
156     napi_value promise = nullptr;
157     napi_create_promise(env, &asyncContext->deferred, &promise);
158     auto tabsController = tabsControllerWeak_.Upgrade();
159     if (!tabsController) {
160         EventReport::ReportScrollableErrorEvent(
161             "Tabs", ScrollableErrorType::CONTROLLER_NOT_BIND, "preloadItems: Tabs controller not bind.");
162         ReturnPromise(args, promise);
163         return;
164     }
165 
166     ScopeRAII scopeRaii(env);
167     std::set<int32_t> indexSet;
168     if (args.Length() > 0 && args[0]->IsArray()) {
169         auto indexArray = JSRef<JSArray>::Cast(args[0]);
170         size_t size = indexArray->Length();
171         for (size_t i = 0; i < size; i++) {
172             int32_t index = -1;
173             JSViewAbstract::ParseJsInt32(indexArray->GetValueAt(i), index);
174             indexSet.emplace(index);
175         }
176     }
177 
178     auto onPreloadFinish = [asyncContext](int32_t errorCode, std::string message) {
179         CHECK_NULL_VOID(asyncContext);
180         HandleDeferred(asyncContext, errorCode, message);
181     };
182     tabsController->SetPreloadFinishCallback(onPreloadFinish);
183     tabsController->PreloadItems(indexSet);
184     ReturnPromise(args, promise);
185 }
186 
SetTabBarTranslate(const JSCallbackInfo & args)187 void JSTabsController::SetTabBarTranslate(const JSCallbackInfo& args)
188 {
189     ContainerScope scope(instanceId_);
190     auto tabsController = tabsControllerWeak_.Upgrade();
191     if (!tabsController) {
192         EventReport::ReportScrollableErrorEvent(
193             "Tabs", ScrollableErrorType::CONTROLLER_NOT_BIND, "setTabBarTranslate: Tabs controller not bind.");
194         return;
195     }
196 
197     if (args.Length() <= 0) {
198         return;
199     }
200     auto translate = args[0];
201     if (translate->IsObject()) {
202         JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(translate);
203         if (jsObj->HasProperty(static_cast<int32_t>(ArkUIIndex::X)) ||
204             jsObj->HasProperty(static_cast<int32_t>(ArkUIIndex::Y)) ||
205             jsObj->HasProperty(static_cast<int32_t>(ArkUIIndex::Z))) {
206             CalcDimension translateX;
207             CalcDimension translateY;
208             CalcDimension translateZ;
209             JSViewAbstract::ParseJsDimensionVp(jsObj->GetProperty(static_cast<int32_t>(ArkUIIndex::X)), translateX);
210             JSViewAbstract::ParseJsDimensionVp(jsObj->GetProperty(static_cast<int32_t>(ArkUIIndex::Y)), translateY);
211             JSViewAbstract::ParseJsDimensionVp(jsObj->GetProperty(static_cast<int32_t>(ArkUIIndex::Z)), translateZ);
212             auto options = NG::TranslateOptions(translateX, translateY, translateZ);
213             tabsController->SetTabBarTranslate(options);
214             return;
215         }
216     }
217     CalcDimension value;
218     if (JSViewAbstract::ParseJsDimensionVp(translate, value)) {
219         auto options = NG::TranslateOptions(value, value, value);
220         tabsController->SetTabBarTranslate(options);
221     } else {
222         auto options = NG::TranslateOptions(0.0f, 0.0f, 0.0f);
223         tabsController->SetTabBarTranslate(options);
224     }
225 }
226 
SetTabBarOpacity(const JSCallbackInfo & args)227 void JSTabsController::SetTabBarOpacity(const JSCallbackInfo& args)
228 {
229     ContainerScope scope(instanceId_);
230     auto tabsController = tabsControllerWeak_.Upgrade();
231     if (!tabsController) {
232         EventReport::ReportScrollableErrorEvent(
233             "Tabs", ScrollableErrorType::CONTROLLER_NOT_BIND, "setTabBarOpacity: Tabs controller not bind.");
234         return;
235     }
236 
237     if (args.Length() <= 0) {
238         return;
239     }
240     double opacity = 0.0;
241     if (JSViewAbstract::ParseJsDouble(args[0], opacity)) {
242         opacity = std::clamp(opacity, 0.0, 1.0);
243         tabsController->SetTabBarOpacity(opacity);
244     } else {
245         tabsController->SetTabBarOpacity(1.0f);
246     }
247 }
248 
249 } // namespace OHOS::Ace::Framework
250