• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&currentTime, 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(&current);
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(&current);
372     if (!std::isnan(hourWest_)) {
373         current = current - int32_t(hourWest_ * TOTAL_SECONDS_OF_HOUR);
374         timeZoneTime = std::gmtime(&current); // 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