1e16964b2c500311e19ae3d8a7fa355cad18a228
[profile/tv/apps/dotnet/home.git] / TVApps / TVApps / ViewModels / AppsHolder.cs
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.1 (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://floralicense.org/license/
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 using LibTVRefCommonPortable.DataModels;
18 using LibTVRefCommonPortable.Utils;
19 using System.Collections.Generic;
20 using System.Linq;
21 using System.Threading.Tasks;
22 using Xamarin.Forms;
23
24 namespace TVApps.ViewModels
25 {
26     /// <summary>
27     /// A class contains installed, pinned application list.
28     /// The MainPageViewModel changes state of application item by AppsHolder's API
29     /// </summary>
30     internal class AppsHolder
31     {
32         /// <summary>
33         /// The interface for interaction with view model
34         /// </summary>
35         IAppsViewModel ViewModel;
36
37         /// <summary>
38         /// A flag indicates how to sort InstalledApps
39         /// </summary>
40         /// <see cref="SortingOptions"/>
41         public SortingOptions SortingOption;
42
43         /// <summary>
44         /// A list contains AppShortcutInfo about installed applications
45         /// </summary>
46         /// <see cref="AppShortcutInfo"/>
47         public List<AppShortcutInfo> InstalledApps;
48
49         /// <summary>
50         /// A dictionary contains ID of pinned applications
51         /// </summary>
52         public Dictionary<string, string> PinnedApps;
53
54         public string PinnedAppName;
55         public string UnpinnedAppName;
56
57         /// <summary>
58         /// A constructor
59         /// Initializes installed and pinned app list
60         /// </summary>
61         /// <param name="ViewModel">The instance of MainPageViewModel</param>
62         public AppsHolder(IAppsViewModel ViewModel)
63         {
64             this.ViewModel = ViewModel;
65
66             InstalledApps = new List<AppShortcutInfo>();
67             PinnedApps = new Dictionary<string, string>();
68
69             App.SetAppInstalledListener((s, e) =>
70             {
71                 SetApps();
72             });
73
74             App.SetAppUninstalledListener((s, e) =>
75             {
76                 SetApps();
77             });
78
79             SetApps();
80         }
81
82         /// <summary>
83         /// A method gets installed, pinned application information from AppShortcutController.
84         /// And adds state descriptions about pin, delete, long press state
85         /// </summary>
86         private async void SetApps()
87         {
88             var pinnedAppsGettingTask = TVHomeImpl.GetInstance.AppShortcutControllerInstance.GetPinnedAppsAppIDs();
89             var installedAppsGettingTask = TVHomeImpl.GetInstance.AppShortcutControllerInstance.GetInstalledApps();
90
91             await Task.WhenAll(pinnedAppsGettingTask, installedAppsGettingTask);
92
93             PinnedApps = pinnedAppsGettingTask.Result;
94             ViewModel.OnPropertyChanged("SumOfCheckedApp");
95
96             var installedApps = installedAppsGettingTask.Result;
97
98             foreach (AppShortcutInfo item in installedApps)
99             {
100                 if (item.CurrentStateDescription == null)
101                 {
102                     DebuggingUtils.Err("Invalid AppshortcutInfo, " + item.AppID);
103                     continue;
104                 }
105
106                 item.IsPinned = PinnedApps.ContainsKey(item.AppID);
107
108                 var pinStateDescription = new StateDescription()
109                 {
110                     Label = item.CurrentStateDescription.Label,
111                     IconPath = item.CurrentStateDescription.IconPath,
112                     Action = new CommandAction()
113                     {
114                         NextStateDescription = AppsStatus.Pin.ToString().ToLower(),
115                         Command = new Command<string>((key) =>
116                         {
117                             PinToggle(key);
118                         }),
119                         CommandParameter = item.AppID
120                     }
121                 };
122
123                 item.StateDescriptions.Add(AppsStatus.Pin.ToString().ToLower(), pinStateDescription);
124
125                 var deleteStateDescription = new StateDescription()
126                 {
127                     Label = item.CurrentStateDescription.Label,
128                     IconPath = item.CurrentStateDescription.IconPath,
129                     Action = new CommandAction()
130                     {
131                         NextStateDescription = AppsStatus.Delete.ToString().ToLower(),
132                         Command = new Command<string>((key) =>
133                         {
134                             CheckDeleteApp(key);
135                         }),
136                         CommandParameter = item.AppID
137                     }
138                 };
139
140                 item.StateDescriptions.Add(AppsStatus.Delete.ToString().ToLower(), deleteStateDescription);
141
142                 var longPressStateDescription = new StateDescription()
143                 {
144                     Label = item.CurrentStateDescription.Label,
145                     IconPath = item.CurrentStateDescription.IconPath,
146                     Action = new CommandAction()
147                     {
148                         NextStateDescription = AppsStatus.LongPress.ToString().ToLower(),
149                         Command = new Command<string>((key) =>
150                         {
151                             LongPressApp(key);
152                         }),
153                         CommandParameter = item.AppID
154                     }
155                 };
156                 item.StateDescriptions.Add(AppsStatus.LongPress.ToString().ToLower(), longPressStateDescription);
157             }
158
159             InstalledApps = installedApps.ToList();
160             SortApps(SortingOption);
161             UpdateStateDescription(ViewModel.CurrentStatus);
162         }
163
164         /// <summary>
165         /// A method changes pin state of AppShortcutInfo
166         /// And adds or removes application ID in PinnedApps
167         /// </summary>
168         /// <param name="appID">The ID of application for changing pin state</param>
169         private void PinToggle(string appID)
170         {
171             AppShortcutInfo selectedApp = InstalledApps.FirstOrDefault(a => a.AppID == appID);
172             if (selectedApp == null)
173             {
174                 DebuggingUtils.Err("Failed to Pin!!!, Nothing selected, AppID = " + appID);
175                 return;
176             }
177
178             if (PinnedApps.ContainsKey(appID))
179             {
180                 DebuggingUtils.Dbg("UnPin! : " + selectedApp);
181                 selectedApp.IsChecked = false;
182                 selectedApp.IsPinned = false;
183                 PinnedApps.Remove(appID);
184                 UnpinnedAppName = selectedApp.CurrentStateDescription.Label;
185                 ViewModel.OnPropertyChanged("UnpinnedAppName");
186             }
187             else
188             {
189                 DebuggingUtils.Dbg("Pin! : " + selectedApp);
190                 selectedApp.IsChecked = true;
191                 selectedApp.IsPinned = true;
192                 PinnedApps.Add(appID, appID);
193                 PinnedAppName = selectedApp.CurrentStateDescription.Label;
194                 ViewModel.OnPropertyChanged("PinnedAppName");
195             }
196
197             UpdatePinnedApps();
198             ViewModel.OnPropertyChanged("SumOfCheckedApp");
199         }
200
201         /// <summary>
202         /// A method changes pin state of AppShortcutInfo by the Option Menu Pin/Unpin button
203         /// And adds or removes application ID in PinnedApps
204         /// </summary>
205         /// <param name="appID">The ID of application for changing pin state</param>
206         public void OptionMenuPinToggle(string appID)
207         {
208             AppShortcutInfo SelectedApp = InstalledApps.FirstOrDefault(a => a.AppID.Equals(appID));
209             if (SelectedApp == null)
210             {
211                 DebuggingUtils.Err("Failed to get selected app : " + appID);
212                 return;
213             }
214
215             if (PinnedApps.ContainsKey(appID))
216             {
217                 DebuggingUtils.Dbg("Unpin : " + appID);
218                 SelectedApp.IsPinned = false;
219                 PinnedApps.Remove(appID);
220             }
221             else
222             {
223                 DebuggingUtils.Dbg("Pin : " + appID);
224                 SelectedApp.IsPinned = true;
225                 PinnedApps.Add(appID, appID);
226             }
227
228             ViewModel.OnPropertyChanged("SumOfCheckedApp");
229
230             this.UpdatePinnedApps();
231             ViewModel.ChangeCurrentStatus(AppsStatus.Default);
232         }
233
234         /// <summary>
235         /// Removes the pinned app by app ID
236         /// </summary>
237         /// <param name="removableAppsList">The apps list to remove at the pinned app list</param>
238         public void RemovePinnedApp(List<string> removableAppsList)
239         {
240             foreach (string app in removableAppsList)
241             {
242                 if (PinnedApps.ContainsKey(app))
243                 {
244                     DebuggingUtils.Dbg("UnPin! : " + app);
245
246                     PinnedApps.Remove(app);
247                 }
248             }
249
250             UpdatePinnedApps();
251         }
252
253         /// <summary>
254         /// A method sends application delete request
255         /// If application is pinned, removes in PinnedApps
256         /// </summary>
257         /// <param name="appID">The ID of application for deleting</param>
258         public void CheckDeleteApp(string appID)
259         {
260             DebuggingUtils.Dbg("check that the app( " + appID + ") can be deleted");
261
262             if (!ApplicationManagerUtils.GetAppInfoRemovable(appID))
263             {
264                 DebuggingUtils.Dbg("This app is not removable : " + appID);
265                 return;
266             }
267
268             string appLabel = null;
269             if (ApplicationManagerUtils.GetInstalledApplication(appID).TryGetValue("Label", out appLabel))
270             {
271                 ViewModel.ShowDeletePopup(appLabel);
272             }
273         }
274
275         public void DeleteApp(string appID)
276         {
277             // if the app to be deleted is pinned, remove the app in the pinned apps list
278             string pkgID = PackageManagerUtils.GetPackageIDByAppID(appID);
279             if (pkgID == null)
280             {
281                 DebuggingUtils.Err("Failed to get the package ID by app ID(" + appID + ")");
282
283                 return;
284             }
285
286             List<string> appsList = PackageManagerUtils.GetApplicationsByPkgID(pkgID);
287             if (appsList == null || appsList.Count == 0)
288             {
289                 DebuggingUtils.Err("Failed to get the apps list by package ID(" + pkgID + ")");
290
291                 return;
292             }
293
294             ViewModel.ChangeCurrentStatus(AppsStatus.Default);
295
296             if (PackageManagerUtils.UninstallPackageByAppID(appID) == false)
297             {
298                 DebuggingUtils.Err("App uninstall is failed!!!, " + appID);
299             }
300             else
301             {
302                 var removed = from app in InstalledApps
303                               where app.AppID == appID
304                               select app;
305                 InstalledApps.Remove(removed.First());
306                 foreach (var item in InstalledApps)
307                 {
308                     DebuggingUtils.Dbg("- " + item.AppID);
309                 }
310
311                 RemovePinnedApp(appsList);
312                 RefreshApps();
313             }
314         }
315
316         /// <summary>
317         /// A method changes long press state of AppShortcutInfo
318         /// </summary>
319         /// <param name="AppID">The ID of application for showing option menu</param>
320         private void LongPressApp(string AppID)
321         {
322             // TODO:
323             DebuggingUtils.Dbg(" +++++ long press app : " + AppID);
324         }
325
326         /// <summary>
327         /// A method updates state description of applications
328         /// </summary>
329         /// <param name="status">The state name for updating state description</param>
330         public void UpdateStateDescription(AppsStatus status)
331         {
332             string tag = status.ToString().ToLower();
333
334             // TODO : remove this code. this code is temporary.
335             if (status == AppsStatus.LongPress)
336             {
337                 AppShortcutInfo focuesedApp = InstalledApps.Find(a => a.IsFocused);
338                 if (focuesedApp == null)
339                 {
340                     DebuggingUtils.Dbg("FocusedApp is not exist. Change app status to default");
341                     ViewModel.ChangeCurrentStatus(AppsStatus.Default);
342                     return;
343                 }
344             }
345
346             DebuggingUtils.Dbg("AppsListStateUpdate, status = " + status.ToString() + ", tag = " + tag);
347             foreach (AppShortcutInfo item in InstalledApps)
348             {
349                 item.CurrentStateDescription = item.StateDescriptions[tag];
350                 switch (status)
351                 {
352                     case AppsStatus.Default:
353                         item.IsChecked = false;
354                         item.IsDim = false;
355                         item.IsShowOptions = false;
356                         break;
357                     case AppsStatus.Pin:
358                         item.IsChecked = item.IsPinned;
359                         break;
360                     case AppsStatus.LongPress:
361                         if (item.IsFocused)
362                         {
363                             item.IsShowOptions = true;
364                         }
365                         else
366                         {
367                             item.IsDim = true;
368                         }
369
370                         break;
371                     case AppsStatus.Delete:
372                         if (!item.IsRemovable)
373                         {
374                             item.IsDim = true;
375                         }
376
377                         item.IsChecked = false;
378                         break;
379                 }
380
381                 item.IsPinned = PinnedApps.ContainsKey(item.AppID);
382             }
383
384             ViewModel.OnPropertyChanged("InstalledAppList");
385         }
386
387         /// <summary>
388         /// A method refresh InstalledApps
389         /// </summary>
390         private void RefreshApps()
391         {
392             // Only updating elements of InstalledApps is not update the GUI.
393             InstalledApps = new List<AppShortcutInfo>(InstalledApps);
394             ViewModel.OnPropertyChanged("InstalledAppList");
395         }
396
397         /// <summary>
398         /// A method sorts InstalledApps according to parameter
399         /// </summary>
400         /// <param name="sortOption">The option for sorting InstalledApps</param>
401         /// <see cref="SortingOptions"></see>
402         public void SortApps(SortingOptions sortOption)
403         {
404             AppsListSorter.GetSortedAppsList(sortOption, ref InstalledApps);
405             RefreshApps();
406         }
407
408         /// <summary>
409         /// A method reloads PinnedApps from AppShortcutController
410         /// </summary>
411         public async void ResetPinnedApps()
412         {
413             PinnedApps = await TVHomeImpl.GetInstance.AppShortcutControllerInstance.GetPinnedAppsAppIDs();
414         }
415
416         /// <summary>
417         /// A method updates list about pinned application to AppShortcutController
418         /// </summary>
419         public void UpdatePinnedApps()
420         {
421             List<AppShortcutInfo> pinnedAppList = new List<AppShortcutInfo>();
422             foreach (var item in PinnedApps)
423             {
424                 pinnedAppList.Add(new AppShortcutInfo()
425                 {
426                     AppID = item.Key,
427                 });
428             }
429
430             TVHomeImpl.GetInstance.AppShortcutControllerInstance.UpdatePinnedApps(pinnedAppList);
431         }
432
433         /// <summary>
434         /// A method changes visible state of option menu to true
435         /// </summary>
436         /// <param name="appId">The ID of application for showing option menu</param>
437         public void ShowLongPressOption(string appId)
438         {
439             AppShortcutInfo longPressedApp = InstalledApps.Find(app => app.AppID.Equals(appId));
440             if (longPressedApp != null)
441             {
442                 longPressedApp.IsDim = false;
443                 longPressedApp.IsShowOptions = true;
444             }
445         }
446
447         /// <summary>
448         /// A method changes visible state of option menu to false
449         /// </summary>
450         /// <param name="appId">The ID of application for hiding option menu</param>
451         public void HideLongPressOption(string appId)
452         {
453             AppShortcutInfo longPressedApp = InstalledApps.Find(app => app.AppID.Equals(appId));
454             if (longPressedApp != null)
455             {
456                 longPressedApp.IsShowOptions = false;
457             }
458         }
459     }
460 }