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/texttimer/render_texttimer.h"
17 
18 #include <string>
19 
20 #include "base/i18n/localization.h"
21 #include "core/components/stack/stack_element.h"
22 #include "core/components/text/render_text.h"
23 #include "core/components/texttimer/texttimer_component.h"
24 
25 namespace OHOS::Ace {
RenderTextTimer()26 RenderTextTimer::RenderTextTimer()
27 {
28     textComponent_ = AceType::MakeRefPtr<TextComponent>(std::string(""));
29     renderText_ = AceType::DynamicCast<RenderText>(RenderText::Create());
30     AddChild(renderText_);
31 }
32 
~RenderTextTimer()33 RenderTextTimer::~RenderTextTimer()
34 {
35     if (scheduler_ && scheduler_->IsActive()) {
36         scheduler_->Stop();
37     }
38 }
39 
Update(const RefPtr<Component> & component)40 void RenderTextTimer::Update(const RefPtr<Component>& component)
41 {
42     auto timerComponent = AceType::DynamicCast<TextTimerComponent>(component);
43     if (!timerComponent) {
44         LOGE("input timerComponent is incorrect type or null.");
45         return;
46     }
47 
48     inputCount_ = timerComponent->GetInputCount();
49     isCountDown_ = timerComponent->GetIsCountDown();
50     format_ = timerComponent->GetFormat();
51 
52     const auto context = context_.Upgrade();
53     if (context && context->GetIsDeclarative()) {
54         if (timerComponent->GetOnTimer()) {
55             onTimer_ = *timerComponent->GetOnTimer();
56         }
57     }
58 
59     const auto& timerController = timerComponent->GetTextTimerController();
60     if (timerController) {
61         auto weak = AceType::WeakClaim(this);
62         timerController->OnStart([weak]() {
63             auto timerRender = weak.Upgrade();
64             if (timerRender) {
65                 timerRender->HandleStart();
66             }
67         });
68         timerController->OnPause([weak]() {
69             auto timerRender = weak.Upgrade();
70             if (timerRender) {
71                 timerRender->HandlePause();
72             }
73         });
74         timerController->OnReset([weak]() {
75             auto timerRender = weak.Upgrade();
76             if (timerRender) {
77                 timerRender->HandleReset();
78             }
79         });
80     }
81 
82     auto weak = AceType::WeakClaim(this);
83     if (!scheduler_) {
84         auto&& callback = [weak](uint64_t duration) {
85             auto timer = weak.Upgrade();
86             if (timer) {
87                 timer->Tick(duration);
88             } else {
89                 LOGW("empty timer, skip tick callback.");
90             }
91         };
92         scheduler_ = SchedulerBuilder::Build(callback, context);
93         textComponent_->SetTextStyle(timerComponent->GetTextStyle());
94         UpdateValue(isCountDown_ ? inputCount_ : 0);
95     } else {
96         HandleReset();
97     }
98 
99     MarkNeedRender();
100 }
101 
PerformLayout()102 void RenderTextTimer::PerformLayout()
103 {
104     Size layoutSize;
105     const auto& children = GetChildren();
106     if (!children.empty()) {
107         auto child = children.front();
108         child->Layout(GetLayoutParam());
109         child->SetPosition(Offset::Zero());
110         layoutSize = child->GetLayoutSize();
111     }
112     SetLayoutSize(layoutSize);
113 }
114 
UpdateValue(uint32_t elapsedTime)115 void RenderTextTimer::UpdateValue(uint32_t elapsedTime)
116 {
117     std::string timerText = Localization::GetInstance()->FormatDuration(elapsedTime, format_);
118 
119     if (!textComponent_) {
120         LOGE("(RenderTextTimer::UpdateValue)texttimer component is null.");
121         return;
122     }
123 
124     if (textComponent_->GetData() == timerText) {
125         return; // needless to update
126     }
127 
128     textComponent_->SetData(timerText);
129     if (!renderText_) {
130         LOGE("(RenderTextTimer::UpdateValue)render texttimer is null.");
131         return;
132     }
133     renderText_->Attach(GetContext());
134     renderText_->Update(textComponent_);
135     MarkNeedRender();
136 }
137 
Tick(uint64_t duration)138 void RenderTextTimer::Tick(uint64_t duration)
139 {
140     elapsedTime_ += duration;
141 
142     if (onTimer_) {
143         onTimer_(GetMilliseconds(), elapsedTime_);
144     }
145 
146     double tmp_value = static_cast<double>(elapsedTime_);
147     if (isCountDown_) {
148         tmp_value = (inputCount_ >= elapsedTime_) ? (inputCount_ - elapsedTime_) : 0;
149     }
150 
151     if (isCountDown_ && tmp_value <= 0) {
152         UpdateValue(0);
153         HandlePause();
154         return;
155     }
156 
157     UpdateValue(static_cast<uint32_t>(tmp_value));
158 }
159 
HandleStart()160 void RenderTextTimer::HandleStart()
161 {
162     if (scheduler_ && !scheduler_->IsActive()) {
163         scheduler_->Start();
164     }
165 }
166 
HandlePause()167 void RenderTextTimer::HandlePause()
168 {
169     if (scheduler_ && scheduler_->IsActive()) {
170         scheduler_->Stop();
171     }
172 }
173 
HandleReset()174 void RenderTextTimer::HandleReset()
175 {
176     if (scheduler_ && scheduler_->IsActive()) {
177         scheduler_->Stop();
178     }
179     elapsedTime_ = 0;
180     UpdateValue(isCountDown_ ? inputCount_ : 0);
181 }
182 } // namespace OHOS::Ace