1 /*
2 * Copyright (c) 2021-2022 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_text_clock.h"
17
18 #include <regex>
19 #include <string>
20
21 #include "base/log/ace_scoring_log.h"
22 #include "bridge/declarative_frontend/jsview/js_text.h"
23 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
24 #include "bridge/declarative_frontend/jsview/js_view_common_def.h"
25 #include "bridge/declarative_frontend/jsview/models/text_clock_model_impl.h"
26 #include "core/components_ng/pattern/text_clock/text_clock_model.h"
27 #include "core/components_ng/pattern/text_clock/text_clock_model_ng.h"
28
29 namespace OHOS::Ace {
30
31 std::unique_ptr<TextClockModel> TextClockModel::instance_ = nullptr;
32
GetInstance()33 TextClockModel* TextClockModel::GetInstance()
34 {
35 if (!instance_) {
36 #ifdef NG_BUILD
37 instance_.reset(new NG::TextClockModelNG());
38 #else
39 if (Container::IsCurrentUseNewPipeline()) {
40 instance_.reset(new NG::TextClockModelNG());
41 } else {
42 instance_.reset(new Framework::TextClockModelImpl());
43 }
44 #endif
45 }
46 return instance_.get();
47 }
48 } // namespace OHOS::Ace
49
50 namespace OHOS::Ace::Framework {
51
52 namespace {
53 const std::vector<FontStyle> FONT_STYLES = { FontStyle::NORMAL, FontStyle::ITALIC };
54 const int32_t TWENTY_FOUR_HOUR_BASE = 24;
55 constexpr int32_t HOURS_WEST_LOWER_LIMIT = -14;
56 constexpr int32_t HOURS_WEST_UPPER_LIMIT = 12;
57 constexpr int32_t HOURS_WEST_GEOGRAPHICAL_LOWER_LIMIT = -12;
58
HoursWestIsValid(int32_t hoursWest)59 bool HoursWestIsValid(int32_t hoursWest)
60 {
61 if (hoursWest < HOURS_WEST_LOWER_LIMIT || hoursWest > HOURS_WEST_UPPER_LIMIT) {
62 return false;
63 }
64 if (hoursWest < HOURS_WEST_GEOGRAPHICAL_LOWER_LIMIT) {
65 hoursWest += TWENTY_FOUR_HOUR_BASE;
66 }
67 return true;
68 }
69 } // namespace
70
Create(const JSCallbackInfo & info)71 void JSTextClock::Create(const JSCallbackInfo& info)
72 {
73 auto controller = TextClockModel::GetInstance()->Create();
74 if (info.Length() < 1 || !info[0]->IsObject()) {
75 LOGD("TextClock Info is non-valid");
76 return;
77 }
78 JSRef<JSObject> optionsObject = JSRef<JSObject>::Cast(info[0]);
79 JSRef<JSVal> hourWestVal = optionsObject->GetProperty("timeZoneOffset");
80 if (hourWestVal->IsNumber() && HoursWestIsValid(hourWestVal->ToNumber<int32_t>())) {
81 TextClockModel::GetInstance()->SetHoursWest(hourWestVal->ToNumber<int32_t>());
82 } else {
83 TextClockModel::GetInstance()->SetHoursWest(INT_MAX);
84 LOGE("hourWest args is invalid");
85 }
86 auto controllerObj = optionsObject->GetProperty("controller");
87 if (!controllerObj->IsUndefined() && !controllerObj->IsNull()) {
88 auto* jsController = JSRef<JSObject>::Cast(controllerObj)->Unwrap<JSTextClockController>();
89 if (jsController != nullptr) {
90 if (controller) {
91 jsController->SetController(controller);
92 } else {
93 LOGE("TextClockController is nullptr");
94 }
95 }
96 return;
97 }
98 LOGE("controllerObj is nullptr or undefined");
99 }
100
JSBind(BindingTarget globalObj)101 void JSTextClock::JSBind(BindingTarget globalObj)
102 {
103 JSClass<JSTextClock>::Declare("TextClock");
104 MethodOptions opt = MethodOptions::NONE;
105 JSClass<JSTextClock>::StaticMethod("create", &JSTextClock::Create, opt);
106 JSClass<JSTextClock>::StaticMethod("format", &JSTextClock::SetFormat, opt);
107 JSClass<JSTextClock>::StaticMethod("onDateChange", &JSTextClock::JsOnDateChange, opt);
108 JSClass<JSTextClock>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
109 JSClass<JSTextClock>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
110 JSClass<JSTextClock>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
111 JSClass<JSTextClock>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
112 JSClass<JSTextClock>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
113 JSClass<JSTextClock>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
114 JSClass<JSTextClock>::StaticMethod("fontColor", &JSText::SetTextColor, opt);
115 JSClass<JSTextClock>::StaticMethod("fontSize", &JSText::SetFontSize, opt);
116 JSClass<JSTextClock>::StaticMethod("fontStyle", &JSText::SetFontStyle, opt);
117 JSClass<JSTextClock>::StaticMethod("fontWeight", &JSText::SetFontWeight, opt);
118 JSClass<JSTextClock>::StaticMethod("fontFamily", &JSText::SetFontFamily, opt);
119 JSClass<JSTextClock>::Inherit<JSViewAbstract>();
120 JSClass<JSTextClock>::Bind<>(globalObj);
121 }
122
SetFormat(const JSCallbackInfo & info)123 void JSTextClock::SetFormat(const JSCallbackInfo& info)
124 {
125 if (info.Length() < 1) {
126 LOGE("The arg is wrong, it is supposed to have atleast 1 argument.");
127 return;
128 }
129 std::string value;
130 if (!ParseJsString(info[0], value)) {
131 return;
132 }
133 std::regex pattern(
134 R"(^([Yy]*[_|\W\s]*[M]*[_|\W\s]*[d]*[_|\W\s]*[D]*[_|\W\s]*[Hh]*[_|\W\s]*[m]*[_|\W\s]*[s]*[_|\W\s]*[S]*)$)");
135 if (!std::regex_match(value, pattern)) {
136 LOGE("The arg is wrong, because of format matching error.");
137 TextClockModel::GetInstance()->SetFormat("hms");
138 return;
139 }
140 TextClockModel::GetInstance()->SetFormat(value);
141 }
142
JsOnDateChange(const JSCallbackInfo & info)143 void JSTextClock::JsOnDateChange(const JSCallbackInfo& info)
144 {
145 if (!info[0]->IsFunction()) {
146 return;
147 }
148
149 auto jsFunc = AceType::MakeRefPtr<JsFunction>(JSRef<JSObject>(), JSRef<JSFunc>::Cast(info[0]));
150 auto onChange = [execCtx = info.GetExecutionContext(), func = std::move(jsFunc)](const std::string& value) {
151 JAVASCRIPT_EXECUTION_SCOPE_WITH_CHECK(execCtx);
152 ACE_SCORING_EVENT("TextClock.onDateChange");
153 auto newJSVal = JSRef<JSVal>::Make(ToJSValue(value));
154 func->ExecuteJS(1, &newJSVal);
155 };
156 TextClockModel::GetInstance()->SetOnDateChange(std::move(onChange));
157 }
158
JSBind(BindingTarget globalObj)159 void JSTextClockController::JSBind(BindingTarget globalObj)
160 {
161 JSClass<JSTextClockController>::Declare("TextClockController");
162 JSClass<JSTextClockController>::Method("start", &JSTextClockController::Start);
163 JSClass<JSTextClockController>::Method("stop", &JSTextClockController::Stop);
164 JSClass<JSTextClockController>::Bind(
165 globalObj, JSTextClockController::Constructor, JSTextClockController::Destructor);
166 }
167
Constructor(const JSCallbackInfo & args)168 void JSTextClockController::Constructor(const JSCallbackInfo& args)
169 {
170 auto scroller = Referenced::MakeRefPtr<JSTextClockController>();
171 scroller->IncRefCount();
172 args.SetReturnValue(Referenced::RawPtr(scroller));
173 }
174
Destructor(JSTextClockController * scroller)175 void JSTextClockController::Destructor(JSTextClockController* scroller)
176 {
177 if (scroller != nullptr) {
178 scroller->DecRefCount();
179 }
180 }
181
Start()182 void JSTextClockController::Start()
183 {
184 if (controller_) {
185 controller_->Start();
186 }
187 }
188
Stop()189 void JSTextClockController::Stop()
190 {
191 if (controller_) {
192 controller_->Stop();
193 }
194 }
195 } // namespace OHOS::Ace::Framework
196