WeatherInformation WP8: MainPage with progress bar.
[CSharpForFun/.git] / WindowsPhone / WP8 / WeatherInformation / WeatherInformation / MainPage.xaml.cs
1 using Microsoft.Phone.Controls;
2 using System;
3 using System.Linq;
4 using System.Globalization;
5 using System.Windows;
6 using System.Windows.Controls;
7 using System.Windows.Navigation;
8 using WeatherInformation.Model;
9 using WeatherInformation.Model.Services;
10 using WeatherInformation.Resources;
11 using WeatherInformation.ViewModels;
12 using System.Threading.Tasks;
13 using WeatherInformation.Model.JsonDataParser;
14
15 namespace WeatherInformation
16 {
17     public partial class MainPage : PhoneApplicationPage
18     {
19         private MainViewModel _mainViewModel;
20         private bool _isNewPageInstance = false;
21
22         // Constructor
23         public MainPage()
24         {
25             InitializeComponent();
26
27             _isNewPageInstance = true;
28
29             // Código de ejemplo para traducir ApplicationBar
30             //BuildLocalizedApplicationBar();
31         }
32
33
34         // Cargar datos para los elementos MainViewModel
35         protected override void OnNavigatedTo(NavigationEventArgs e)
36         {
37             base.OnNavigatedTo(e);
38
39             // If _isNewPageInstance is true, the page constuctor has been called, so
40             // state may need to be restored.
41             if (_isNewPageInstance)
42             {
43                 if (_mainViewModel == null)
44                 {
45                     _mainViewModel = new MainViewModel(new SettingsViewModel());
46                 }
47
48                 DataContext = _mainViewModel;
49             }
50             // Set _isNewPageInstance to false. If the user navigates back to this page
51             // and it has remained in memory, this value will continue to be false.
52             _isNewPageInstance = false;
53
54             UpdateApplicationDataUI();
55         }
56
57         async private void UpdateApplicationDataUI()
58         {
59             Location locationItem = null;
60             using (var db = new LocationDataContext(LocationDataContext.DBConnectionString))
61             {
62                 locationItem = db.Locations.Where(location => location.IsSelected).FirstOrDefault();
63             }
64
65             // Empty UI
66             this.CurrentData.Visibility = Visibility.Collapsed;
67             this.ForecastData.Visibility = Visibility.Collapsed;
68             this.ProgressBarRemoteData.Visibility = Visibility.Collapsed;
69             this.NoDataAvailable.Visibility = Visibility.Collapsed;
70
71             if (locationItem == null)
72             {
73                 // Nothing to do.
74                 // Show error message.
75                 this.CurrentData.Visibility = Visibility.Collapsed;
76                 this.ForecastData.Visibility = Visibility.Collapsed;
77                 this.ProgressBarRemoteData.Visibility = Visibility.Collapsed;
78                 this.NoDataAvailable.Visibility = Visibility.Visible;
79                 return;
80             }
81
82             // If the application member variable is not empty,
83             // set the page's data object from the application member variable.
84             WeatherData weatherData = (Application.Current as WeatherInformation.App).ApplicationDataObject;
85             if (!IsDataFresh(locationItem.LastRemoteDataUpdate) || weatherData == null)
86             {
87                 // Gets the data from the web.
88                 this.CurrentData.Visibility = Visibility.Collapsed;
89                 this.ForecastData.Visibility = Visibility.Collapsed;
90                 this.ProgressBarRemoteData.Visibility = Visibility.Visible;
91                 this.NoDataAvailable.Visibility = Visibility.Collapsed;
92
93                 await GetRemoteDataAndUpdateUI(locationItem);
94             }
95             else
96             {
97                 this.CurrentData.Visibility = Visibility.Visible;
98                 this.ForecastData.Visibility = Visibility.Visible;
99                 this.ProgressBarRemoteData.Visibility = Visibility.Collapsed;
100                 this.NoDataAvailable.Visibility = Visibility.Collapsed;
101
102                 UpdateUI(weatherData);
103             }
104         }
105
106         private void UpdateUI(WeatherData weatherData)
107         {
108             if (weatherData != null)
109             {
110                 _mainViewModel.LoadData(weatherData);
111             }
112         }
113
114         async private Task GetRemoteDataAndUpdateUI(Location locationItem)
115         {
116             // Load remote data (aynchronous way by means of async/await)
117             try
118             {
119                 // Without ConfigureAwait(false) await returns data on the calling thread.
120                 WeatherData weatherData = await GetRemoteDataAsync(locationItem);
121
122                 this.CurrentData.Visibility = Visibility.Visible;
123                 this.ForecastData.Visibility = Visibility.Visible;
124                 this.ProgressBarRemoteData.Visibility = Visibility.Collapsed;
125                 this.NoDataAvailable.Visibility = Visibility.Collapsed;
126
127                 UpdateUI(weatherData);
128
129                 (Application.Current as WeatherInformation.App).ApplicationDataObject = weatherData;
130
131                 using (var db = new LocationDataContext(LocationDataContext.DBConnectionString))
132                 {
133                     locationItem = db.Locations.Where(location => location.IsSelected).FirstOrDefault();
134                     locationItem.LastRemoteDataUpdate = DateTime.UtcNow;
135                     db.SubmitChanges();
136                 }
137             }
138             catch(Exception e)
139             {
140                 // Empty UI and show error message
141                 this.CurrentData.Visibility = Visibility.Collapsed;
142                 this.ForecastData.Visibility = Visibility.Collapsed;
143                 this.ProgressBarRemoteData.Visibility = Visibility.Collapsed;
144                 this.NoDataAvailable.Visibility = Visibility.Visible;
145             }
146
147         }
148
149         private void LongListSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
150         {
151             LongListSelector longListSelector = sender as LongListSelector;
152
153             // TODO: with LINQ :(
154             ItemViewModel element = longListSelector.SelectedItem as ItemViewModel;
155             int index = longListSelector.ItemsSource.IndexOf(element);
156             String uri = string.Format(CultureInfo.InvariantCulture, "/SelectedDatePage.xaml?parameter={0}", index);
157             NavigationService.Navigate(new Uri(uri, UriKind.Relative));
158         }
159
160         /// <summary>
161         /// Retrieve remote weather data.
162         /// </summary>
163         async public Task<WeatherData> GetRemoteDataAsync(Location locationItem)
164         {
165             double latitude = locationItem.Latitude;
166             double longitude = locationItem.Longitude;
167             int resultsNumber = Convert.ToInt32(AppResources.APIOpenWeatherMapResultsNumber);
168
169             CustomHTTPClient httpClient = new CustomHTTPClient();
170
171             string formattedForecastURL = String.Format(
172                 CultureInfo.InvariantCulture, AppResources.URIAPIOpenWeatherMapForecast,
173                 AppResources.APIVersionOpenWeatherMap, latitude, longitude, resultsNumber);
174             string jsonForecast = await httpClient.GetWeatherDataAsync(formattedForecastURL).ConfigureAwait(false);
175
176             string formattedCurrentURL = String.Format(
177                 CultureInfo.InvariantCulture, AppResources.URIAPIOpenWeatherMapCurrent,
178                 AppResources.APIVersionOpenWeatherMap, latitude, longitude, resultsNumber);
179             string jsonCurrent = await httpClient.GetWeatherDataAsync(formattedCurrentURL).ConfigureAwait(false);
180
181             var parser = new ServiceParser(new JsonParser());
182             var weatherData = parser.WeatherDataParser(jsonForecast, jsonCurrent, locationItem.City, locationItem.Country);
183
184             return weatherData;
185         }
186
187         private bool IsDataFresh(DateTime? lastUpdate)
188         {
189             if (lastUpdate == null)
190             {
191                 return false;
192             }
193
194             // Check the time elapsed since data was last saved to isolated storage.
195             TimeSpan TimeSinceLastSave = DateTime.UtcNow - lastUpdate.Value;
196
197             if (TimeSinceLastSave.TotalSeconds < 30)
198             {
199                 return true;
200             }
201
202             return false;
203         }
204
205         private void Location_Click(object sender, EventArgs e)
206         {
207             NavigationService.Navigate(new Uri("/MapPage.xaml", UriKind.Relative));
208         }
209
210         private void Settings_Click(object sender, EventArgs e)
211         {
212             NavigationService.Navigate(new Uri("/SettingsPage.xaml", UriKind.Relative));
213         }
214
215         // Código de ejemplo para compilar una ApplicationBar traducida
216         //private void BuildLocalizedApplicationBar()
217         //{
218         //    // Establecer ApplicationBar de la página en una nueva instancia de ApplicationBar.
219         //    ApplicationBar = new ApplicationBar();
220
221         //    // Crear un nuevo botón y establecer el valor de texto en la cadena traducida de AppResources.
222         //    ApplicationBarIconButton appBarButton = new ApplicationBarIconButton(new Uri("/Assets/AppBar/appbar.add.rest.png", UriKind.Relative));
223         //    appBarButton.Text = AppResources.AppBarButtonText;
224         //    ApplicationBar.Buttons.Add(appBarButton);
225
226         //    // Crear un nuevo elemento de menú con la cadena traducida de AppResources.
227         //    ApplicationBarMenuItem appBarMenuItem = new ApplicationBarMenuItem(AppResources.AppBarMenuItemText);
228         //    ApplicationBar.MenuItems.Add(appBarMenuItem);
229         //}
230     }
231 }