1 /*
2 * Copyright (c) 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 "core/components_ng/pattern/texttimer/text_timer_pattern.h"
17
18 #include <stack>
19 #include <string>
20
21 #include "base/i18n/localization.h"
22 #include "base/utils/utils.h"
23 #include "core/components/common/layout/constants.h"
24 #include "core/components_ng/property/property.h"
25
26 namespace OHOS::Ace::NG {
27 namespace {
28 constexpr double DEFAULT_COUNT = 60000.0;
29 const std::string DEFAULT_FORMAT = "HH:mm:ss.SS";
30 } // namespace
31
TextTimerPattern()32 TextTimerPattern::TextTimerPattern()
33 {
34 textTimerController_ = MakeRefPtr<TextTimerController>();
35 }
36
FireChangeEvent() const37 void TextTimerPattern::FireChangeEvent() const
38 {
39 auto textTimerEventHub = GetEventHub<TextTimerEventHub>();
40 CHECK_NULL_VOID(textTimerEventHub);
41 textTimerEventHub->FireChangeEvent(std::to_string(GetMilliseconds()), std::to_string(elapsedTime_));
42 }
43
InitTextTimerController()44 void TextTimerPattern::InitTextTimerController()
45 {
46 if (textTimerController_) {
47 if (textTimerController_->HasInitialized()) {
48 return;
49 }
50 auto weak = AceType::WeakClaim(this);
51 textTimerController_->OnStart([weak]() {
52 auto timerRender = weak.Upgrade();
53 if (timerRender) {
54 timerRender->HandleStart();
55 }
56 });
57 textTimerController_->OnPause([weak]() {
58 auto timerRender = weak.Upgrade();
59 if (timerRender) {
60 timerRender->HandlePause();
61 }
62 });
63 textTimerController_->OnReset([weak]() {
64 auto timerRender = weak.Upgrade();
65 if (timerRender) {
66 timerRender->HandleReset();
67 }
68 });
69 }
70 }
71
InitTimerDisplay()72 void TextTimerPattern::InitTimerDisplay()
73 {
74 auto host = GetHost();
75 CHECK_NULL_VOID(host);
76
77 auto weak = AceType::WeakClaim(this);
78 if (!scheduler_) {
79 auto&& callback = [weak](uint64_t duration) {
80 auto timer = weak.Upgrade();
81 if (timer) {
82 timer->Tick(duration);
83 } else {
84 LOGW("empty timer, skip tick callback.");
85 }
86 };
87 scheduler_ = SchedulerBuilder::Build(callback, host->GetContext());
88 auto count = isCountDown_ ? inputCount_ : 0;
89 UpdateTextTimer(static_cast<uint32_t>(count));
90 } else {
91 HandleReset();
92 }
93 }
94
Tick(uint64_t duration)95 void TextTimerPattern::Tick(uint64_t duration)
96 {
97 elapsedTime_ += duration;
98 FireChangeEvent();
99
100 auto tmpValue = static_cast<double>(elapsedTime_);
101 if (isCountDown_) {
102 tmpValue =
103 (inputCount_ >= static_cast<double>(elapsedTime_)) ? (inputCount_ - static_cast<double>(elapsedTime_)) : 0;
104 }
105 if (isCountDown_ && tmpValue <= 0) {
106 UpdateTextTimer(0);
107 HandlePause();
108 return;
109 }
110
111 UpdateTextTimer(static_cast<uint32_t>(tmpValue));
112 }
113
OnModifyDone()114 void TextTimerPattern::OnModifyDone()
115 {
116 auto host = GetHost();
117 CHECK_NULL_VOID(host);
118 auto textLayoutProperty = GetLayoutProperty<TextLayoutProperty>();
119 CHECK_NULL_VOID(textLayoutProperty);
120 textLayoutProperty->UpdateTextOverflow(TextOverflow::NONE);
121 if (textLayoutProperty->GetPositionProperty()) {
122 textLayoutProperty->UpdateAlignment(
123 textLayoutProperty->GetPositionProperty()->GetAlignment().value_or(Alignment::CENTER));
124 } else {
125 textLayoutProperty->UpdateAlignment(Alignment::CENTER);
126 }
127 textLayoutProperty->UpdateTextOverflow(TextOverflow::NONE);
128
129 isCountDown_ = GetIsCountDown();
130 inputCount_ = GetInputCount();
131
132 InitTextTimerController();
133 InitTimerDisplay();
134 }
135
UpdateTextTimer(uint32_t elapsedTime)136 void TextTimerPattern::UpdateTextTimer(uint32_t elapsedTime)
137 {
138 auto host = GetHost();
139 CHECK_NULL_VOID(host);
140 auto textLayoutProperty = GetLayoutProperty<TextLayoutProperty>();
141 CHECK_NULL_VOID(textLayoutProperty);
142
143 // format time text.
144 std::string timerText = Localization::GetInstance()->FormatDuration(elapsedTime, GetFormat());
145 if (timerText.empty()) {
146 timerText = Localization::GetInstance()->FormatDuration(elapsedTime, DEFAULT_FORMAT);
147 }
148 if (textLayoutProperty->GetContent() == timerText) {
149 return; // needless to update
150 }
151
152 textLayoutProperty->UpdateContent(timerText); // Update time text.
153 host->MarkDirtyNode(PROPERTY_UPDATE_MEASURE_SELF);
154 TextPattern::OnModifyDone();
155 }
156
GetFormat() const157 std::string TextTimerPattern::GetFormat() const
158 {
159 auto textTimerLayoutProperty = GetLayoutProperty<TextTimerLayoutProperty>();
160 CHECK_NULL_RETURN(textTimerLayoutProperty, DEFAULT_FORMAT);
161 return textTimerLayoutProperty->GetFormat().value_or(DEFAULT_FORMAT);
162 }
163
GetIsCountDown() const164 bool TextTimerPattern::GetIsCountDown() const
165 {
166 auto textTimerLayoutProperty = GetLayoutProperty<TextTimerLayoutProperty>();
167 CHECK_NULL_RETURN(textTimerLayoutProperty, false);
168 return textTimerLayoutProperty->GetIsCountDown().value_or(false);
169 }
170
GetInputCount() const171 double TextTimerPattern::GetInputCount() const
172 {
173 auto textTimerLayoutProperty = GetLayoutProperty<TextTimerLayoutProperty>();
174 CHECK_NULL_RETURN(textTimerLayoutProperty, DEFAULT_COUNT);
175 return textTimerLayoutProperty->GetInputCount().value_or(DEFAULT_COUNT);
176 }
177
HandleStart()178 void TextTimerPattern::HandleStart()
179 {
180 if (scheduler_ && !scheduler_->IsActive()) {
181 scheduler_->Start();
182 }
183 }
184
HandlePause()185 void TextTimerPattern::HandlePause()
186 {
187 if (scheduler_ && scheduler_->IsActive()) {
188 scheduler_->Stop();
189 }
190 }
191
HandleReset()192 void TextTimerPattern::HandleReset()
193 {
194 if (scheduler_ && scheduler_->IsActive()) {
195 scheduler_->Stop();
196 }
197 elapsedTime_ = 0;
198 auto count = isCountDown_ ? inputCount_ : 0;
199 UpdateTextTimer(static_cast<uint32_t>(count));
200 }
201 } // namespace OHOS::Ace::NG
202