From cb08471c057e78d278891f08d03bc4aa41fe4d0d Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Tue, 23 Dec 2014 01:29:17 +0300 Subject: Fast resume --- Juick/App.xaml.cs | 124 +++++++++++++++++++++++++++++++++++++- Juick/Classes/MyUriMapper.cs | 35 +++++++++++ Juick/MainPage.xaml.cs | 31 +--------- Juick/ViewModels/AppViewModel.cs | 1 + Juick/ViewModels/PageViewModel.cs | 4 ++ 5 files changed, 165 insertions(+), 30 deletions(-) create mode 100644 Juick/Classes/MyUriMapper.cs diff --git a/Juick/App.xaml.cs b/Juick/App.xaml.cs index 03e0d10..1e91f38 100644 --- a/Juick/App.xaml.cs +++ b/Juick/App.xaml.cs @@ -95,13 +95,17 @@ namespace Juick null, "/ApplicationWideTile.png", null); + RootFrame.UriMapper = new MyUriMapper(); } // Code to execute when the application is activated (brought to foreground) // This code will not execute when the application is first launched private void Application_Activated(object sender, ActivatedEventArgs e) { - // Ensure that application state is restored appropriately + if (e.IsApplicationInstancePreserved == false) + { + RootFrame.UriMapper = new MyUriMapper(); + } } // Code to execute when the application is deactivated (sent to background) @@ -139,9 +143,26 @@ namespace Juick #region Phone application initialization + public enum SessionType + { + None, + Home, + DeepLink + } + // Avoid double-initialization private bool phoneApplicationInitialized = false; + // Set to Home when the app is launched from Primary tile. + // Set to DeepLink when the app is launched from Deep Link. + private SessionType _sessionType = SessionType.None; + + // Set to true when the page navigation is being reset + private bool _wasRelaunched = false; + + // set to true when 5 min passed since the app was relaunched + private bool _mustClearPagestack = false; + // Do not add any additional code to this method private void InitializePhoneApplication() { @@ -156,10 +177,87 @@ namespace Juick // Handle navigation failures RootFrame.NavigationFailed += RootFrame_NavigationFailed; + RootFrame.Navigated += CheckForResetNavigation; + + RootFrame.Navigating += RootFrame_Navigating; + + RootFrame.UriMapper = new MyUriMapper(); + // Ensure we don't initialize again phoneApplicationInitialized = true; } + void RootFrame_Navigating(object sender, NavigatingCancelEventArgs e) + { + // If the session type is None or New, check the navigation Uri to determine if the + // navigation is a deep link or if it points to the app's main page. + if (_sessionType == SessionType.None && e.NavigationMode == NavigationMode.New) + { + // This block will run if the current navigation is part of the app's intial launch + + + // Keep track of Session Type + if (e.Uri.ToString().Contains("DeepLink=true")) + { + _sessionType = SessionType.DeepLink; + } + else if (e.Uri.ToString().Contains("/MainPage.xaml")) + { + _sessionType = SessionType.Home; + } + } + + + + if (e.NavigationMode == NavigationMode.Reset) + { + // This block will execute if the current navigation is a relaunch. + // If so, another navigation will be coming, so this records that a relaunch just happened + // so that the next navigation can use this info. + _wasRelaunched = true; + } + else if (e.NavigationMode == NavigationMode.New && _wasRelaunched) + { + // This block will run if the previous navigation was a relaunch + _wasRelaunched = false; + + if (e.Uri.ToString().Contains("ShareContent") || e.Uri.ToString().Contains("mid")) + { + // This block will run if the launch Uri contains "DeepLink=true" which + // was specified when the secondary tile was created in MainPage.xaml.cs + + _sessionType = SessionType.DeepLink; + // The app was relaunched via a Deep Link. + // The page stack will be cleared. + } + else if (e.Uri.OriginalString.Contains("/MainPage.xaml")) + { + // This block will run if the navigation Uri is the main page + if (_sessionType == SessionType.DeepLink) + { + // When the app was previously launched via Deep Link and relaunched via Main Tile, we need to clear the page stack. + _sessionType = SessionType.Home; + } + else + { + if (!_mustClearPagestack) + { + //The app was previously launched via Main Tile and relaunched via Main Tile. Cancel the navigation to resume. + e.Cancel = true; + RootFrame.Navigated -= ClearBackStackAfterReset; + } + } + } + + _mustClearPagestack = false; + } + else if (e.NavigationMode == NavigationMode.New && !_wasRelaunched && e.Uri.ToString().Contains("/MainPage.xaml")) + { + // Home button: Any time we do a forward nav to "MainPage" we assume it's from the Home button, so we clear the backstack + RootFrame.Navigated += ClearBackStackAfterReset; + } + } + // Do not add any additional code to this method private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e) { @@ -171,6 +269,30 @@ namespace Juick RootFrame.Navigated -= CompleteInitializePhoneApplication; } + private void CheckForResetNavigation(object sender, NavigationEventArgs e) + { + // If the app has received a 'reset' navigation, then we need to check + // on the next navigation to see if the page stack should be reset + if (e.NavigationMode == NavigationMode.Reset) + RootFrame.Navigated += ClearBackStackAfterReset; + } + + private void ClearBackStackAfterReset(object sender, NavigationEventArgs e) + { + // Unregister the event so it doesn't get called again + RootFrame.Navigated -= ClearBackStackAfterReset; + + // Only clear the stack for 'new' (forward) and 'refresh' navigations + if (e.NavigationMode != NavigationMode.New) + return; + + // For UI consistency, clear the entire page stack + while (RootFrame.RemoveBackEntry() != null) + { + ; // do nothing + } + } + #endregion } } \ No newline at end of file diff --git a/Juick/Classes/MyUriMapper.cs b/Juick/Classes/MyUriMapper.cs new file mode 100644 index 0000000..4f757a5 --- /dev/null +++ b/Juick/Classes/MyUriMapper.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Navigation; + +namespace Juick.Classes +{ + public class MyUriMapper : UriMapperBase + { + public override Uri MapUri(Uri uri) + { + string tempUri = uri.OriginalString; + string mappedUri; + + // Launch from the photo share picker. + // Incoming URI example: /MainPage.xaml?Action=ShareContent&FileId=%7BA3D54E2D-7977-4E2B-B92D-3EB126E5D168%7D + if ((tempUri.Contains("ShareContent")) && (tempUri.Contains("FileId"))) + { + mappedUri = tempUri.Replace("MainPage", "NewPostView"); + return new Uri(mappedUri, UriKind.Relative); + } + + if (!App.AppContext.Account.IsAuthenticated) + { + mappedUri = tempUri.Replace("MainPage", "LoginView"); + return new Uri(mappedUri, UriKind.Relative); + } + + // Otherwise perform normal launch. + return uri; + } + } +} diff --git a/Juick/MainPage.xaml.cs b/Juick/MainPage.xaml.cs index edf2d3b..4da88ec 100644 --- a/Juick/MainPage.xaml.cs +++ b/Juick/MainPage.xaml.cs @@ -52,35 +52,8 @@ namespace Juick } protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) - { - var loginUriPart = "/LoginView.xaml"; - var newPostUriPart = "/NewPostView.xaml"; - var navigateUri = string.Empty; - var FileId = string.Empty; - // Get a dictionary of query string keys and values. - IDictionary queryStrings = NavigationContext.QueryString; - - // Ensure that there is at least one key in the query string, and check - // whether the "FileId" key is present. - - navigateUri = App.AppContext.Account.IsAuthenticated ? newPostUriPart : loginUriPart; - if (queryStrings.ContainsKey("FileId")) - { - FileId = queryStrings["FileId"]; - navigateUri = string.Format("{0}?FileId={1}", navigateUri, FileId); - } - if (!string.IsNullOrEmpty(FileId) || navigateUri.StartsWith(loginUriPart)) - { - ((App)Application.Current).NavigateTo(new Uri(navigateUri, UriKind.Relative), true); - } - if (queryStrings.ContainsKey("mid")) - { - var mid = queryStrings["mid"]; - navigateUri = string.Format("/ThreadView.xaml?mid={0}", mid); - ((App)Application.Current).NavigateTo(new Uri(navigateUri, UriKind.Relative), true); - } - App.AppContext.Client.Authenticator = new HttpBasicAuthenticator(App.AppContext.Account.UserName, App.AppContext.Account.Password); - + { + App.AppContext.Client.Authenticator = new HttpBasicAuthenticator(App.AppContext.Account.UserName, App.AppContext.Account.Password); } diff --git a/Juick/ViewModels/AppViewModel.cs b/Juick/ViewModels/AppViewModel.cs index ba33625..4aa9321 100644 --- a/Juick/ViewModels/AppViewModel.cs +++ b/Juick/ViewModels/AppViewModel.cs @@ -162,6 +162,7 @@ namespace Juick.ViewModels public void EnableNotifications() { if (!Account.IsAuthenticated) return; + if (pushChannel.ChannelUri == null) return; var channelUri = pushChannel.ChannelUri.ToString(); if (channelUri == Account.NotificationUri) return; diff --git a/Juick/ViewModels/PageViewModel.cs b/Juick/ViewModels/PageViewModel.cs index 9781a9e..c13e6f1 100644 --- a/Juick/ViewModels/PageViewModel.cs +++ b/Juick/ViewModels/PageViewModel.cs @@ -73,6 +73,10 @@ namespace Juick.ViewModels _context.Client.ExecuteAsync>(request, response => { _context.IsDataLoading = false; + if (response.ErrorException != null) + { + return; + } if (response.Data == null) return; response.Data.Select(x => new PostItem(x)).ToList().ForEach(i => Items.Add(i)); -- cgit v1.2.3