1 /*
2 * Copyright (c) 2024 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/linear_indicator/linear_indicator_controller.h"
17
18 #include "core/components_ng/pattern/linear_indicator/linear_indicator_pattern.h"
19 #include "core/components_ng/pattern/progress/progress_pattern.h"
20 #include "core/pipeline_ng/pipeline_context.h"
21
22 namespace OHOS::Ace::NG {
LinearIndicatorControllerData()23 LinearIndicatorControllerData::LinearIndicatorControllerData()
24 : progressAnimation_(nullptr), animationTag_(0), progressInterval_(),
25 totalAnimationTime_(LinearIndicatorController::ANIMATION_TIME_MIN), totalIntervalTime_(0), isLoop_(true)
26 {
27 InitData();
28 }
29
InitData()30 void LinearIndicatorControllerData::InitData()
31 {
32 state_ = LinearIndicatorControllerDataState::STOP;
33 index_ = 0;
34 value_ = .0f;
35 intervalConsumeTime_ = 0;
36 intervalStart_ = std::chrono::system_clock::time_point();
37 }
38
GetProgressSize() const39 int32_t LinearIndicatorController::GetProgressSize() const
40 {
41 auto host = GetHost();
42 CHECK_NULL_RETURN(host, 0);
43 return host->GetChildren().size();
44 }
45
GetProgressNode(int32_t index) const46 RefPtr<FrameNode> LinearIndicatorController::GetProgressNode(int32_t index) const
47 {
48 auto host = GetHost();
49 CHECK_NULL_RETURN(host, nullptr);
50 return AceType::DynamicCast<FrameNode>(host->GetChildAtIndex(index));
51 }
52
InitProgressValue()53 void LinearIndicatorController::InitProgressValue()
54 {
55 int32_t size = GetProgressSize();
56 int32_t index = animationData_.Index();
57 for (int32_t i = 0; i < size; ++i) {
58 float value = .0f;
59 if (i < index) {
60 value = END_VALUE;
61 } else if (i == index) {
62 value = animationData_.Value();
63 }
64 SetProgressComponentValue(i, value);
65 }
66 }
67
SetProgressComponentValue(int32_t index,float value)68 bool LinearIndicatorController::SetProgressComponentValue(int32_t index, float value)
69 {
70 RefPtr<FrameNode> progressNode = GetProgressNode(index);
71 CHECK_NULL_RETURN(progressNode, false);
72 RefPtr<ProgressPaintProperty> paintProperty = progressNode->GetPaintProperty<ProgressPaintProperty>();
73 CHECK_NULL_RETURN(paintProperty, false);
74 paintProperty->UpdateValue(value);
75 progressNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
76 return true;
77 }
78
SetProgressValue(float value)79 void LinearIndicatorController::SetProgressValue(float value)
80 {
81 if (!animationData_.IsRuning()) {
82 return;
83 }
84 if (SetProgressComponentValue(animationData_.Index(), value)) {
85 SetValueAndCallback(value, false);
86 return;
87 }
88 StopAnimation(LinearIndicatorControllerDataState::ANIMATION_PAUSE);
89 animationData_.SetIndexAndValue(0, .0f);
90 StartProgressAnimation();
91 }
92
ProgreAnimationStart()93 void LinearIndicatorController::ProgreAnimationStart()
94 {
95 if (animationData_.Index() == 0) {
96 InitProgressValue();
97 }
98 }
99
StartProgressInterval(int32_t intervalTime)100 void LinearIndicatorController::StartProgressInterval(int32_t intervalTime)
101 {
102 auto host = GetHost();
103 CHECK_NULL_VOID(host);
104 auto context = host->GetContext();
105 CHECK_NULL_VOID(context);
106 auto taskExecutor = context->GetTaskExecutor();
107 CHECK_NULL_VOID(taskExecutor);
108 animationData_.ProgressIntervalCancel();
109 auto weak = AceType::WeakClaim(this);
110 animationData_.ProgressIntervalReset([weak] {
111 auto control = weak.Upgrade();
112 CHECK_NULL_VOID(control);
113 control->StartProgressAnimation();
114 });
115 taskExecutor->PostDelayedTask(
116 animationData_.ProgressInterval(), TaskExecutor::TaskType::UI, intervalTime, LINEAR_INDICATOR_INTERVAL_NAME);
117 animationData_.SetState(LinearIndicatorControllerDataState::INTERVAL);
118 animationData_.UpdateIntervalStart(animationData_.TotalIntervalTime() - intervalTime);
119 }
120
ProgreAnimationEnd()121 void LinearIndicatorController::ProgreAnimationEnd()
122 {
123 if (animationData_.IsPause()) {
124 return;
125 }
126 animationData_.ProgressAnimationAndClear();
127 if (!animationData_.IsRuning()) {
128 return;
129 }
130 int32_t index = animationData_.UpdateIndex();
131 int32_t progressSize = GetProgressSize();
132 if (progressSize == 0) {
133 animationData_.SetIndex(0);
134 animationData_.SetState(LinearIndicatorControllerDataState::STOP);
135 return;
136 }
137 if (index >= progressSize) {
138 animationData_.SetIndex(0);
139 if (!animationData_.IsLoop()) {
140 animationData_.SetState(LinearIndicatorControllerDataState::STOP);
141 return;
142 }
143 }
144 StartProgressInterval(animationData_.TotalIntervalTime());
145 }
146
StartProgressAnimation()147 void LinearIndicatorController::StartProgressAnimation()
148 {
149 if (animationData_.IsProgressAnimation()) {
150 return;
151 }
152 auto host = GetHost();
153 CHECK_NULL_VOID(host);
154 auto weak = AceType::WeakClaim(this);
155 host->CreateAnimatablePropertyFloat(LINEAR_INDICATOR_ANIMATION_NAME, 0, [weak](float value) {
156 auto control = weak.Upgrade();
157 CHECK_NULL_VOID(control);
158 control->SetProgressValue(value);
159 });
160
161 host->UpdateAnimatablePropertyFloat(LINEAR_INDICATOR_ANIMATION_NAME, animationData_.Value());
162
163 int32_t animationTime = animationData_.TotalAnimationTime() * (END_VALUE - animationData_.Value()) / END_VALUE;
164 AnimationOption option;
165 option.SetDuration(animationTime);
166 option.SetCurve(Curves::LINEAR);
167
168 int32_t animationTag = animationData_.UpdateAnimationTag();
169 animationData_.SetProgressAnimation(AnimationUtils::StartAnimation(
170 option,
171 [weak]() {
172 auto control = weak.Upgrade();
173 CHECK_NULL_VOID(control);
174 auto host = control->GetHost();
175 CHECK_NULL_VOID(host);
176 host->UpdateAnimatablePropertyFloat(LINEAR_INDICATOR_ANIMATION_NAME, END_VALUE);
177 control->ProgreAnimationStart();
178 },
179 [weak, animationTag]() {
180 auto control = weak.Upgrade();
181 CHECK_NULL_VOID(control);
182 if (control->animationData_.AnimationTag() != animationTag) {
183 return;
184 }
185 control->ProgreAnimationEnd();
186 }));
187 animationData_.SetState(LinearIndicatorControllerDataState::ANIMATION);
188 }
189
PlayingUpdateTime(int32_t animationTime,int32_t intervalTime)190 void LinearIndicatorController::PlayingUpdateTime(int32_t animationTime, int32_t intervalTime)
191 {
192 if (!animationData_.IsRuning()) {
193 return;
194 }
195 if (animationData_.IsTimeEqually(animationTime, intervalTime)) {
196 return;
197 }
198 if (animationData_.State() == LinearIndicatorControllerDataState::INTERVAL) {
199 if (animationData_.IsIntervalTimeEqually(intervalTime)) {
200 animationData_.SetTotalAnimationTime(animationTime);
201 } else {
202 animationData_.ProgressIntervalCancel();
203 animationData_.SetTime(animationTime, intervalTime);
204 int32_t consumeTime = animationData_.IntervalCurrentConsumeTime();
205 if (consumeTime >= intervalTime) {
206 StartProgressAnimation();
207 } else {
208 StartProgressInterval(intervalTime - consumeTime);
209 }
210 }
211 } else {
212 if (animationData_.IsAnimationTimeEqually(animationTime)) {
213 animationData_.SetTotalIntervalTime(intervalTime);
214 } else {
215 StopAnimation(LinearIndicatorControllerDataState::ANIMATION_PAUSE);
216 SetValueAndCallback(RecalcProgressValue(animationTime), true);
217 animationData_.SetTime(animationTime, intervalTime);
218 StartProgressAnimation();
219 }
220 }
221 }
222
Start(int32_t animationTime,int32_t intervalTime)223 void LinearIndicatorController::Start(int32_t animationTime, int32_t intervalTime)
224 {
225 animationTime = std::max(animationTime, ANIMATION_TIME_MIN);
226 intervalTime = std::max(intervalTime, 0);
227 if (animationData_.IsRuning()) {
228 PlayingUpdateTime(animationTime, intervalTime);
229 } else if (animationData_.IsPause()) {
230 if (animationData_.State() == LinearIndicatorControllerDataState::INTERVAL_PAUSE) {
231 animationData_.SetTime(animationTime, intervalTime);
232 int32_t consumeTime = animationData_.IntervalConsumeTime();
233 if (consumeTime >= intervalTime) {
234 StartProgressAnimation();
235 } else {
236 StartProgressInterval(intervalTime - consumeTime);
237 }
238 } else {
239 SetValueAndCallback(RecalcProgressValue(animationTime), true);
240 animationData_.SetTime(animationTime, intervalTime);
241 StartProgressAnimation();
242 }
243 } else {
244 animationData_.SetTime(animationTime, intervalTime);
245 StartProgressAnimation();
246 }
247 }
248
Pause()249 void LinearIndicatorController::Pause()
250 {
251 if (!animationData_.IsRuning()) {
252 return;
253 }
254 if (animationData_.State() == LinearIndicatorControllerDataState::INTERVAL) {
255 animationData_.SetState(LinearIndicatorControllerDataState::INTERVAL_PAUSE);
256 animationData_.ProgressIntervalCancel();
257 return;
258 }
259 StopAnimation(LinearIndicatorControllerDataState::ANIMATION_PAUSE);
260 }
261
Stop()262 void LinearIndicatorController::Stop()
263 {
264 if (animationData_.IsRuning()) {
265 if (animationData_.State() == LinearIndicatorControllerDataState::INTERVAL) {
266 animationData_.ProgressIntervalCancel();
267 } else {
268 StopAnimation(LinearIndicatorControllerDataState::STOP);
269 }
270 }
271 if ((animationData_.Index() != 0) || (!NearZero(animationData_.Value()))) {
272 if (changeCallback_) {
273 changeCallback_(0, .0f);
274 }
275 }
276 animationData_.InitData();
277 InitProgressValue();
278 }
279
SetProgress(int32_t index,float value)280 void LinearIndicatorController::SetProgress(int32_t index, float value)
281 {
282 if (animationData_.Index() == index && animationData_.Value() == value) {
283 return;
284 }
285 int32_t progressSize = GetProgressSize();
286 if (progressSize == 0) {
287 animationData_.InitData();
288 return;
289 }
290 if (index < 0 || index >= progressSize) {
291 return;
292 }
293 if (value < 0 || value > END_VALUE) {
294 return;
295 }
296 if (changeCallback_) {
297 changeCallback_(index, value);
298 }
299 bool isRuning = animationData_.IsRuning();
300 bool isPause = animationData_.IsPause();
301 if (isRuning) {
302 if (animationData_.State() == LinearIndicatorControllerDataState::INTERVAL) {
303 animationData_.ProgressIntervalCancel();
304 } else {
305 StopAnimation(LinearIndicatorControllerDataState::ANIMATION_PAUSE);
306 }
307 }
308 animationData_.SetIndexAndValue(index, value);
309 InitProgressValue();
310 if (isRuning) {
311 StartProgressAnimation();
312 } else if (isPause) {
313 animationData_.SetState(LinearIndicatorControllerDataState::ANIMATION_PAUSE);
314 }
315 }
316
GetHost() const317 RefPtr<FrameNode> LinearIndicatorController::GetHost() const
318 {
319 auto pattern = pattern_.Upgrade();
320 CHECK_NULL_RETURN(pattern, nullptr);
321 return pattern->GetHost();
322 }
323
StopAnimation(LinearIndicatorControllerDataState state)324 void LinearIndicatorController::StopAnimation(LinearIndicatorControllerDataState state)
325 {
326 animationData_.SetState(state);
327 AnimationUtils::StopAnimation(animationData_.ProgressAnimationAndClear());
328 }
329
UpdateProgressSize(int32_t size)330 void LinearIndicatorController::UpdateProgressSize(int32_t size)
331 {
332 if (animationData_.Index() >= size) {
333 SetProgress(size - 1, END_VALUE);
334 }
335 }
336
RecalcProgressValue(int32_t newAnimationTime)337 float LinearIndicatorController::RecalcProgressValue(int32_t newAnimationTime)
338 {
339 if (newAnimationTime == 0) {
340 return END_VALUE;
341 }
342 int32_t oldAnimationTime = animationData_.TotalAnimationTime();
343 float oldValue = animationData_.Value();
344 return std::clamp(oldAnimationTime * oldValue / newAnimationTime, .0f, END_VALUE);
345 }
346
SetValueAndCallback(float value,bool isDraw)347 void LinearIndicatorController::SetValueAndCallback(float value, bool isDraw)
348 {
349 animationData_.SetValue(value);
350 if (isDraw) {
351 InitProgressValue();
352 }
353 if (changeCallback_) {
354 changeCallback_(animationData_.Index(), value);
355 }
356 }
357 } // namespace OHOS::Ace::NG
358