2 * Copyright (c) 2017 Samsung Electronics Co., Ltd
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
8 * http://floralicense.org/license/
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.
19 using TVApps.ViewModels;
20 using System.ComponentModel;
21 using LibTVRefCommonPortable.Utils;
22 using System.Threading;
23 using System.Threading.Tasks;
24 using System.Windows.Input;
25 using System.Collections.Generic;
27 using Xamarin.Forms.PlatformConfiguration.TizenSpecific;
28 using TVApps.Controls;
29 using Tizen.Xamarin.Forms.Extension;
31 namespace TVApps.Views
33 using Tizen = Xamarin.Forms.PlatformConfiguration.Tizen;
35 /// A custom view for displaying main page of TV Apps
37 public partial class MainPage : ContentPage
39 private DropdownList sortList;
40 private Button doneButton;
41 private Button cancelButton;
44 /// SubPanel icon's transition height value when it focused.
46 private int showTransitionHeight = SizeUtils.GetHeightSize(12);
49 /// Identifies the CurrentStatus bindable property
51 public static readonly BindableProperty CurrentStatusProperty = BindableProperty.Create("CurrentStatus", typeof(AppsStatus), typeof(MainPage), default(AppsStatus));
54 /// Gets or sets current status of MainPage
56 public AppsStatus CurrentStatus
58 get { return (AppsStatus)GetValue(CurrentStatusProperty); }
59 set { SetValue(CurrentStatusProperty, value); }
63 /// Identifies the app label bindable property
65 public static readonly BindableProperty DeletePopupAppLabelProperty = BindableProperty.Create("DeletePopupAppLabel", typeof(string), typeof(MainPage), default(string));
68 /// Gets or sets the app label to display at the delete popup
70 public string DeletePopupAppLabel
72 get { return (string)GetValue(DeletePopupAppLabelProperty); }
73 set { SetValue(DeletePopupAppLabelProperty, value); }
77 /// Identifies the delete popup visibility bindable property
79 public static readonly BindableProperty IsEnabledDeletePopupProperty = BindableProperty.Create("IsEnabledDeletePopup", typeof(bool), typeof(MainPage), default(bool));
82 /// Gets or sets whether delete popup is displayed
84 public bool IsEnabledDeletePopup
86 get { return (bool)GetValue(IsEnabledDeletePopupProperty); }
87 set { SetValue(IsEnabledDeletePopupProperty, value); }
91 /// Identifies the pin app control request received information bindable property
93 public static readonly BindableProperty IsPinAppRequestedProperty = BindableProperty.Create("IsPinAppRequested", typeof(bool), typeof(MainPage), default(bool));
96 /// Gets or sets whether pin app control request received information.
98 public bool IsPinAppRequested
100 get { return (bool)GetValue(IsPinAppRequestedProperty); }
101 set { SetValue(IsPinAppRequestedProperty, value); }
105 /// Identifies the delete popup command bindable property
107 public static readonly BindableProperty DeletePopupCommandProperty = BindableProperty.Create("DeletePopupCommand", typeof(Command), typeof(MainPage), default(Command));
110 /// A command will be executed if the button of the delete popup is clicked
112 public ICommand DeletePopupCommand
114 get { return (ICommand)GetValue(DeletePopupCommandProperty); }
115 set { SetValue(DeletePopupCommandProperty, value); }
119 /// Identifies the SumOfCheckedApp bindable property
121 public static readonly BindableProperty SumOfCheckedAppProperty = BindableProperty.Create("SumOfCheckedApp", typeof(int), typeof(MainPage), default(int));
124 /// Gets or sets count of checked AppItemCell
126 public int SumOfCheckedApp
128 get { return (int)GetValue(SumOfCheckedAppProperty); }
129 set { SetValue(SumOfCheckedAppProperty, value); }
133 private async void PlayHideAnimation()
135 var animation = new Animation();
136 var headerAnimation = new Animation(v => Header.Opacity = v, 1, 0);
137 var titleAnimation = new Animation(v => TitleLabel.Opacity = v, 1, 0);
138 var footerAnimation = new Animation(v => FooterNormal.Opacity = v, 1, 0);
139 var appListHeightAnimation = new Animation(v => AppList.TranslationY = v, 0, SizeUtils.GetHeightSize(12));
140 var appListAnimation = new Animation(v => AppList.Opacity = v, 1, 0);
141 var mainAnimation = new Animation(v => this.Opacity = v, 1, 0);
143 animation.Add(0.2, 0.8, headerAnimation);
144 animation.Add(0.2, 0.8, titleAnimation);
145 animation.Add(0.2, 0.8, footerAnimation);
146 animation.Add(0.2, 1, appListHeightAnimation);
147 animation.Add(0.2, 0.8, appListAnimation);
148 animation.Add(0.2, 1, mainAnimation);
150 animation.Commit(this, "QuitAnimation", 16, 834);
156 /// Adds PropertyChanged event handler and MenuKey event listener
160 InitializeComponent();
162 int backKeyImageSize = SizeUtils.GetHeightSize(40);
163 BackKeyInfoImage.WidthRequest = backKeyImageSize;
164 BackKeyInfoImage.HeightRequest = backKeyImageSize;
165 BackKeyInfo.FontSize = SizeUtils.GetFontSize(28);
166 BackKeyInfo.Margin = new Thickness(SizeUtils.GetWidthSize(6), 0, 0, 0);
169 PropertyChanged += MainPagePropertyChanged;
170 SetCurrentStatus(AppsStatus.Default);
172 // TODO: This code is temporary for menu option test
173 App.SetMenuKeyListener((e, arg) =>
175 DebuggingUtils.Dbg("[Apps] Menu key is pressed");
177 if (CurrentStatus == AppsStatus.Default)
179 MessagingCenter.Send<MainPage, string>(this, "ChangeCurrentStatus", AppsStatus.LongPress.ToString());
183 AppList.OnChangeFocusChainingCommand = new Command(() =>
186 AppList.InitializeFocus();
190 protected override async void OnAppearing()
194 await AppList.TranslateTo(0, showTransitionHeight, 0);
195 #pragma warning disable CS4014
196 AppList.TranslateTo(0, 0, 667);
197 #pragma warning restore CS4014
198 await PageDimBox.FadeTo(0.0, 667);
199 PageDimBox.IsVisible = false;
201 AppList.InitializeFocus();
205 private void MakeFocusChaining()
207 List<View> upperList = AppList.GetAppsUpperList().ToList();
208 List<View> lowerList = AppList.GetAppsLowerList().ToList();
210 int upperCount = upperList.Count;
211 int lowerCount = lowerList.Count;
217 for (int i = 1; i < upperCount-1; i++)
219 prevButton = upperList[i-1].FindByName<Button>("ButtonFocusArea");
220 button = upperList[i].FindByName<Button>("ButtonFocusArea");
221 nextButton = upperList[i + 1].FindByName<Button>("ButtonFocusArea");
223 SetFocusChainingLeftAndRight(prevButton, button);
224 SetFocusChainingLeftAndRight(button, nextButton);
228 prevButton?.On<Tizen>()?.SetNextFocusDownView(
229 lowerList[i - 1].FindByName<Button>("ButtonFocusArea"));
232 button?.On<Tizen>()?.SetNextFocusDownView(
233 lowerList[i].FindByName<Button>("ButtonFocusArea"));
235 if (i == upperCount-2)
237 button?.On<Tizen>()?.SetNextFocusDownView(lowerList[i].FindByName<Button>("ButtonFocusArea"));
239 nextButton?.On<Tizen>()?.SetNextFocusRightView(nextButton);
240 nextButton?.On<Tizen>()?.SetNextFocusDownView(
241 lowerList[lowerCount - 1].FindByName<Button>("ButtonFocusArea"));
245 for (int i = 1; i < lowerCount - 1; i++)
247 prevButton = lowerList[i - 1].FindByName<Button>("ButtonFocusArea");
248 button = lowerList[i].FindByName<Button>("ButtonFocusArea");
249 nextButton = lowerList[i + 1].FindByName<Button>("ButtonFocusArea");
251 SetFocusChainingLeftAndRight(prevButton, button);
252 SetFocusChainingLeftAndRight(button, nextButton);
256 prevButton?.On<Tizen>()?.SetNextFocusUpView(
257 upperList[i - 1].FindByName<Button>("ButtonFocusArea"));
260 button?.On<Tizen>()?.SetNextFocusUpView(
261 upperList[i].FindByName<Button>("ButtonFocusArea"));
263 if (i == lowerCount-2)
265 nextButton?.On<Tizen>()?.SetNextFocusUpView(upperList[i+1].FindByName<Button>("ButtonFocusArea"));
267 if (upperCount > lowerCount)
269 nextButton?.On<Tizen>()?.SetNextFocusRightView(upperList[upperCount-1].FindByName<Button>("ButtonFocusArea"));
273 nextButton?.On<Tizen>()?.SetNextFocusRightView(nextButton);
278 SetFocusChainingWithCurrentStatus(CurrentStatus);
281 private void SetFocusChainingLeftAndRight(Button left, Button right)
283 left?.On<Tizen>()?.SetNextFocusRightView(right);
284 right?.On<Tizen>()?.SetNextFocusLeftView(left);
287 private void SetFocusChainingUpAndDownForDefaultMode()
289 List<View> lowerList = AppList.GetAppsLowerList().ToList();
290 sortList = FooterNormal.GetSortDropdownList();
292 foreach (var item in lowerList)
294 Button button = item.FindByName<Button>("ButtonFocusArea");
295 button?.On<Tizen>()?.SetNextFocusDownView(sortList);
299 private void SetFocusChainingUpAndDownForDeleteMode()
301 List<View> lowerList = AppList.GetAppsLowerList().ToList();
302 cancelButton = FooterDelete.GetCancelButton();
304 foreach (var item in lowerList)
306 Button button = item.FindByName<Button>("ButtonFocusArea");
307 button?.On<Tizen>()?.SetNextFocusDownView(cancelButton);
310 if (lowerList.Count > 0)
312 cancelButton?.On<Tizen>()?.SetNextFocusUpView(lowerList[lowerList.Count - 1].FindByName<Button>("ButtonFocusArea"));
315 cancelButton?.On<Tizen>()?.SetNextFocusLeftView(cancelButton);
318 private void SetFocusChainingUpAndDownForPinMode()
320 List<View> lowerList = AppList.GetAppsLowerList().ToList();
321 doneButton = FooterPin.GetDoneButton();
323 foreach (var item in lowerList)
325 Button button = item.FindByName<Button>("ButtonFocusArea");
326 button?.On<Tizen>()?.SetNextFocusDownView(doneButton);
329 if (lowerList.Count > 0 )
331 doneButton?.On<Tizen>()?.SetNextFocusUpView(lowerList[lowerList.Count - 1].FindByName<Button>("ButtonFocusArea"));
334 doneButton?.On<Tizen>()?.SetNextFocusLeftView(doneButton);
337 private void SetFocusChainingWithCurrentStatus(AppsStatus status)
341 case AppsStatus.Default:
342 SetFocusChainingUpAndDownForDefaultMode();
345 SetFocusChainingUpAndDownForPinMode();
347 case AppsStatus.Delete:
348 SetFocusChainingUpAndDownForDeleteMode();
350 case AppsStatus.LongPress:
351 SetFocusChainingUpAndDownForDefaultMode();
357 /// A method sets current status of MainPage
358 /// Changes visibility of footers
360 /// <param name="status">The next status name</param>
361 private void SetCurrentStatus(AppsStatus status)
365 case AppsStatus.Default:
366 FooterNormal.IsVisible = true;
367 FooterPin.IsVisible = false;
368 FooterDelete.IsVisible = false;
369 BackKeyInfo.Text = "Quit";
370 AddtionalInfo.IsVisible = false;
371 TitleLabel.IsVisible = true;
372 AppList.InitializeFocus();
375 FooterNormal.IsVisible = false;
376 FooterPin.IsVisible = true;
377 FooterDelete.IsVisible = false;
378 BackKeyInfo.Text = "Front";
380 case AppsStatus.Delete:
381 FooterNormal.IsVisible = false;
382 FooterPin.IsVisible = false;
383 FooterDelete.IsVisible = true;
384 BackKeyInfo.Text = "Front";
386 case AppsStatus.LongPress:
387 FooterNormal.IsVisible = true;
388 FooterPin.IsVisible = false;
389 FooterDelete.IsVisible = false;
390 BackKeyInfo.Text = "Front";
398 /// This method is called when the properties of MainPage is changed
399 /// If CurrentStatus is changed, call SetCurrentStatus method
401 /// <param name="sender">The source of the event</param>
402 /// <param name="e">The event that is occurred when property of MainPage is changed</param>
403 private async void MainPagePropertyChanged(object sender, PropertyChangedEventArgs e)
405 if (e.PropertyName.Equals("CurrentStatus"))
407 SetCurrentStatus(CurrentStatus);
409 else if (e.PropertyName.Equals("IsEnabledDeletePopup"))
411 if (IsEnabledDeletePopup)
413 bool answer = await DisplayAlert(DeletePopupAppLabel, "Do you want to delete?", "YES", "NO");
414 Dictionary<string, string> ret = new Dictionary<string, string>();
415 ret.Add("AppLabel", DeletePopupAppLabel);
416 ret.Add("answer", answer ? "yes" : "no");
417 DeletePopupCommand?.Execute(ret);
421 AppList.InitializeFocus();
424 else if (e.PropertyName.Equals("SumOfCheckedApp"))
426 AdditionalInfoText1.Text = SumOfCheckedApp.ToString() + " Apps";
427 AdditionalInfoText2.Text = "Checked";
432 /// A task for handling BackKey event
434 /// <returns>Always returns true</returns>
435 private async Task<bool> OnBackKeyPressedAtMain()
437 if (CurrentStatus != AppsStatus.Default)
439 MessagingCenter.Send<MainPage, string>(this, "ChangeCurrentStatus", AppsStatus.Default.ToString());
443 if (!AppList.IsFirstItemFocused)
445 AppList.InitializeFocus();
449 var answer = await DisplayAlert("QUIT", "Do you want to quit?", "YES", "NO");
453 await Task.Delay(800);
454 AppControlUtils.SelfTerminate();
458 AppList.InitializeFocus();
465 /// This method is called when Back button is pressed
467 /// <returns>Always returns true</returns>
468 /// <see cref="Page.OnBackButtonPressed"/>
469 protected override bool OnBackButtonPressed()
471 if (IsPinAppRequested)
476 SynchronizationContext.Current.Post(async (o) =>
478 await OnBackKeyPressedAtMain();