1 /*
2 * Copyright (c) 2022-2025 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 "core/components_ng/pattern/text_clock/text_clock_pattern.h"
17
18 #include <ctime>
19 #include <string>
20 #include <sys/time.h>
21 #include "ui/base/utils/utils.h"
22
23 #include "base/i18n/localization.h"
24 #include "base/log/dump_log.h"
25 #include "base/utils/multi_thread.h"
26 #include "base/utils/system_properties.h"
27 #include "core/components_ng/pattern/text_clock/text_clock_layout_property.h"
28 #include "core/components_ng/property/property.h"
29 #include "core/event/time/time_event_proxy.h"
30
31 namespace OHOS::Ace::NG {
32 namespace {
33 constexpr int32_t STRING_NEXT_POS = 1;
34 constexpr int32_t TOTAL_SECONDS_OF_HOUR = 60 * 60;
35 constexpr int32_t BASE_YEAR = 1900;
36 constexpr int32_t INTERVAL_OF_U_SECOND = 1000000;
37 constexpr int32_t MICROSECONDS_OF_MILLISECOND = 1000;
38 constexpr int32_t MILLISECONDS_OF_SECOND = 1000;
39 constexpr int32_t TOTAL_SECONDS_OF_MINUTE = 60;
40 constexpr int32_t STR_SIZE_ONE = 1;
41 constexpr int32_t STR_SIZE_TWO = 2;
42 constexpr int32_t MAX_LENGTH_OF_MILLIS = 3;
43 constexpr int32_t SIZE_OF_AM_PM_STRING = 2;
44 constexpr int32_t SIZE_OF_TIME_TEXT = 30;
45 constexpr int32_t BOUNDARY_OF_AM_PM = 12;
46 constexpr int32_t LOG_INTERVAL_TIME = 59 * 1000;
47 constexpr bool ON_TIME_CHANGE = true;
48 const char CHAR_0 = '0';
49 const char CHAR_9 = '9';
50 const char CHAR_SPACE = ' ';
51 const std::string STR_0 = "0";
52 const std::string STR_PREFIX_24H = " 0";
53 const std::string STR_PREFIX_12H = " ";
54 const std::string DEFAULT_FORMAT = "aa hh:mm:ss";
55 const std::string DEFAULT_FORMAT_24H = "HH:mm:ss";
56 const std::string FORM_FORMAT = "hh:mm";
57 const std::string FORM_FORMAT_24H = "HH:mm";
58 const std::string FORMAT_12H = "%Y/%m/%d %I:%M:%S";
59 const std::string FORMAT_24H = "%Y/%m/%d %H:%M:%S";
60 constexpr char TEXTCLOCK_WEEK[] = "textclock.week";
61 constexpr char TEXTCLOCK_YEAR[] = "textclock.year";
62 constexpr char TEXTCLOCK_MONTH[] = "textclock.month";
63 constexpr char TEXTCLOCK_DAY[] = "textclock.day";
64
65 enum class TextClockElementIndex {
66 CUR_YEAR_INDEX = 0,
67 CUR_MONTH_INDEX = 1,
68 CUR_DAY_INDEX = 2,
69 CUR_HOUR_INDEX = 3,
70 CUR_MINUTE_INDEX = 4,
71 CUR_SECOND_INDEX = 5,
72 CUR_MILLISECOND_INDEX = 6,
73 CUR_AMPM_INDEX = 7,
74 CUR_WEEK_INDEX = 8,
75 CUR_SHORT_YEAR_INDEX = 9,
76 CUR_SHORT_MONTH_INDEX = 10,
77 CUR_SHORT_DAY_INDEX = 11,
78 CUR_CENTISECOND_INDEX = 12,
79 CUR_SHORT_WEEK_INDEX = 13,
80 CUR_MAX_INDEX
81 };
82 enum class TextClockElementLen {
83 ONLY_ONE_DATE_ELEMENT = 1,
84 SHORT_YEAR_IN_YEAR_INDEX = 2,
85 YEAR_FORMAT_MIN_LEN = 2,
86 MON_DAY_FORMAT_MAX_LEN = 2,
87 MON_DAY_FORMAT_MIN_LEN = 1,
88 CENTISECOND_FORMAT_LEN = 2,
89 MILLISECOND_FORMAT_LEN = 3,
90 YEAR_WEEK_FORMAT_MAX_LEN = 4,
91 };
92 enum class TextClockWeekType {
93 WEEK_FULL_TYPE = 1,
94 WEEK_SHORT_TYPE = 2,
95 };
96 } // namespace
97
TextClockPattern()98 TextClockPattern::TextClockPattern()
99 {
100 textClockController_ = MakeRefPtr<TextClockController>();
101 }
102
OnAttachToFrameNode()103 void TextClockPattern::OnAttachToFrameNode()
104 {
105 auto host = GetHost();
106 CHECK_NULL_VOID(host);
107 THREAD_SAFE_NODE_CHECK(host, OnAttachToFrameNode);
108 InitTextClockController();
109 InitUpdateTimeTextCallBack();
110 auto* eventProxy = TimeEventProxy::GetInstance();
111 if (eventProxy) {
112 eventProxy->Register(WeakClaim(this));
113 }
114 }
115
OnDetachFromFrameNode(FrameNode * frameNode)116 void TextClockPattern::OnDetachFromFrameNode(FrameNode* frameNode)
117 {
118 THREAD_SAFE_NODE_CHECK(frameNode, OnDetachFromFrameNode, frameNode);
119 auto pipeline = PipelineContext::GetCurrentContext();
120 CHECK_NULL_VOID(pipeline);
121 pipeline->RemoveVisibleAreaChangeNode(frameNode->GetId());
122 }
123
OnAttachToMainTree()124 void TextClockPattern::OnAttachToMainTree()
125 {
126 auto host = GetHost();
127 CHECK_NULL_VOID(host);
128 THREAD_SAFE_NODE_CHECK(host, OnAttachToMainTree);
129 }
130
OnDetachFromMainTree()131 void TextClockPattern::OnDetachFromMainTree()
132 {
133 auto host = GetHost();
134 CHECK_NULL_VOID(host);
135 THREAD_SAFE_NODE_CHECK(host, OnDetachFromMainTree);
136 }
137
UpdateTextLayoutProperty(RefPtr<TextClockLayoutProperty> & layoutProperty,RefPtr<TextLayoutProperty> & textLayoutProperty,const TextStyle & textStyleTheme)138 void TextClockPattern::UpdateTextLayoutProperty(RefPtr<TextClockLayoutProperty>& layoutProperty,
139 RefPtr<TextLayoutProperty>& textLayoutProperty, const TextStyle& textStyleTheme)
140 {
141 if (layoutProperty->GetFontSize().has_value()) {
142 textLayoutProperty->UpdateFontSize(layoutProperty->GetFontSize().value());
143 }
144 if (layoutProperty->GetFontWeight().has_value()) {
145 textLayoutProperty->UpdateFontWeight(layoutProperty->GetFontWeight().value());
146 }
147 textLayoutProperty->UpdateTextColor(layoutProperty->GetTextColor().has_value()
148 ? layoutProperty->GetTextColor().value()
149 : textStyleTheme.GetTextColor());
150 if (layoutProperty->GetFontFamily().has_value() && !layoutProperty->GetFontFamily().value().empty()) {
151 textLayoutProperty->UpdateFontFamily(layoutProperty->GetFontFamily().value());
152 }
153 if (layoutProperty->GetItalicFontStyle().has_value()) {
154 textLayoutProperty->UpdateItalicFontStyle(layoutProperty->GetItalicFontStyle().value());
155 }
156 if (layoutProperty->GetTextShadow().has_value()) {
157 textLayoutProperty->UpdateTextShadow(layoutProperty->GetTextShadow().value());
158 }
159 if (layoutProperty->GetFontFeature().has_value()) {
160 textLayoutProperty->UpdateFontFeature(layoutProperty->GetFontFeature().value());
161 }
162 }
163
OnThemeScopeUpdate(int32_t themeScopeId)164 bool TextClockPattern::OnThemeScopeUpdate(int32_t themeScopeId)
165 {
166 auto host = GetHost();
167 CHECK_NULL_RETURN(host, false);
168 auto textNode = GetTextNode();
169 CHECK_NULL_RETURN(textNode, false);
170 auto textClockProperty = host->GetLayoutProperty<TextClockLayoutProperty>();
171 CHECK_NULL_RETURN(textClockProperty, false);
172
173 if (!textClockProperty->HasTextColor()) {
174 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
175 textNode->MarkModifyDone();
176 OnModifyDone();
177 }
178 return false;
179 }
180
OnModifyDone()181 void TextClockPattern::OnModifyDone()
182 {
183 auto host = GetHost();
184 CHECK_NULL_VOID(host);
185
186 if (host->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN)) {
187 Pattern::OnModifyDone();
188 }
189
190 auto textNode = GetTextNode();
191 CHECK_NULL_VOID(textNode);
192 auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
193 CHECK_NULL_VOID(textLayoutProperty);
194 auto textClockProperty = host->GetLayoutProperty<TextClockLayoutProperty>();
195 CHECK_NULL_VOID(textClockProperty);
196
197 auto pipeline = PipelineBase::GetCurrentContext();
198 CHECK_NULL_VOID(pipeline);
199 auto textTheme = pipeline->GetTheme<TextClockTheme>(host->GetThemeScopeId());
200 CHECK_NULL_VOID(textTheme);
201
202 textLayoutProperty->UpdateTextOverflow(TextOverflow::NONE);
203 UpdateTextLayoutProperty(textClockProperty, textLayoutProperty, textTheme->GetTextStyleClock());
204 hourWest_ = GetHoursWest();
205 delayTask_.Cancel();
206 UpdateTimeText();
207 FireBuilder();
208 }
209
InitTextClockController()210 void TextClockPattern::InitTextClockController()
211 {
212 CHECK_NULL_VOID(textClockController_);
213 if (textClockController_->HasInitialized()) {
214 return;
215 }
216 textClockController_->OnStart([wp = WeakClaim(this)]() {
217 auto textClock = wp.Upgrade();
218 if (textClock) {
219 textClock->isStart_ = true;
220 textClock->UpdateTimeText();
221 }
222 });
223 textClockController_->OnStop([wp = WeakClaim(this)]() {
224 auto textClock = wp.Upgrade();
225 if (textClock) {
226 textClock->isStart_ = false;
227 textClock->FireBuilder();
228 textClock->delayTask_.Cancel();
229 }
230 });
231 }
232
OnVisibleChange(bool isVisible)233 void TextClockPattern::OnVisibleChange(bool isVisible)
234 {
235 TAG_LOGI(AceLogTag::ACE_TEXT_CLOCK,
236 "Clock is %{public}s and clock %{public}s running",
237 isVisible ? "visible" : "invisible", isVisible ? "starts" : "stops");
238 if (isVisible && !isSetVisible_) {
239 isSetVisible_ = isVisible;
240 UpdateTimeText();
241 } else if (!isVisible) {
242 isSetVisible_ = isVisible;
243 delayTask_.Cancel();
244 }
245 }
246
OnVisibleAreaChange(bool visible)247 void TextClockPattern::OnVisibleAreaChange(bool visible)
248 {
249 TAG_LOGI(AceLogTag::ACE_TEXT_CLOCK,
250 "Clock is %{public}s the visible area and clock %{public}s running",
251 visible ? "in" : "out of", visible ? "starts" : "stops");
252 if (visible && !isInVisibleArea_) {
253 isInVisibleArea_ = visible;
254 UpdateTimeText();
255 } else if (!visible) {
256 isInVisibleArea_ = visible;
257 delayTask_.Cancel();
258 }
259 }
260
RegistVisibleAreaChangeCallback()261 void TextClockPattern::RegistVisibleAreaChangeCallback()
262 {
263 auto host = GetHost();
264 CHECK_NULL_VOID(host);
265 auto pipeline = host->GetContext();
266 CHECK_NULL_VOID(pipeline);
267
268 auto areaCallback = [weak = WeakClaim(this)](bool visible, double ratio) {
269 auto pattern = weak.Upgrade();
270 CHECK_NULL_VOID(pattern);
271 pattern->OnVisibleAreaChange(visible);
272 };
273 pipeline->RemoveVisibleAreaChangeNode(host->GetId());
274 std::vector<double> ratioList = {0.0};
275 pipeline->AddVisibleAreaChangeNode(host, ratioList, areaCallback, false);
276 }
277
InitUpdateTimeTextCallBack()278 void TextClockPattern::InitUpdateTimeTextCallBack()
279 {
280 auto host = GetHost();
281 CHECK_NULL_VOID(host);
282 auto context = host->GetContext();
283 if (context) {
284 auto container = Container::Current();
285 bool isDynamicComponent = container && container->IsDynamicRender();
286 isForm_ = context->IsFormRender() && !isDynamicComponent;
287 }
288 RegistVisibleAreaChangeCallback();
289 }
290
UpdateTimeText(bool isTimeChange)291 void TextClockPattern::UpdateTimeText(bool isTimeChange)
292 {
293 if (!isStart_ || (!isTimeChange && (!isSetVisible_ || !isInVisibleArea_))) {
294 return;
295 }
296 FireBuilder();
297 if (!isForm_) {
298 RequestUpdateForNextSecond();
299 }
300 std::string currentTime = GetCurrentFormatDateTime();
301 if (currentTime.empty()) {
302 TAG_LOGE(AceLogTag::ACE_TEXT_CLOCK, "currentTime is empty");
303 return;
304 }
305 if (currentTime != prevTime_ || isTimeChange) {
306 auto host = GetHost();
307 CHECK_NULL_VOID(host);
308 auto textNode = GetTextNode();
309 CHECK_NULL_VOID(textNode);
310 auto textLayoutProperty = textNode->GetLayoutProperty<TextLayoutProperty>();
311 CHECK_NULL_VOID(textLayoutProperty);
312 textLayoutProperty->UpdateContent(currentTime); // update time text.
313 auto textContext = textNode->GetRenderContext();
314 CHECK_NULL_VOID(textContext);
315 textContext->SetClipToFrame(false);
316 textContext->UpdateClipEdge(false);
317 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF_AND_PARENT);
318 textNode->MarkModifyDone();
319 textNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
320 prevTime_ = currentTime;
321 FireChangeEvent();
322 }
323 }
324
RequestUpdateForNextSecond()325 void TextClockPattern::RequestUpdateForNextSecond()
326 {
327 struct timeval currentTime {};
328 gettimeofday(¤tTime, nullptr);
329 /**
330 * 1 second = 1000 millisecond = 1000000 microsecond.
331 * Millisecond is abbreviated as msec. Microsecond is abbreviated as usec.
332 * unit of [delayTime] is msec, unit of [tv_usec] is usec
333 * when [tv_usec] is 000100, (INTERVAL_OF_U_SECOND - timeUsec) / MICROSECONDS_OF_MILLISECOND = 999 msec
334 * which will cause the delay task still arriving in current second, because 999000 + 000100 = 999100 < 1 second
335 * so add an additional millisecond to modify the loss of precision during division
336 */
337 int32_t delayTime =
338 (INTERVAL_OF_U_SECOND - static_cast<int32_t>(currentTime.tv_usec)) / MICROSECONDS_OF_MILLISECOND +
339 1; // millisecond
340 auto nextMinuteFlag = isForm_ || (!makeFunc_.has_value() && GetFormat().find('S') == std::string::npos
341 && GetFormat().find('s') == std::string::npos);
342 if (nextMinuteFlag) {
343 time_t current = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
344 auto* timeZoneTime = std::localtime(¤t);
345 // delay to next minute
346 int32_t tempTime = (TOTAL_SECONDS_OF_MINUTE - timeZoneTime->tm_sec) * MILLISECONDS_OF_SECOND;
347 delayTime += (tempTime - MILLISECONDS_OF_SECOND);
348 }
349
350 auto host = GetHost();
351 CHECK_NULL_VOID(host);
352 auto context = host->GetContext();
353 CHECK_NULL_VOID(context);
354 CHECK_NULL_VOID(context->GetTaskExecutor());
355 delayTask_.Reset([weak = WeakClaim(this)] {
356 auto textClock = weak.Upgrade();
357 CHECK_NULL_VOID(textClock);
358 if (!textClock->isStart_) {
359 return;
360 }
361 textClock->UpdateTimeText();
362 });
363 context->GetTaskExecutor()->PostDelayedTask(
364 delayTask_, TaskExecutor::TaskType::UI, delayTime, "ArkUITextClockUpdateTimeText");
365 }
366
GetCurrentFormatDateTime()367 std::string TextClockPattern::GetCurrentFormatDateTime()
368 {
369 auto now = std::chrono::system_clock::now();
370 time_t current = std::chrono::system_clock::to_time_t(now);
371 auto* timeZoneTime = std::localtime(¤t);
372 if (!std::isnan(hourWest_)) {
373 current = current - int32_t(hourWest_ * TOTAL_SECONDS_OF_HOUR);
374 timeZoneTime = std::gmtime(¤t); // Convert to UTC time.
375 }
376 CHECK_NULL_RETURN(timeZoneTime, "");
377 DateTime dateTime; // This is for i18n date time.
378 dateTime.year =static_cast<uint32_t>(timeZoneTime->tm_year + BASE_YEAR);
379 dateTime.month = static_cast<uint32_t>(timeZoneTime->tm_mon);
380 dateTime.day = static_cast<uint32_t>(timeZoneTime->tm_mday);
381 dateTime.hour = static_cast<uint32_t>(timeZoneTime->tm_hour);
382 dateTime.minute = static_cast<uint32_t>(timeZoneTime->tm_min);
383 dateTime.second = static_cast<uint32_t>(timeZoneTime->tm_sec);
384 if (Container::LessThanAPIVersion(PlatformVersion::VERSION_ELEVEN) && !isForm_) {
385 return Localization::GetInstance()->FormatDateTime(dateTime, GetFormat());
386 }
387 dateTime.week = static_cast<uint32_t>(timeZoneTime->tm_wday); // 0-6
388
389 // parse input format
390 formatElementMap_.clear();
391 ParseInputFormat();
392
393 char buffer[SIZE_OF_TIME_TEXT] = {};
394 std::string dateTimeFormat = is24H_ ? FORMAT_24H : FORMAT_12H;
395 std::strftime(buffer, sizeof(buffer), dateTimeFormat.c_str(), timeZoneTime);
396 CHECK_NULL_RETURN(buffer, "");
397 auto duration_cast_to_millis = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
398 auto timeValue = duration_cast_to_millis.count();
399 auto millis = std::to_string(timeValue % 1000);
400 auto millisLength = millis.length();
401 if (millisLength < MAX_LENGTH_OF_MILLIS) {
402 millis = std::string(MAX_LENGTH_OF_MILLIS - millisLength, '0') + millis;
403 }
404 std::string dateTimeValue = std::string(buffer) + "." + millis;
405 if (!is24H_) {
406 auto zeroPos = dateTimeValue.find(STR_PREFIX_24H);
407 if (zeroPos != std::string::npos) {
408 dateTimeValue = dateTimeValue.replace(zeroPos, STR_PREFIX_24H.length(), STR_PREFIX_12H);
409 }
410 }
411 std::string outputDateTime = ParseDateTime(dateTimeValue, timeZoneTime->tm_wday, timeZoneTime->tm_mon,
412 timeZoneTime->tm_hour);
413 if (timeValue - timeValue_ > LOG_INTERVAL_TIME) {
414 timeValue_ = timeValue;
415 TAG_LOGI(AceLogTag::ACE_TEXT_CLOCK, "newTime:%{public}s", outputDateTime.c_str());
416 }
417 return outputDateTime;
418 }
419
ParseDateTime(const std::string & dateTimeValue,int32_t week,int32_t month,int32_t hour)420 std::string TextClockPattern::ParseDateTime(const std::string& dateTimeValue,
421 int32_t week, int32_t month, int32_t hour)
422 {
423 std::string language = Localization::GetInstance()->GetLanguage();
424 // parse data time
425 std::string tempdateTimeValue = dateTimeValue;
426 std::string strAmPm = is24H_ ? "" : GetAmPm(hour);
427 std::vector<std::string> curDateTime = ParseDateTimeValue(tempdateTimeValue);
428 auto spacePos = tempdateTimeValue.find(CHAR_SPACE);
429 if (spacePos != std::string::npos) {
430 tempdateTimeValue.insert(spacePos + STRING_NEXT_POS, strAmPm);
431 }
432 curDateTime[(int32_t)(TextClockElementIndex::CUR_AMPM_INDEX)] = strAmPm;
433
434 // parse week
435 curDateTime[(int32_t)(TextClockElementIndex::CUR_WEEK_INDEX)] = GetWeek(false, week);
436 curDateTime[(int32_t)(TextClockElementIndex::CUR_SHORT_WEEK_INDEX)] = GetWeek(true, week);
437 // parse month
438 if (strcmp(language.c_str(), "zh") != 0) {
439 auto strMonth = GetMonth(month);
440 curDateTime[(int32_t)(TextClockElementIndex::CUR_MONTH_INDEX)] = strMonth;
441 curDateTime[(int32_t)(TextClockElementIndex::CUR_SHORT_MONTH_INDEX)] = strMonth;
442 }
443 // splice date time
444 std::string outputDateTime = SpliceDateTime(curDateTime);
445 if ((curDateTime[(int32_t)(TextClockElementIndex::CUR_YEAR_INDEX)] == "1900") || (outputDateTime == "")) {
446 if (isForm_) {
447 TextClockFormatElement tempFormatElement;
448 std::vector<std::string> formSplitter = { "h", ":", "m" };
449 formatElementMap_.clear();
450 tempFormatElement.formatElement = formSplitter[0];
451 tempFormatElement.elementKey = 'h';
452 tempFormatElement.formatElementNum = (int32_t)(TextClockElementIndex::CUR_HOUR_INDEX);
453 formatElementMap_[0] = tempFormatElement;
454 tempFormatElement.formatElement = formSplitter[1];
455 tempFormatElement.elementKey = ':';
456 tempFormatElement.formatElementNum = (int32_t)(TextClockElementIndex::CUR_MAX_INDEX);
457 formatElementMap_[1] = tempFormatElement;
458 tempFormatElement.formatElement = formSplitter[2];
459 tempFormatElement.elementKey = 'm';
460 tempFormatElement.formatElementNum = (int32_t)(TextClockElementIndex::CUR_MINUTE_INDEX);
461 formatElementMap_[2] = tempFormatElement;
462 outputDateTime = SpliceDateTime(curDateTime);
463 } else {
464 outputDateTime = tempdateTimeValue;
465 }
466 }
467 return outputDateTime;
468 }
469
ParseInputFormat()470 void TextClockPattern::ParseInputFormat()
471 {
472 std::string inputFormat = GetFormat();
473 std::vector<std::string> formatSplitter;
474 auto i = 0;
475 auto j = 0;
476 auto len = static_cast<int32_t>(inputFormat.length());
477 std::string tempFormat = "";
478 TextClockFormatElement tempFormatElement;
479 tempFormatElement.formatElement = "";
480 tempFormatElement.formatElementNum = 0;
481 auto is12h = true;
482 for (tempFormat = inputFormat[i]; i < len; i++) {
483 if (inputFormat[i] == 'H') {
484 is24H_ = true;
485 is12h = false;
486 }
487 if ((i + 1) < len) {
488 if (inputFormat[i] == inputFormat[i + 1]) {
489 tempFormat += inputFormat[i + 1]; // the same element format
490 tempFormatElement.formatElementNum++;
491 } else {
492 tempFormatElement.formatElement = tempFormat;
493 tempFormatElement.formatElementNum++;
494 GetDateTimeIndex(inputFormat[i], tempFormatElement);
495 tempFormatElement.elementKey = inputFormat[i];
496 formatElementMap_[j] = tempFormatElement;
497 j++;
498 // clear current element
499 tempFormat = "";
500 tempFormat += inputFormat[i + 1]; // the next element format
501 tempFormatElement.formatElement = "";
502 tempFormatElement.formatElementNum = 0;
503 }
504 } else { // the last element
505 tempFormatElement.formatElement = tempFormat;
506 tempFormatElement.formatElementNum++;
507 GetDateTimeIndex(inputFormat[i], tempFormatElement);
508 tempFormatElement.elementKey = inputFormat[i];
509 formatElementMap_[j] = tempFormatElement;
510 }
511 }
512 auto host = GetHost();
513 CHECK_NULL_VOID(host);
514 if (host->GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN) && is12h) {
515 is24H_ = false;
516 }
517 }
518
GetDateTimeIndex(const char & element,TextClockFormatElement & tempFormatElement)519 void TextClockPattern::GetDateTimeIndex(const char& element, TextClockFormatElement& tempFormatElement)
520 {
521 switch (element) {
522 case 'y':
523 if (tempFormatElement.formatElementNum >= (int32_t)(TextClockElementLen::YEAR_WEEK_FORMAT_MAX_LEN)) {
524 tempFormatElement.formatElementNum = (int32_t)(TextClockElementIndex::CUR_YEAR_INDEX);
525 } else {
526 tempFormatElement.formatElementNum = (int32_t)(TextClockElementIndex::CUR_SHORT_YEAR_INDEX);
527 }
528 break;
529 case 'M':
530 if (tempFormatElement.formatElementNum >= (int32_t)(TextClockElementLen::MON_DAY_FORMAT_MAX_LEN)) {
531 tempFormatElement.formatElementNum = (int32_t)(TextClockElementIndex::CUR_MONTH_INDEX);
532 } else {
533 tempFormatElement.formatElementNum = (int32_t)(TextClockElementIndex::CUR_SHORT_MONTH_INDEX);
534 }
535 break;
536 case 'd':
537 if (tempFormatElement.formatElementNum >= (int32_t)(TextClockElementLen::MON_DAY_FORMAT_MAX_LEN)) {
538 tempFormatElement.formatElementNum = (int32_t)(TextClockElementIndex::CUR_DAY_INDEX);
539 } else {
540 tempFormatElement.formatElementNum = (int32_t)(TextClockElementIndex::CUR_SHORT_DAY_INDEX);
541 }
542 break;
543 case 'E':
544 if (tempFormatElement.formatElementNum >= (int32_t)(TextClockElementLen::YEAR_WEEK_FORMAT_MAX_LEN)) {
545 tempFormatElement.formatElementNum = (int32_t)(TextClockElementIndex::CUR_WEEK_INDEX);
546 } else {
547 tempFormatElement.formatElementNum = (int32_t)(TextClockElementIndex::CUR_SHORT_WEEK_INDEX);
548 }
549 break;
550 case 'a':
551 tempFormatElement.formatElementNum = (int32_t)(TextClockElementIndex::CUR_AMPM_INDEX);
552 break;
553 case 'H':
554 case 'h':
555 tempFormatElement.formatElementNum = (int32_t)(TextClockElementIndex::CUR_HOUR_INDEX);
556 break;
557 case 'm':
558 tempFormatElement.formatElementNum = (int32_t)(TextClockElementIndex::CUR_MINUTE_INDEX);
559 break;
560 case 's':
561 tempFormatElement.formatElementNum = (int32_t)(TextClockElementIndex::CUR_SECOND_INDEX);
562 break;
563 case 'S':
564 if (tempFormatElement.formatElementNum >= (int32_t)(TextClockElementLen::MILLISECOND_FORMAT_LEN)) {
565 tempFormatElement.formatElementNum = (int32_t)(TextClockElementIndex::CUR_MILLISECOND_INDEX);
566 } else {
567 tempFormatElement.formatElementNum = (int32_t)(TextClockElementIndex::CUR_CENTISECOND_INDEX);
568 }
569 break;
570 default:
571 break;
572 }
573 }
574
GetAmPm(int32_t hour)575 std::string TextClockPattern::GetAmPm(int32_t hour)
576 {
577 std::string language = Localization::GetInstance()->GetLanguage();
578 std::string curAmPm = "";
579 std::vector<std::string> amPmStrings = Localization::GetInstance()->GetAmPmStrings();
580 if (amPmStrings.size() < SIZE_OF_AM_PM_STRING) {
581 return curAmPm;
582 }
583 if (hour < BOUNDARY_OF_AM_PM) {
584 curAmPm = amPmStrings[0];
585 } else {
586 curAmPm = amPmStrings[1];
587 }
588 return curAmPm;
589 }
590
AddZeroPrefix(const std::string & strTimeValue)591 std::string TextClockPattern::AddZeroPrefix(const std::string& strTimeValue)
592 {
593 if (strTimeValue.size() == STR_SIZE_ONE && CHAR_0 <= strTimeValue[0] && strTimeValue[0] <= CHAR_9) {
594 return std::string(STR_0) + strTimeValue;
595 }
596 return strTimeValue;
597 }
598
RemoveZeroPrefix(const std::string & strTimeValue)599 std::string TextClockPattern::RemoveZeroPrefix(const std::string& strTimeValue)
600 {
601 if (strTimeValue.size() == STR_SIZE_TWO && strTimeValue[0] == CHAR_0) {
602 return strTimeValue.substr(1, 1);
603 }
604 return strTimeValue;
605 }
606
ParseDateTimeValue(const std::string & strDateTimeValue)607 std::vector<std::string> TextClockPattern::ParseDateTimeValue(const std::string& strDateTimeValue)
608 {
609 std::string dateTimeValue = strDateTimeValue;
610 std::vector<std::string> curDateTime = { "1900", "0", "1", "0", "0", "0", "0", "", "0", "", "", "", "", "" };
611 auto dateFirstSplit = dateTimeValue.find('/');
612 auto dateSecondSplit = dateTimeValue.find('/', dateFirstSplit + 1);
613 auto dateThirdSplit =
614 (dateTimeValue.find(',') != std::string::npos) ? dateTimeValue.find(',') : dateTimeValue.find(' ');
615 if (curDateTime.size() != static_cast<size_t>(TextClockElementIndex::CUR_MAX_INDEX)) {
616 return curDateTime;
617 }
618 if ((dateFirstSplit != std::string::npos) && (dateSecondSplit != std::string::npos) &&
619 (dateThirdSplit != std::string::npos) && (dateSecondSplit > dateFirstSplit) &&
620 (dateThirdSplit > dateSecondSplit)) {
621 std::string dateFirst = dateTimeValue.substr(0, dateFirstSplit);
622 std::string dateSecond = dateTimeValue.substr(dateFirstSplit + 1, dateSecondSplit - dateFirstSplit - 1);
623 std::string dateThird = dateTimeValue.substr(dateSecondSplit + 1, dateThirdSplit - dateSecondSplit - 1);
624 if (dateFirstSplit > static_cast<size_t>(TextClockElementLen::MON_DAY_FORMAT_MAX_LEN)) {
625 curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_YEAR_INDEX)] = dateFirst;
626 curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_MONTH_INDEX)] = dateSecond;
627 curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_DAY_INDEX)] = dateThird;
628 } else {
629 curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_YEAR_INDEX)] = dateThird;
630 curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_MONTH_INDEX)] = dateFirst;
631 curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_DAY_INDEX)] = dateSecond;
632 }
633
634 // get short date
635 curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_SHORT_YEAR_INDEX)] =
636 (curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_YEAR_INDEX)].length() >
637 static_cast<size_t>(TextClockElementLen::YEAR_FORMAT_MIN_LEN))
638 ? curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_YEAR_INDEX)].substr(
639 static_cast<size_t>(TextClockElementLen::SHORT_YEAR_IN_YEAR_INDEX),
640 static_cast<size_t>(TextClockElementLen::YEAR_FORMAT_MIN_LEN))
641 : curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_YEAR_INDEX)];
642 if (curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_MONTH_INDEX)].length() >
643 static_cast<size_t>(TextClockElementLen::MON_DAY_FORMAT_MIN_LEN)) {
644 curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_SHORT_MONTH_INDEX)] =
645 (curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_MONTH_INDEX)].substr(0, 1) == "0")
646 ? curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_MONTH_INDEX)].substr(1, 1)
647 : curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_MONTH_INDEX)];
648 }
649 if (curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_DAY_INDEX)].length() >
650 static_cast<size_t>(TextClockElementLen::MON_DAY_FORMAT_MIN_LEN)) {
651 curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_SHORT_DAY_INDEX)] =
652 (curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_DAY_INDEX)].substr(0, 1) == "0")
653 ? curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_DAY_INDEX)].substr(1, 1)
654 : curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_DAY_INDEX)];
655 }
656
657 dateTimeValue.erase(0, dateThirdSplit);
658 if (dateTimeValue.find(" ") != std::string::npos) {
659 dateTimeValue.replace(dateTimeValue.find(" "), 1, "");
660 }
661 if (dateTimeValue.find(",") != std::string::npos) {
662 dateTimeValue.replace(dateTimeValue.find(","), 1, "");
663 }
664 auto timeFirstSplit = dateTimeValue.find(':');
665 auto timeSecondSplit = dateTimeValue.find(':', timeFirstSplit + 1);
666 auto timeThirdSplit =
667 (dateTimeValue.find('.') != std::string::npos) ? dateTimeValue.find('.') : (dateTimeValue.length() - 1);
668 if ((timeFirstSplit != std::string::npos) && (timeSecondSplit != std::string::npos) &&
669 (timeThirdSplit != std::string::npos) && (timeSecondSplit > timeFirstSplit) &&
670 (timeThirdSplit > timeSecondSplit)) {
671 if (GetPrefixHour() == ZeroPrefixType::SHOW && !is24H_) {
672 curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_HOUR_INDEX)] =
673 AddZeroPrefix((dateTimeValue.substr(0, timeFirstSplit)));
674 } else if (GetPrefixHour() == ZeroPrefixType::HIDE && is24H_) {
675 curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_HOUR_INDEX)] =
676 RemoveZeroPrefix((dateTimeValue.substr(0, timeFirstSplit)));
677 } else {
678 curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_HOUR_INDEX)] =
679 dateTimeValue.substr(0, timeFirstSplit);
680 }
681 curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_MINUTE_INDEX)] =
682 dateTimeValue.substr(timeFirstSplit + 1, timeSecondSplit - timeFirstSplit - 1);
683 curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_SECOND_INDEX)] =
684 dateTimeValue.substr(timeSecondSplit + 1, timeThirdSplit - timeSecondSplit - 1);
685 curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_MILLISECOND_INDEX)] =
686 (timeThirdSplit < (dateTimeValue.length() - 1))
687 ? dateTimeValue.substr(timeThirdSplit + 1, (dateTimeValue.length() - 1 - timeThirdSplit))
688 : "";
689 }
690 curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_CENTISECOND_INDEX)] =
691 (curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_MILLISECOND_INDEX)].length() >
692 static_cast<size_t>(TextClockElementLen::CENTISECOND_FORMAT_LEN))
693 ? curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_MILLISECOND_INDEX)].substr(
694 0, static_cast<size_t>(TextClockElementLen::CENTISECOND_FORMAT_LEN))
695 : curDateTime[static_cast<size_t>(TextClockElementIndex::CUR_MILLISECOND_INDEX)];
696 }
697 return curDateTime;
698 }
699
700 // abstractItem: true:get letter false:get non letter
Abstract(const std::string & strSource,const bool & abstractItem)701 std::string TextClockPattern::Abstract(const std::string& strSource, const bool& abstractItem)
702 {
703 std::string strTemp = "";
704 for (char str : strSource) {
705 if (abstractItem ? (std::isalpha(str)) : !(std::isalpha(str))) {
706 strTemp += str;
707 }
708 }
709 return strTemp;
710 }
711
GetDigitNumber(const std::string & strSource)712 int32_t TextClockPattern::GetDigitNumber(const std::string& strSource)
713 {
714 auto letterNum = 0;
715 for (char str : strSource) {
716 if (std::isdigit(str)) {
717 letterNum++;
718 }
719 }
720 return letterNum;
721 }
722
723 // isShortType: false:full type week, true:short type week
GetWeek(const bool & isShortType,const int32_t & week)724 std::string TextClockPattern::GetWeek(const bool& isShortType, const int32_t& week)
725 {
726 std::string language = Localization::GetInstance()->GetLanguage();
727 std::vector<std::string> weeks = Localization::GetInstance()->GetWeekdays(isShortType);
728 std::string curWeek = "";
729
730 if (week < (int32_t)weeks.size()) {
731 if ((strcmp(language.c_str(), "zh") == 0) && isShortType) {
732 // chinese E/EE/EEE
733 curWeek = Localization::GetInstance()->GetEntryLetters(TEXTCLOCK_WEEK) + weeks[week];
734 } else {
735 curWeek = weeks[week];
736 }
737 }
738 return curWeek;
739 }
740
GetMonth(int32_t month)741 std::string TextClockPattern::GetMonth(int32_t month)
742 {
743 std::vector<std::string> months = Localization::GetInstance()->GetMonths(true);
744 std::string curMonth = "";
745 if (month < (int32_t)months.size()) {
746 curMonth = months[month];
747 }
748 return curMonth;
749 }
750
SpliceDateTime(const std::vector<std::string> & curDateTime)751 std::string TextClockPattern::SpliceDateTime(const std::vector<std::string>& curDateTime)
752 {
753 std::string format = "";
754 std::string tempFormat = "";
755 bool oneElement = false;
756 if (((int32_t)(formatElementMap_.size()) == (int32_t)TextClockElementLen::ONLY_ONE_DATE_ELEMENT) &&
757 ((strcmp(Localization::GetInstance()->GetLanguage().c_str(), "zh") == 0))) {
758 oneElement = true; // year,month or day need Chinese suffix when Chinese system
759 }
760 auto it = formatElementMap_.begin();
761 while (it != formatElementMap_.end()) {
762 tempFormat = CheckDateTimeElement(curDateTime, it->second.elementKey, it->second.formatElementNum, oneElement);
763 if (tempFormat.empty()) {
764 tempFormat = Abstract(it->second.formatElement, false); // get non letter splitter
765 }
766 format += tempFormat;
767 it++;
768 }
769 return format;
770 }
771
CheckDateTimeElement(const std::vector<std::string> & curDateTime,const char & element,const int32_t & elementIndex,const bool & oneElement)772 std::string TextClockPattern::CheckDateTimeElement(const std::vector<std::string>& curDateTime, const char& element,
773 const int32_t& elementIndex, const bool& oneElement)
774 {
775 std::string format = "";
776 std::string curDateTimeElement = "yMdHhmsSaE";
777 if (curDateTimeElement.find(element) != std::string::npos) {
778 format = curDateTime[elementIndex];
779 if ((oneElement)) {
780 switch (element) {
781 case 'y':
782 format += Localization::GetInstance()->GetEntryLetters(TEXTCLOCK_YEAR);
783 break;
784 case 'M':
785 format += Localization::GetInstance()->GetEntryLetters(TEXTCLOCK_MONTH);
786 break;
787 case 'd':
788 format += Localization::GetInstance()->GetEntryLetters(TEXTCLOCK_DAY);
789 break;
790 default:
791 break;
792 }
793 }
794 }
795 return format;
796 }
797
FireChangeEvent() const798 void TextClockPattern::FireChangeEvent() const
799 {
800 auto textClockEventHub = GetOrCreateEventHub<TextClockEventHub>();
801 CHECK_NULL_VOID(textClockEventHub);
802 textClockEventHub->FireChangeEvent(std::to_string(GetMilliseconds() / MICROSECONDS_OF_MILLISECOND));
803 }
804
GetFormat() const805 std::string TextClockPattern::GetFormat() const
806 {
807 auto textClockLayoutProperty = GetLayoutProperty<TextClockLayoutProperty>();
808 if (isForm_) {
809 auto defaultFormFormat = FORM_FORMAT;
810 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN) && is24H_) {
811 defaultFormFormat = FORM_FORMAT_24H;
812 }
813 CHECK_NULL_RETURN(textClockLayoutProperty, defaultFormFormat);
814 std::string result = textClockLayoutProperty->GetFormat().value_or(defaultFormFormat);
815 if (result.find("s") != std::string::npos || result.find("S") != std::string::npos) {
816 return defaultFormFormat;
817 }
818 return result;
819 }
820 auto defaultFormat = DEFAULT_FORMAT;
821 if (Container::GreatOrEqualAPITargetVersion(PlatformVersion::VERSION_EIGHTEEN) && is24H_) {
822 defaultFormat = DEFAULT_FORMAT_24H;
823 }
824 CHECK_NULL_RETURN(textClockLayoutProperty, defaultFormat);
825 return textClockLayoutProperty->GetFormat().value_or(defaultFormat);
826 }
827
GetHoursWest() const828 float TextClockPattern::GetHoursWest() const
829 {
830 auto textClockLayoutProperty = GetLayoutProperty<TextClockLayoutProperty>();
831 CHECK_NULL_RETURN(textClockLayoutProperty, NAN);
832 if (textClockLayoutProperty->GetHoursWest().has_value()) {
833 return textClockLayoutProperty->GetHoursWest().value();
834 }
835 return NAN;
836 }
837
GetTextNode()838 RefPtr<FrameNode> TextClockPattern::GetTextNode()
839 {
840 auto host = GetHost();
841 CHECK_NULL_RETURN(host, nullptr);
842 auto textNode = AceType::DynamicCast<FrameNode>(host->GetLastChild());
843 CHECK_NULL_RETURN(textNode, nullptr);
844 if (textNode->GetTag() != V2::TEXT_ETS_TAG) {
845 return nullptr;
846 }
847 return textNode;
848 }
849
OnTimeChange()850 void TextClockPattern::OnTimeChange()
851 {
852 TAG_LOGI(AceLogTag::ACE_TEXT_CLOCK, "Time is changed and clock updates");
853 is24H_ = SystemProperties::Is24HourClock();
854 UpdateTimeText(ON_TIME_CHANGE);
855 }
856
FireBuilder()857 void TextClockPattern::FireBuilder()
858 {
859 auto host = GetHost();
860 CHECK_NULL_VOID(host);
861 if (!makeFunc_.has_value()) {
862 auto children = host->GetChildren();
863 for (const auto& child : children) {
864 if (child->GetId() == nodeId_) {
865 host->RemoveChildAndReturnIndex(child);
866 host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
867 }
868 }
869 return;
870 }
871 auto node = BuildContentModifierNode();
872 if (contentModifierNode_ == node) {
873 return;
874 }
875 host->RemoveChildAndReturnIndex(contentModifierNode_);
876 contentModifierNode_ = node;
877 CHECK_NULL_VOID(contentModifierNode_);
878 nodeId_ = contentModifierNode_->GetId();
879 host->AddChild(contentModifierNode_, 0);
880 host->MarkNeedFrameFlushDirty(PROPERTY_UPDATE_MEASURE);
881 }
882
BuildContentModifierNode()883 RefPtr<FrameNode> TextClockPattern::BuildContentModifierNode()
884 {
885 if (!makeFunc_.has_value()) {
886 return nullptr;
887 }
888 auto timeZoneOffset = GetHoursWest();
889 auto started = isStart_;
890 auto timeValue = static_cast<int64_t>(GetMilliseconds() / MICROSECONDS_OF_MILLISECOND);
891 auto host = GetHost();
892 CHECK_NULL_RETURN(host, nullptr);
893 auto eventHub = host->GetOrCreateEventHub<TextClockEventHub>();
894 CHECK_NULL_RETURN(eventHub, nullptr);
895 auto enabled = eventHub->IsEnabled();
896 TextClockConfiguration textClockConfiguration(timeZoneOffset, started, timeValue, enabled);
897 return (makeFunc_.value())(textClockConfiguration);
898 }
899
OnLanguageConfigurationUpdate()900 void TextClockPattern::OnLanguageConfigurationUpdate()
901 {
902 TAG_LOGI(AceLogTag::ACE_TEXT_CLOCK, "Language is changed and clock updates");
903 UpdateTimeText(true);
904 }
905
DumpInfo()906 void TextClockPattern::DumpInfo()
907 {
908 DumpLog::GetInstance().AddDesc("format: ", GetFormat());
909 DumpLog::GetInstance().AddDesc("hourWest: ", hourWest_);
910 DumpLog::GetInstance().AddDesc("is24H: ", is24H_ ? "true" : "false");
911 DumpLog::GetInstance().AddDesc("isInVisibleArea: ", isInVisibleArea_ ? "true" : "false");
912 DumpLog::GetInstance().AddDesc("isStart: ", isStart_ ? "true" : "false");
913 }
914
OnColorConfigurationUpdate()915 void TextClockPattern::OnColorConfigurationUpdate()
916 {
917 if (!SystemProperties::ConfigChangePerform()) {
918 return;
919 }
920
921 auto host = GetHost();
922 CHECK_NULL_VOID(host);
923 auto pipeline = host->GetContextWithCheck();
924 CHECK_NULL_VOID(pipeline);
925 auto theme = pipeline->GetTheme<TextClockTheme>();
926 CHECK_NULL_VOID(theme);
927 auto pops = host->GetLayoutProperty<TextClockLayoutProperty>();
928 CHECK_NULL_VOID(pops);
929
930 if (!pops->HasTextColorSetByUser() || (pops->HasTextColorSetByUser() && !pops->GetTextColorSetByUserValue())) {
931 UpdateTextClockColor(theme->GetTextStyleClock().GetTextColor(), false);
932 }
933 }
934
ToJsonValue(std::unique_ptr<JsonValue> & json,const InspectorFilter & filter) const935 void TextClockPattern::ToJsonValue(std::unique_ptr<JsonValue>& json, const InspectorFilter& filter) const
936 {
937 Pattern::ToJsonValue(json, filter);
938 /* no fixed attr below, just return */
939 if (filter.IsFastFilter()) {
940 return;
941 }
942 auto textClockLayoutProperty = GetLayoutProperty<TextClockLayoutProperty>();
943 CHECK_NULL_VOID(textClockLayoutProperty);
944 auto optionJson = JsonUtil::Create(true);
945 optionJson->Put("hour",
946 TimeFormat::GetHourFormat(
947 static_cast<int32_t>(textClockLayoutProperty->GetPrefixHourValue(ZeroPrefixType::AUTO)), is24H_)
948 .c_str());
949 json->PutExtAttr("dateTimeOptions", optionJson->ToString().c_str(), filter);
950 }
951
OnColorModeChange(uint32_t colorMode)952 void TextClockPattern::OnColorModeChange(uint32_t colorMode)
953 {
954 Pattern::OnColorModeChange(colorMode);
955 auto host = GetHost();
956 CHECK_NULL_VOID(host);
957 auto pipelineContext = host->GetContext();
958 CHECK_NULL_VOID(pipelineContext);
959 if (host->GetRerenderable()) {
960 host->MarkModifyDone();
961 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
962 }
963 }
964
UpdateTextClockColor(const Color & color,bool isFirstLoad)965 void TextClockPattern::UpdateTextClockColor(const Color& color, bool isFirstLoad)
966 {
967 auto host = GetHost();
968 CHECK_NULL_VOID(host);
969 auto layoutProperty = host->GetLayoutProperty<TextClockLayoutProperty>();
970 CHECK_NULL_VOID(layoutProperty);
971 auto renderContext = host->GetRenderContext();
972 CHECK_NULL_VOID(renderContext);
973 auto pipelineContext = host->GetContext();
974 CHECK_NULL_VOID(pipelineContext);
975 if (isFirstLoad || pipelineContext->IsSystmColorChange()) {
976 layoutProperty->UpdateTextColor(color);
977 renderContext->UpdateForegroundColor(color);
978 renderContext->ResetForegroundColorStrategy();
979 renderContext->UpdateForegroundColorFlag(true);
980 }
981 }
982
UpdateTextClockFontSize(const CalcDimension & fontSize)983 void TextClockPattern::UpdateTextClockFontSize(const CalcDimension& fontSize)
984 {
985 auto host = GetHost();
986 CHECK_NULL_VOID(host);
987 auto layoutProperty = host->GetLayoutProperty<TextClockLayoutProperty>();
988 CHECK_NULL_VOID(layoutProperty);
989 layoutProperty->UpdateFontSize(fontSize);
990 }
991
UpdateTextClockFontFamily(const std::vector<std::string> & fontFamilies)992 void TextClockPattern::UpdateTextClockFontFamily(const std::vector<std::string>& fontFamilies)
993 {
994 auto host = GetHost();
995 CHECK_NULL_VOID(host);
996 auto layoutProperty = host->GetLayoutProperty<TextClockLayoutProperty>();
997 CHECK_NULL_VOID(layoutProperty);
998 layoutProperty->UpdateFontFamily(fontFamilies);
999 }
1000
UpdateTextClockFormat(const std::string & format)1001 void TextClockPattern::UpdateTextClockFormat(const std::string& format)
1002 {
1003 auto host = GetHost();
1004 CHECK_NULL_VOID(host);
1005 auto layoutProperty = host->GetLayoutProperty<TextClockLayoutProperty>();
1006 CHECK_NULL_VOID(layoutProperty);
1007 layoutProperty->UpdateFormat(format);
1008 }
1009 } // namespace OHOS::Ace::NG
1010