8e3c94a95e01a2be892e39ea5f18542af4be7aa2
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Components / Controls / Loading.cs
1 /*
2  * Copyright(c) 2022 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 using System.Collections.Generic;
19 using System.ComponentModel;
20 using System.Diagnostics;
21 using Tizen.NUI.BaseComponents;
22 using Tizen.NUI.Binding;
23 using Tizen.NUI.Accessibility;
24
25 namespace Tizen.NUI.Components
26 {
27     /// <summary>
28     /// The Loading class of nui component. It's used to indicate informs users of the ongoing operation.
29     /// </summary>
30     /// <remarks>
31     /// The Loading is created as `LottieAnimationView` first.
32     /// When the user sets ImageArray separately, the image is changed to `ImageVisual`.
33     /// </remarks>
34     /// <since_tizen> 6 </since_tizen>
35     public class Loading : Control
36     {
37         /// <summary>
38         /// ImageArrayProperty
39         /// </summary>
40         [EditorBrowsable(EditorBrowsableState.Never)]
41         public static readonly BindableProperty ImageArrayProperty = BindableProperty.Create(nameof(ImageArray), typeof(string[]), typeof(Loading), null, propertyChanged: (bindable, oldValue, newValue) =>
42         {
43             var instance = (Loading)bindable;
44             if (newValue != null)
45             {
46                 instance.InternalImageArray = newValue as string[];
47             }
48         },
49         defaultValueCreator: (bindable) =>
50         {
51             var instance = (Loading)bindable;
52             return instance.InternalImageArray;
53         });
54
55         /// <summary>The ImageList bindable property.</summary>
56         [EditorBrowsable(EditorBrowsableState.Never)]
57         public static readonly BindableProperty ImageListProperty = BindableProperty.Create(nameof(ImageList), typeof(IList<string>), typeof(Loading), null, propertyChanged: (bindable, oldValue, newValue) =>
58         {
59             Debug.Assert(((Loading)bindable).imageVisual != null);
60
61             var newList = newValue as List<string>;
62             ((Loading)bindable).imageVisual.URLS = newList == null ? new List<string>() : newList;
63         },
64         defaultValueCreator: (bindable) =>
65         {
66             Debug.Assert(((Loading)bindable).imageVisual != null);
67             return ((Loading)bindable).imageVisual.URLS;
68         });
69         /// <summary>The lottie resource url bindable property.</summary>
70         [EditorBrowsable(EditorBrowsableState.Never)]
71         public static readonly BindableProperty LottieResourceUrlProperty = BindableProperty.Create(nameof(LottieResourceUrl), typeof(string), typeof(Loading), null, propertyChanged: (bindable, oldValue, newValue) =>
72         {
73             var instance = (Loading)bindable;
74             instance.RemoveImageVisual();
75             instance.EnsureLottieView(newValue as string ?? string.Empty);
76         },
77         defaultValueCreator: (bindable) =>
78         {
79             var lottie = ((Loading)bindable).defaultLottieView;
80             return lottie == null ? string.Empty : lottie.URL;
81         });
82         /// <summary>The Size bindable property.</summary>
83         [EditorBrowsable(EditorBrowsableState.Never)]
84         public new static readonly BindableProperty SizeProperty = BindableProperty.Create(nameof(Size), typeof(Size), typeof(Loading), new Size(0, 0), propertyChanged: (bindable, oldValue, newValue) =>
85         {
86             var instance = (Loading)bindable;
87             if (newValue != null)
88             {
89                 Size size = (Size)newValue;
90                 ((View)bindable).Size = size;
91             }
92         },
93         defaultValueCreator: (bindable) =>
94         {
95             var instance = (View)bindable;
96             return instance.Size;
97         });
98         /// <summary>The FrameRate bindable property.</summary>
99         [EditorBrowsable(EditorBrowsableState.Never)]
100         public static readonly BindableProperty FrameRateProperty = BindableProperty.Create(nameof(FrameRate), typeof(int), typeof(Loading), (int)(1000 / 16.6f), propertyChanged: (bindable, oldValue, newValue) =>
101         {
102             var instance = (Loading)bindable;
103             instance.frameRate = (int)newValue;
104             if (0 != instance.frameRate && instance.imageVisual != null) //It will crash if 0
105             {
106                 instance.imageVisual.FrameDelay = instance.frameRate;
107             }
108         },
109         defaultValueCreator: (bindable) =>
110         {
111             return ((Loading)bindable).frameRate;
112         });
113
114         private const string ImageVisualName = "loadingImageVisual";
115         private AnimatedImageVisual imageVisual = null;
116         private LottieAnimationView defaultLottieView = null;
117         private int frameRate = (int)(1000 / 16.6f);
118         private const float defaultFrameDelay = 16.6f;
119         private static readonly string lottieResource = FrameworkInformation.ResourcePath + "IoT_loading_circle_light.json";
120
121
122         /// <summary>
123         /// Actions value to Play animated images.
124         /// </summary>
125         private static int ActionPlay = Interop.AnimatedImageView.AnimatedImageVisualActionPlayGet();
126
127         /// <summary>
128         /// Actions value to Pause animated images.
129         /// </summary>
130         private static int ActionPause = Interop.AnimatedImageView.AnimatedImageVisualActionPauseGet();
131
132         /// <summary>
133         /// Actions value to Stop animated images.
134         /// </summary>
135         private static int ActionStop = Interop.AnimatedImageView.AnimatedImageVisualActionStopGet();
136
137         static Loading() { }
138
139         /// <summary>
140         /// The constructor of Loading.
141         /// </summary>
142         /// <since_tizen> 6 </since_tizen>
143         public Loading() : base()
144         {
145             Initialize();
146         }
147
148         /// <summary>
149         /// Constructor of the Loading class with special style.
150         /// </summary>
151         /// <param name="style">The string to initialize the Loading.</param>
152         /// <since_tizen> 8 </since_tizen>
153         public Loading(string style) : base(style)
154         {
155             Initialize();
156         }
157
158         /// <summary>
159         /// The constructor of the Loading class with specific style.
160         /// </summary>
161         /// <param name="loadingStyle">The style object to initialize the Loading.</param>
162         /// <since_tizen> 8 </since_tizen>
163         public Loading(LoadingStyle loadingStyle) : base(loadingStyle)
164         {
165             Initialize();
166         }
167
168         /// <summary>
169         /// Return currently applied style.
170         /// </summary>
171         /// <remarks>
172         /// Modifying contents in style may cause unexpected behaviour.
173         /// </remarks>
174         /// <since_tizen> 8 </since_tizen>
175         public LoadingStyle Style => (LoadingStyle)(ViewStyle as LoadingStyle)?.Clone();
176
177         /// <summary>
178         /// Gets or sets loading image resource array.
179         /// The mutually exclusive with "LottieResourceUrl".
180         /// </summary>
181         /// <since_tizen> 6 </since_tizen>
182         public string[] ImageArray
183         {
184             get
185             {
186                 return GetValue(ImageArrayProperty) as string[];
187             }
188             set
189             {
190                 RemoveLottieView();
191                 EnsureImageVisual();
192
193                 SetValue(ImageArrayProperty, value);
194                 NotifyPropertyChanged();
195             }
196         }
197         private string[] InternalImageArray
198         {
199             get => (GetValue(ImageListProperty) as List<string>)?.ToArray() ?? null;
200             set => SetValue(ImageListProperty, value == null ? new List<string>() : new List<string>((string[])value));
201         }
202
203         /// <summary>
204         /// Gets loading image resource array.
205         /// </summary>
206         [EditorBrowsable(EditorBrowsableState.Never)]
207         public IList<string> ImageList
208         {
209             get
210             {
211                 return GetValue(ImageListProperty) as List<string>;
212             }
213         }
214
215         /// <summary>
216         /// Gets or sets an lottie resource url.
217         /// The mutually exclusive with "ImageArray".
218         /// </summary>
219         [EditorBrowsable(EditorBrowsableState.Never)]
220         public string LottieResourceUrl
221         {
222             get => GetValue(LottieResourceUrlProperty) as string;
223             set => SetValue(LottieResourceUrlProperty, value);
224         }
225
226         /// <summary>
227         /// Gets or sets loading size.
228         /// </summary>
229         /// <since_tizen> 6 </since_tizen>
230         public new Size Size
231         {
232             get
233             {
234                 return (Size)GetValue(SizeProperty);
235             }
236             set
237             {
238                 SetValue(SizeProperty, value);
239             }
240         }
241
242         /// <summary>
243         /// Gets or sets frame rate of loading.
244         /// </summary>
245         /// <since_tizen> 6 </since_tizen>
246         public int FrameRate
247         {
248             get
249             {
250                 return (int)GetValue(FrameRateProperty);
251             }
252             set
253             {
254                 if (defaultLottieView != null)
255                 {
256                     Tizen.Log.Error("NUI", "Cannot set the frame rate to Lottie Animation. If you want to control it, please set `ImageArray` together.\n");
257                 }
258                 SetValue(FrameRateProperty, value);
259             }
260         }
261
262         /// <inheritdoc/>
263         [EditorBrowsable(EditorBrowsableState.Never)]
264         public override void OnInitialize()
265         {
266             base.OnInitialize();
267             AccessibilityRole = Role.ProgressBar;
268
269             EnsureLottieView(lottieResource);
270
271             AccessibilityManager.Instance.SetAccessibilityAttribute(this, AccessibilityManager.AccessibilityAttribute.Trait, "Loading");
272         }
273
274         /// <inheritdoc/>
275         [EditorBrowsable(EditorBrowsableState.Never)]
276         public override void ApplyStyle(ViewStyle viewStyle)
277         {
278             base.ApplyStyle(viewStyle);
279
280             if (viewStyle is LoadingStyle loadingStyle)
281             {
282                 if (loadingStyle.Images != null)
283                 {
284                     ImageArray = loadingStyle.Images;
285                 }
286
287                 if (loadingStyle.LoadingSize != null)
288                 {
289                     Size = loadingStyle.LoadingSize;
290                 }
291             }
292         }
293
294         /// <summary>
295         /// Get Loading style.
296         /// </summary>
297         /// <returns>The default loading style.</returns>
298         /// <since_tizen> 8 </since_tizen>
299         protected override ViewStyle CreateViewStyle()
300         {
301             return new LoadingStyle();
302         }
303
304         /// <summary>
305         /// Dispose Loading.
306         /// </summary>
307         /// <param name="type">Dispose type.</param>
308         /// <since_tizen> 6 </since_tizen>
309         protected override void Dispose(DisposeTypes type)
310         {
311             if (disposed)
312             {
313                 return;
314             }
315
316             if (type == DisposeTypes.Explicit)
317             {
318                 //Called by User
319                 //Release your own managed resources here.
320                 //You should release all of your own disposable objects here.
321                 RemoveVisual("loadingImageVisual");
322
323                 if (defaultLottieView != null)
324                 {
325                     Utility.Dispose(defaultLottieView);
326                     defaultLottieView = null;
327                 }
328             }
329
330             //You must call base.Dispose(type) just before exit.
331             base.Dispose(type);
332         }
333
334         /// <summary>
335         /// Play Loading Animation.
336         /// </summary>
337         /// <since_tizen> 10 </since_tizen>
338         public void Play()
339         {
340             if (defaultLottieView != null)
341             {
342                 defaultLottieView.Play();
343             }
344             else
345             {
346                 PropertyValue attributes = new PropertyValue(0);
347                 this.DoAction(imageVisual.VisualIndex, ActionPlay, attributes);
348                 attributes.Dispose();
349             }
350         }
351
352         /// <summary>
353         /// Pause Loading Animation.
354         /// </summary>
355         /// <since_tizen> 10 </since_tizen>
356         public void Pause()
357         {
358             if (defaultLottieView != null)
359             {
360                 defaultLottieView.Pause();
361             }
362             else
363             {
364                 PropertyValue attributes = new PropertyValue(0);
365                 this.DoAction(imageVisual.VisualIndex, ActionPause, attributes);
366                 attributes.Dispose();
367             }
368         }
369
370         /// <summary>
371         /// Stop Loading Animation.
372         /// </summary>
373         /// <since_tizen> 10 </since_tizen>
374         public void Stop()
375         {
376             if (defaultLottieView != null)
377             {
378                 defaultLottieView.Stop();
379             }
380             else
381             {
382                 PropertyValue attributes = new PropertyValue(0);
383                 this.DoAction(imageVisual.VisualIndex, ActionStop, attributes);
384                 attributes.Dispose();
385             }
386         }
387
388         private void Initialize()
389         {
390             AccessibilityHighlightable = true;
391         }
392
393         private void EnsureLottieView(string url)
394         {
395             if (defaultLottieView != null)
396             {
397                 if (defaultLottieView.URL == url) return;
398                 defaultLottieView.Stop();
399             }
400             else Add(defaultLottieView = new LottieAnimationView() { LoopCount = -1 });
401
402             defaultLottieView.URL = url;
403             defaultLottieView.Play();
404         }
405
406         private void RemoveLottieView()
407         {
408             if (defaultLottieView == null) return;
409             defaultLottieView.Stop();
410             defaultLottieView.Dispose();
411             defaultLottieView = null;
412         }
413
414         private void EnsureImageVisual()
415         {
416             if (imageVisual == null)
417             {
418                 imageVisual = new AnimatedImageVisual()
419                 {
420                     URLS = new List<string>(),
421                     FrameDelay = defaultFrameDelay,
422                     LoopCount = -1,
423                     Position = new Vector2(0, 0),
424                     Origin = Visual.AlignType.Center,
425                     AnchorPoint = Visual.AlignType.Center,
426                     SizePolicy = VisualTransformPolicyType.Relative,
427                     Size = new Size2D(1, 1)
428                 };
429
430                 AddVisual(ImageVisualName, imageVisual);
431             }
432         }
433
434         private void RemoveImageVisual()
435         {
436             if (imageVisual == null) return;
437             RemoveVisual(ImageVisualName);
438             imageVisual.Dispose();
439             imageVisual = null;
440         }
441     }
442 }