This blog post is an addendum to the article, Build a Xamarin App with Authentication and Offline Support, to be published in MSDN Magazine, September 2015. I'll update this post with a link once the article is available. Part 1, Cloud-Connected Mobile Apps – Create a Web Service with Azure Web Apps and WebJobs, which discusses the backend of the project, is available now.
As promised, there are a few points of interest in the app that have not been discussed previously.
First, we implemented some niceties for displaying items both in the home page list and on the item page:
When processing data from the backend in DataModel.ProcessItems, the app generates a description from the first 100 characters of the body. Because that body is typically HTML and the description is plain text, we use a one-line regular expression replacement to do a quick strip of the tags (this is the private function StripHTML in sync.cs):
Regex.Replace(source, "<[^>]*>", string.Empty).Replace("n", " ");
Similarly, we noticed during testing that item titles can have smart quotes in them, but the text field in the ListView control will display their escape sequence instead. So another little one-liner (CleanEscapes in sync.cs) takes care of this:
source.Replace("'", """).Replace(""", """);
The item page displays the name of the item’s source (such as StackOverflow or Twitter), and to make it easy to go to that source directly the ItemPage constructor makes it a hyperlink with the following code:
Command = new Command (() =>
It’s also very likely that the item’s HTML displayed in the ItemPage’s WebView will contain hyperlinks. Left to themselves, these hyperlinks will cause navigation within the WebView, but because there are no navigation controls the user wouldn’t be able to return to the item itself. To prevent this, the following code redirects navigations within the WebView to the default browser. The trick (mentioned in Altostratus Extra #1) is that the exact behavior of the WebView varies by platform: on iOS and Windows Phone, a Navigating event will be raised when the webview is first loaded with content from the app, whereas on Android you get the event only for navigations within the WebView once it’s loaded. We thus use Device.OnPlatform to initialize a flag that says whether to ignore the first event:
private Boolean navigateToBrowser = Device.OnPlatform<Boolean>(false, true, false);
wv.Navigating += (Object sender, WebNavigatingEventArgs e) =>
e.Cancel = true;
navigateToBrowser = true;
And second, although we wanted a change of configuration to trigger a sync with the backend, we obviously don’t want to do this with every UI activity in the configuration page. Instead, a sync should only be triggered if the user actually changes something in the configuration when they return to the home page.
To implement this, the UserPreferences class in the data model, which matches the data exchanged with the backend, supports cloning an instance (its Clone method) and comparing to another instance (its IsEqual method). The Configuration page uses these within its OnAppearing and OnDisappearing events to have the data model refresh itself if the user made changes when they return to the home page. This way, the user could toggle categories, change the conversation limit, and even log in and log off again, but if ultimately the user returns to the home page with exactly the same configuration, nothing needs to happen in the data model or the home page UI.