Prechádzať zdrojové kódy

Added other projext files as template

Kenneth van Ewijk 10 rokov pred
rodič
commit
7f8533005e

+ 13 - 2
YJMPD-UWP/App.xaml

@@ -2,7 +2,18 @@
     x:Class="YJMPD_UWP.App"
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
-    xmlns:local="using:YJMPD_UWP"
-    RequestedTheme="Light">
+    xmlns:local="using:YJMPD_UWP">
+
+    <Application.Resources>
+        <ResourceDictionary>
+            <ResourceDictionary.ThemeDictionaries>
+                <ResourceDictionary x:Key="Dark" Source="Themes/DarkTheme.xaml"/>
+                <ResourceDictionary x:Key="Light" Source="Themes/LightTheme.xaml"/>
+            </ResourceDictionary.ThemeDictionaries>
+            <ResourceDictionary.MergedDictionaries>
+                <ResourceDictionary Source="Themes/DefaultStyles.xaml"/>
+            </ResourceDictionary.MergedDictionaries>
+        </ResourceDictionary>
+    </Application.Resources>
 
 </Application>

+ 78 - 15
YJMPD-UWP/App.xaml.cs

@@ -1,27 +1,88 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Runtime.InteropServices.WindowsRuntime;
+using YJMPD_UWP.Model;
+using System;
 using Windows.ApplicationModel;
 using Windows.ApplicationModel.Activation;
 using Windows.Foundation;
-using Windows.Foundation.Collections;
+using Windows.Globalization;
+using Windows.Graphics.Display;
+using Windows.UI.Core;
+using Windows.UI.ViewManagement;
 using Windows.UI.Xaml;
 using Windows.UI.Xaml.Controls;
-using Windows.UI.Xaml.Controls.Primitives;
-using Windows.UI.Xaml.Data;
-using Windows.UI.Xaml.Input;
-using Windows.UI.Xaml.Media;
 using Windows.UI.Xaml.Navigation;
 
 namespace YJMPD_UWP
 {
-    /// <summary>
-    /// Provides application-specific behavior to supplement the default Application class.
-    /// </summary>
     sealed partial class App : Application
     {
+
+        public static Frame rootFrame;
+
+
+        // =======================
+        //      SINGLETONS
+        // =======================
+        private static GeoTracker geo = new GeoTracker();
+
+        public static GeoTracker Geo
+        {
+            get
+            {
+                return geo;
+            }
+        }
+
+        private static CompassTracker cm = new CompassTracker();
+
+        public static CompassTracker CompassTracker
+        {
+            get
+            {
+                return cm;
+            }
+        }
+
+        public static CoreDispatcher Dispatcher
+        {
+            get
+            {
+                return Windows.UI.Core.CoreWindow.GetForCurrentThread().Dispatcher;
+            }
+        }
+
+
+        // =========================
+        // STATIC HELPER FUNCTIONS
+        // =========================
+
+        public static Size ScreenSize
+        {
+            get
+            {
+                var bounds = ApplicationView.GetForCurrentView().VisibleBounds;
+                var scaleFactor = DisplayInformation.GetForCurrentView().RawPixelsPerViewPixel;
+                Size size = new Size(bounds.Width * scaleFactor, bounds.Height * scaleFactor);
+                return size;
+            }
+        }
+
+        public static MainPage MainPage
+        {
+            get
+            {
+                Frame f = Window.Current.Content as Frame;
+                MainPage mp = f.Content as MainPage;
+                return mp;
+            }
+        }
+
+
+
+        // ===============================
+        // NORMAL STUFF
+        // ===============================
+
+
         /// <summary>
         /// Initializes the singleton application object.  This is the first line of authored code
         /// executed, and as such is the logical equivalent of main() or WinMain().
@@ -29,6 +90,7 @@ namespace YJMPD_UWP
         public App()
         {
             this.InitializeComponent();
+
             this.Suspending += OnSuspending;
         }
 
@@ -43,11 +105,11 @@ namespace YJMPD_UWP
 #if DEBUG
             if (System.Diagnostics.Debugger.IsAttached)
             {
-                this.DebugSettings.EnableFrameRateCounter = true;
+                this.DebugSettings.EnableFrameRateCounter = false;
             }
 #endif
 
-            Frame rootFrame = Window.Current.Content as Frame;
+            rootFrame = Window.Current.Content as Frame;
 
             // Do not repeat app initialization when the Window already has content,
             // just ensure that the window is active
@@ -74,6 +136,7 @@ namespace YJMPD_UWP
                 // parameter
                 rootFrame.Navigate(typeof(MainPage), e.Arguments);
             }
+
             // Ensure the current window is active
             Window.Current.Activate();
         }

+ 17 - 0
YJMPD-UWP/Helpers/Extensions.cs

@@ -0,0 +1,17 @@
+using Newtonsoft.Json.Linq;
+using System;
+
+namespace YJMPD_UWP.Helpers
+{
+    public static class Extensions
+    {
+        public static bool NullOrEmpty(this JToken token)
+        {
+            return (token == null) ||
+                   (token.Type == JTokenType.Array && !token.HasValues) ||
+                   (token.Type == JTokenType.Object && !token.HasValues) ||
+                   (token.Type == JTokenType.String && token.ToString() == String.Empty) ||
+                   (token.Type == JTokenType.Null);
+        }
+    }
+}

+ 45 - 0
YJMPD-UWP/Helpers/Settings.cs

@@ -0,0 +1,45 @@
+using System;
+using System.Threading.Tasks;
+using Windows.Globalization;
+using Windows.Storage;
+
+namespace YJMPD_UWP.Helpers
+{
+    static class Settings
+    {
+        private static ApplicationDataContainer LOCAL_SETTINGS = ApplicationData.Current.LocalSettings;
+
+        public delegate void OnLanguageUpdateHandler(EventArgs e);
+        public static event OnLanguageUpdateHandler OnLanguageUpdate;
+
+        public static bool Tracking
+        {
+            get
+            {
+                return (bool)LOCAL_SETTINGS.Values["tracking"];
+            }
+            set
+            {
+                LOCAL_SETTINGS.Values["tracking"] = value;
+            }
+        }
+
+        static Settings()
+        {
+            LOCAL_SETTINGS.Values["tracking"] = true;
+
+            if (CurrentLanguage == "")
+                ApplicationLanguages.PrimaryLanguageOverride = "en";
+        }
+
+        public static async void ChangeLanguage(string lang)
+        {
+            ApplicationLanguages.PrimaryLanguageOverride = lang;
+            await Task.Delay(TimeSpan.FromMilliseconds(100));
+            //App.rootFrame.Navigate(typeof(MainPage));
+            OnLanguageUpdate(new EventArgs());
+        }
+
+        public static string CurrentLanguage { get { return ApplicationLanguages.PrimaryLanguageOverride; } }
+    }
+}

+ 269 - 0
YJMPD-UWP/Helpers/Util.cs

@@ -0,0 +1,269 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Windows.ApplicationModel.Resources;
+using Windows.Data.Xml.Dom;
+using Windows.Devices.Geolocation;
+using Windows.Services.Maps;
+using Windows.UI;
+using Windows.UI.Notifications;
+using Windows.UI.Popups;
+using Windows.UI.Xaml.Controls.Maps;
+
+namespace YJMPD_UWP.Helpers
+{
+    class Util
+    {
+        public enum DialogType { YESNO, OKCANCEL }
+
+        public static ResourceLoader Loader
+        {
+            get
+            {
+                return new Windows.ApplicationModel.Resources.ResourceLoader();
+            }
+        }
+
+        public static double Now { get { return (DateTime.Now - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds; } }
+
+        public static string MillisecondsToTime(double millis)
+        {
+            DateTime time = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+            string timestr = time.AddMilliseconds(millis) + "";
+            return timestr;
+        }
+
+        public static async Task<Geopoint> FindLocation(string location, Geopoint reference)
+        {
+            MapLocationFinderResult result = await MapLocationFinder.FindLocationsAsync(location, reference);
+            MapLocation from = result.Locations.FirstOrDefault();
+            Geopoint p = from.Point;
+            return p;
+        }
+
+        public static async Task<MapRoute> FindWalkingRoute(Geopoint from, Geopoint to)
+        {
+            MapRouteFinderResult routeResult = await MapRouteFinder.GetWalkingRouteAsync(from, to);
+            MapRoute b = routeResult.Route;
+            return b;
+        }
+
+        public static async Task<MapRoute> FindWalkingRoute(List<Geopoint> points)
+        {
+            MapRouteFinderResult routeResult = await MapRouteFinder.GetWalkingRouteFromWaypointsAsync(points);
+            MapRoute b = routeResult.Route;
+            return b;
+        }
+
+        public static async Task<MapRoute> FindWalkingRoute(string from, string to, Geopoint reference)
+        {
+            Geopoint f = await FindLocation(from, reference);
+            Geopoint t = await FindLocation(to, reference);
+            MapRoute m = await FindWalkingRoute(f, t);
+            return m;
+        }
+
+        public static async Task<String> FindAddress(Geopoint p)
+        {
+            // Reverse geocode the specified geographic location.
+            MapLocationFinderResult result =
+                await MapLocationFinder.FindLocationsAtAsync(p);
+
+            string returnstring = "";
+
+            // If the query returns results, display the name of the town
+            // contained in the address of the first result.
+            if (result.Status == MapLocationFinderStatus.Success)
+            {
+                MapAddress address = result.Locations[0].Address;
+
+                //returnstring = address.Street + " " + address.StreetNumber + ", " + address.Town;
+                returnstring += (address.BuildingName == "" ? "" : address.BuildingName + ", ");
+                returnstring += (address.Street == "" ? "" : address.Street + (address.StreetNumber == "" ? ", " : " " + address.StreetNumber + ", "));
+                returnstring += address.Town;
+            }
+
+            return returnstring;
+        }
+
+        public static async Task<String> FindAddress(double latitude, double longitude)
+        {
+            Geopoint p = new Geopoint(new BasicGeoposition() { Latitude = latitude, Longitude = longitude });
+            string address = await FindAddress(p);
+            return address;
+        }
+
+        public static MapPolyline GetRouteLine(MapRoute m, Color color, int zindex, int thickness = 5)
+        {
+            var line = new MapPolyline
+            {
+                StrokeThickness = thickness,
+                StrokeColor = color,
+                StrokeDashed = false,
+                ZIndex = zindex
+            };
+
+            if (m != null)
+                line.Path = new Geopath(m.Path.Positions);
+
+            return line;
+        }
+
+        public static MapPolyline GetRouteLine(List<BasicGeoposition> positions, Color color, int zindex, int thickness = 5)
+        {
+            var line = new MapPolyline
+            {
+                StrokeThickness = thickness,
+                StrokeColor = color,
+                StrokeDashed = false,
+                ZIndex = zindex
+            };
+
+            line.Path = new Geopath(positions);
+
+            return line;
+        }
+
+        public static MapPolyline GetRouteLine(BasicGeoposition p1, BasicGeoposition p2, Color color, int zindex, int thickness = 5)
+        {
+            var line = new MapPolyline
+            {
+                StrokeThickness = thickness,
+                StrokeColor = color,
+                StrokeDashed = false,
+                ZIndex = zindex
+            };
+
+            List<BasicGeoposition> plist = new List<BasicGeoposition>();
+            plist.Add(p1);
+            plist.Add(p2);
+
+            line.Path = new Geopath(plist);
+
+            return line;
+        }
+
+        public static void ShowToastNotification(string title, string text)
+        {
+            ToastTemplateType toastTemplate = ToastTemplateType.ToastText02;
+            XmlDocument toastXml = ToastNotificationManager.GetTemplateContent(toastTemplate);
+
+            XmlNodeList toastTextElements = toastXml.GetElementsByTagName("text");
+            toastTextElements[0].AppendChild(toastXml.CreateTextNode(title));
+            toastTextElements[1].AppendChild(toastXml.CreateTextNode(text));
+
+            IXmlNode toastNode = toastXml.SelectSingleNode("/toast");
+            XmlElement audio = toastXml.CreateElement("audio");
+
+            audio.SetAttribute("src", "ms-winsoundevent:Notification.IM");
+
+            toastNode.AppendChild(audio);
+
+            ToastNotification toast = new ToastNotification(toastXml);
+            ToastNotificationManager.CreateToastNotifier().Show(toast);
+        }
+
+        public static async Task<bool> ShowConfirmDialog(string title, string content, DialogType type)
+        {
+            MessageDialog dlg = new MessageDialog(content, title);
+            if (type == DialogType.YESNO)
+            {
+                dlg.Commands.Add(new UICommand(Util.Loader.GetString("Yes")) { Id = 0 });
+                dlg.Commands.Add(new UICommand(Util.Loader.GetString("No")) { Id = 1 });
+            }
+            else if (type == DialogType.OKCANCEL)
+            {
+                dlg.Commands.Add(new UICommand(Util.Loader.GetString("Ok")) { Id = 0 });
+                dlg.Commands.Add(new UICommand(Util.Loader.GetString("Cancel")) { Id = 1 });
+            }
+
+            dlg.DefaultCommandIndex = 0;
+            dlg.CancelCommandIndex = 1;
+
+            var result = await dlg.ShowAsync();
+
+            if ((int)result.Id == 0)
+                return true;
+            else
+                return false;
+        }
+
+        public static string TranslatedManeuver(MapRouteManeuver maneuver, int distance)
+        {
+            string response = "";
+            bool onstreet = false;
+            bool meters = true;
+
+            distance = (int)Math.Round(distance / 5.0) * 5;
+
+            switch (maneuver.Kind)
+            {
+                default:
+                    response = Util.Loader.GetString("RouteSeeMap");
+                    meters = false;
+                    break;
+                case MapRouteManeuverKind.End:
+                    response = Util.Loader.GetString("RouteEnd");
+                    break;
+                case MapRouteManeuverKind.GoStraight:
+                    response = Util.Loader.GetString("RouteGoStraight");
+                    onstreet = true;
+                    break;
+                case MapRouteManeuverKind.None:
+                    response = Util.Loader.GetString("RouteNone");
+                    meters = false;
+                    break;
+                case MapRouteManeuverKind.Start:
+                    response = Util.Loader.GetString("RouteStart");
+                    meters = false;
+                    break;
+                case MapRouteManeuverKind.TurnHardLeft:
+                case MapRouteManeuverKind.TurnLeft:
+                    response = Util.Loader.GetString("RouteLeft");
+                    onstreet = true;
+                    break;
+                case MapRouteManeuverKind.TurnHardRight:
+                case MapRouteManeuverKind.TurnRight:
+                    response = Util.Loader.GetString("RouteRight");
+                    onstreet = true;
+                    break;
+                case MapRouteManeuverKind.TrafficCircleLeft:
+                    response = Util.Loader.GetString("RouteTrafficCircleLeft");
+                    onstreet = true;
+                    break;
+                case MapRouteManeuverKind.TrafficCircleRight:
+                    response = Util.Loader.GetString("RouteTrafficCircleRight");
+                    onstreet = true;
+                    break;
+                case MapRouteManeuverKind.TurnKeepLeft:
+                case MapRouteManeuverKind.TurnLightLeft:
+                    response = Util.Loader.GetString("RouteKeepLeft");
+                    break;
+                case MapRouteManeuverKind.TurnKeepRight:
+                case MapRouteManeuverKind.TurnLightRight:
+                    response = Util.Loader.GetString("RouteKeepRight");
+                    break;
+                case MapRouteManeuverKind.UTurnLeft:
+                case MapRouteManeuverKind.UTurnRight:
+                    response = Util.Loader.GetString("RouteUTurn");
+                    break;
+            }
+
+            if (maneuver.StreetName == "")
+                onstreet = false;
+
+            if (distance < 10)
+                meters = false;
+
+
+            if (onstreet)
+                response += " " + Util.Loader.GetString("RouteOn") + " " + maneuver.StreetName;
+
+            if (meters)
+                response = Util.Loader.GetString("RouteIn") + " " + distance + "m" + " " + response.ToLower();
+
+            return response;
+        }
+    }
+}

+ 144 - 1
YJMPD-UWP/MainPage.xaml

@@ -7,7 +7,150 @@
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
     mc:Ignorable="d">
 
-    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
+    <Page.Resources>
+        <Style x:Key="NavStackPanel" TargetType="StackPanel">
+            <Setter Property="Orientation" Value="Horizontal" />
+            <Setter Property="VerticalAlignment" Value="Center" />
+            <Setter Property="MinWidth" Value="275" />
+        </Style>
 
+        <Style x:Key="NavIcon" TargetType="TextBlock">
+            <Setter Property="FontFamily" Value="Segoe MDL2 Assets" />
+            <Setter Property="FontSize" Value="28" />
+            <Setter Property="Margin" Value="0,5,0,0" />
+        </Style>
+
+        <Style x:Key="NavText" TargetType="TextBlock">
+            <Setter Property="FontSize" Value="28" />
+            <Setter Property="Margin" Value="18,0,0,0" />
+        </Style>
+
+
+        <Style x:Key="GPSInfoPanel" TargetType="StackPanel">
+            <Setter Property="Orientation" Value="Horizontal" />
+            <Setter Property="VerticalAlignment" Value="Center" />
+            <Setter Property="Margin" Value="10,0,10,0" />
+        </Style>
+
+        <Style x:Key="GPSInfoIcon" TargetType="TextBlock">
+            <Setter Property="FontFamily" Value="Segoe MDL2 Assets" />
+            <Setter Property="FontSize" Value="20" />
+            <Setter Property="Margin" Value="5,5,0,0" />
+        </Style>
+
+        <Style x:Key="GPSInfoText" TargetType="TextBlock">
+            <Setter Property="FontSize" Value="20" />
+            <Setter Property="Margin" Value="15,0,0,0" />
+        </Style>
+    </Page.Resources>
+
+    <Grid>
+        <Grid.RowDefinitions>
+            <RowDefinition Height="Auto" />
+            <RowDefinition Height="*" />
+        </Grid.RowDefinitions>
+
+        <RelativePanel Grid.Row="0">
+            <Button RelativePanel.AlignLeftWithPanel="True" Name="NavButton" Click="NavButton_Click" VerticalAlignment="Stretch" FontFamily="Segoe MDL2 Assets" Content="&#xE700;" FontSize="28" />
+
+            <Viewbox RelativePanel.RightOf="NavButton" RelativePanel.AlignBottomWith="NavButton" StretchDirection="DownOnly" Stretch="UniformToFill" Margin="10,0,10,0">
+                <TextBlock FontSize="28" Name="PageTitle" Text="{Binding Map}" />
+            </Viewbox>
+        </RelativePanel>
+
+        <SplitView Grid.Row="1" Name="NavView" DisplayMode="Overlay" OpenPaneLength="275">
+            <SplitView.Pane>
+                <RelativePanel VerticalAlignment="Stretch"
+                      ManipulationMode="TranslateX"
+                      ManipulationCompleted="Pane_ManipulationCompleted" Style="{ThemeResource DarkModeFix}">
+
+                    <Viewbox Stretch="Uniform" StretchDirection="DownOnly" HorizontalAlignment="Stretch" RelativePanel.AlignTopWithPanel="True">
+                        <ListBox SelectionMode="Single" Name="NavList" SelectionChanged="NavList_SelectionChanged" Tapped="NavList_Tapped">
+                            <ListBoxItem Name="NavListMap" ManipulationMode="TranslateX" ManipulationCompleted="Pane_ManipulationCompleted">
+                                <StackPanel Style="{StaticResource NavStackPanel}">
+                                    <TextBlock Style="{StaticResource NavIcon}" Text="&#xE909;"/>
+                                    <TextBlock Style="{StaticResource NavText}" Text="{Binding Map}"/>
+                                </StackPanel>
+                            </ListBoxItem>
+                            <ListBoxItem Name="NavListRoute" ManipulationMode="TranslateX" ManipulationCompleted="Pane_ManipulationCompleted">
+                                <StackPanel Style="{StaticResource NavStackPanel}">
+                                    <TextBlock Style="{StaticResource NavIcon}" Text="&#xE7AD;"/>
+                                    <TextBlock Style="{StaticResource NavText}" Text="{Binding Route}"/>
+                                </StackPanel>
+                            </ListBoxItem>
+                            <ListBoxItem Name="NavListLandmarks" ManipulationMode="TranslateX" ManipulationCompleted="Pane_ManipulationCompleted">
+                                <StackPanel Style="{StaticResource NavStackPanel}">
+                                    <TextBlock Style="{StaticResource NavIcon}" Text="&#xE913;"/>
+                                    <TextBlock Style="{StaticResource NavText}" Text="{Binding Landmarks}" />
+                                </StackPanel>
+                            </ListBoxItem>
+                            <ListBoxItem Name="NavListHelp" ManipulationMode="TranslateX" ManipulationCompleted="Pane_ManipulationCompleted">
+                                <StackPanel Style="{StaticResource NavStackPanel}">
+                                    <TextBlock Style="{StaticResource NavIcon}" Text="&#xE897;"/>
+                                    <TextBlock Style="{StaticResource NavText}" Text="{Binding Help}"/>
+                                </StackPanel>
+                            </ListBoxItem>
+                            <ListBoxItem Name="NavListSearch" ManipulationMode="TranslateX" ManipulationCompleted="Pane_ManipulationCompleted">
+                                <StackPanel Style="{StaticResource NavStackPanel}">
+                                    <TextBlock Style="{StaticResource NavIcon}" Text="&#xE71E;"/>
+                                    <TextBlock Style="{StaticResource NavText}" Text="{Binding Search}"/>
+                                </StackPanel>
+                            </ListBoxItem>
+                            <ListBoxItem Name="NavListSettings" ManipulationMode="TranslateX" ManipulationCompleted="Pane_ManipulationCompleted">
+                                <StackPanel Style="{StaticResource NavStackPanel}">
+                                    <TextBlock Style="{StaticResource NavIcon}" Text="&#xE713;"/>
+                                    <TextBlock Style="{StaticResource NavText}" Text="{Binding Settings}"/>
+                                </StackPanel>
+                            </ListBoxItem>
+                        </ListBox>
+                    </Viewbox>
+                    
+                    <StackPanel RelativePanel.AlignBottomWithPanel="True" RelativePanel.AlignLeftWithPanel="True" RelativePanel.AlignRightWithPanel="True" Background="Transparent" Tapped="GPSRefresh_Tapped">
+                        <StackPanel Style="{StaticResource GPSInfoPanel}">
+                            <TextBlock Margin="5,0,0,0" FontSize="16" FontWeight="Bold" Text="{Binding GPSInfo}"/>
+                        </StackPanel>
+
+                        <StackPanel Style="{StaticResource GPSInfoPanel}" Tapped="GPSRefresh_Tapped">
+                            <TextBlock Style="{StaticResource GPSInfoIcon}" Text="&#xE81D;"/>
+                            <TextBlock Style="{StaticResource GPSInfoText}" Text="{Binding Status}"/>
+                        </StackPanel>
+
+                        <StackPanel Style="{StaticResource GPSInfoPanel}">
+                            <TextBlock Style="{StaticResource GPSInfoIcon}" Text="&#xE774;"/>
+                            <TextBlock Style="{StaticResource GPSInfoText}" Text="{Binding Source}"/>
+                        </StackPanel>
+
+                        <StackPanel Style="{StaticResource GPSInfoPanel}">
+                            <TextBlock Style="{StaticResource GPSInfoIcon}" Text="&#xE707;"/>
+                            <TextBlock Style="{StaticResource GPSInfoText}" Text="{Binding Accuracy}"/>
+                        </StackPanel>
+
+                        <StackPanel Orientation="Horizontal" Margin="15,5">
+                            <TextBlock Text="Nav City Breda @"/>
+                            <TextBlock Text="{Binding Year}" Margin="5,0,0,0" />
+                        </StackPanel>
+
+                    </StackPanel>
+                </RelativePanel>
+            </SplitView.Pane>
+            
+            <SplitView.Content>
+                <Grid>
+                    <Frame Name="Frame"/>
+
+                    <StackPanel ManipulationMode="TranslateX"
+                          ManipulationCompleted="Content_ManipulationCompleted"
+                          Width="10"
+                          Background="Transparent"
+                          HorizontalAlignment="Left"
+                          VerticalAlignment="Stretch">
+                    </StackPanel>
+
+                    <StackPanel Name="BackMessage" Background="LightGray" Opacity="0.7" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Margin="0,0,0,40" Visibility="Collapsed" Height="Auto">
+                        <TextBlock Text="{Binding BackText}" Margin="5" HorizontalAlignment="Center" TextAlignment="Center"/>
+                    </StackPanel>
+                </Grid>
+            </SplitView.Content>
+        </SplitView>
     </Grid>
 </Page>

+ 133 - 14
YJMPD-UWP/MainPage.xaml.cs

@@ -1,30 +1,149 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
+using YJMPD_UWP.Helpers;
+using YJMPD_UWP.ViewModels;
+using YJMPD_UWP.Views;
+using System;
 using System.Linq;
-using System.Runtime.InteropServices.WindowsRuntime;
-using Windows.Foundation;
-using Windows.Foundation.Collections;
+using System.Threading.Tasks;
+using Windows.UI.Core;
 using Windows.UI.Xaml;
 using Windows.UI.Xaml.Controls;
-using Windows.UI.Xaml.Controls.Primitives;
-using Windows.UI.Xaml.Data;
 using Windows.UI.Xaml.Input;
-using Windows.UI.Xaml.Media;
 using Windows.UI.Xaml.Navigation;
 
-// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
-
 namespace YJMPD_UWP
 {
-    /// <summary>
-    /// An empty page that can be used on its own or navigated to within a Frame.
-    /// </summary>
     public sealed partial class MainPage : Page
     {
+        double bptime;
+        double lastbptime;
+
         public MainPage()
         {
             this.InitializeComponent();
+            Frame.Navigated += Frame_Navigated;
+            SystemNavigationManager.GetForCurrentView().BackRequested += OnBackRequested;
+
+            bptime = Util.Now;
+
+            this.DataContext = new MainPageVM();
+            Frame.Navigate(typeof(MapView));
+        }
+
+        private void OnBackRequested(object sender, BackRequestedEventArgs e)
+        {
+            if (e.Handled) return;
+
+            if (Frame.CanGoBack)
+            {
+                e.Handled = true;
+                Frame.GoBack();
+                return;
+            }
+
+            lastbptime = bptime;
+            bptime = Util.Now;
+
+            if (bptime - lastbptime > 2000)
+            {
+                ShowHideBackMessage();
+                e.Handled = true;
+            }
+        }
+
+        public async Task<String> ShowHideBackMessage()
+        {
+            BackMessage.Visibility = Visibility.Visible;
+            await Task.Delay(TimeSpan.FromSeconds(2));
+            BackMessage.Visibility = Visibility.Collapsed;
+            return "success";
+        }
+
+        public void Navigate(Type type)
+        {
+            Frame.Navigate(type);
+        }
+
+        public void Navigate(Type type, object param)
+        {
+            Frame.Navigate(type, param);
+        }
+
+        public string Title { get { return PageTitle.Text; } set { PageTitle.Text = value; } }
+
+        public void NavButton_Click(object sender, RoutedEventArgs arg)
+        {
+            NavView.IsPaneOpen = !NavView.IsPaneOpen;
+        }
+
+        private void Frame_Navigated(object sender, NavigationEventArgs e)
+        {
+            //Dirty Hack
+            string pagename = e.SourcePageType.ToString().Split('.').Last();
+
+            NavList.SelectedIndex = -1;
+
+            switch (pagename.ToLower())
+            {
+                default:
+                    PageTitle.Text = "Nav City Breda";
+                    break;
+                case "helpview":
+                    NavList.SelectedIndex = 3;
+                    break;
+                case "settingsview":
+                    NavList.SelectedIndex = 5;
+                    break;
+                case "mapview":
+                    NavList.SelectedIndex = 0;
+                    break;
+                case "routeview":
+                case "routedetailview":
+                    NavList.SelectedIndex = 1;
+                    break;
+                case "landmarkdetailview":
+                case "landmarkview":
+                    NavList.SelectedIndex = 2;
+                    break;
+                case "searchview":
+                    NavList.SelectedIndex = 4;
+                    break;
+            }
+
+            SystemNavigationManager.GetForCurrentView().AppViewBackButtonVisibility =
+                Frame.CanGoBack ?
+                AppViewBackButtonVisibility.Visible :
+                AppViewBackButtonVisibility.Collapsed;
+        }
+
+        private void NavList_SelectionChanged(object sender, SelectionChangedEventArgs e)
+        {
+            NavView.IsPaneOpen = false;
+        }
+
+        private void NavList_Tapped(object sender, TappedRoutedEventArgs e)
+        {
+            NavView.IsPaneOpen = false;
+        }
+
+        private void Content_ManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e)
+        {
+            if (e.Cumulative.Translation.X > 20)
+            {
+                NavView.IsPaneOpen = true;
+            }
+        }
+
+        private void Pane_ManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e)
+        {
+            if (e.Cumulative.Translation.X < -20)
+            {
+                NavView.IsPaneOpen = false;
+            }
+        }
+
+        private void GPSRefresh_Tapped(object sender, TappedRoutedEventArgs e)
+        {
+            App.Geo.ForceRefresh();
         }
     }
 }

+ 81 - 0
YJMPD-UWP/Model/CompassTracker.cs

@@ -0,0 +1,81 @@
+using YJMPD_UWP.Helpers;
+using System;
+using Windows.Devices.Sensors;
+
+namespace YJMPD_UWP.Model
+{
+    public class CompassTracker
+    {
+        public delegate void OnHeadingUpdateHandler(object sender, HeadingUpdatedEventArgs e);
+        public event OnHeadingUpdateHandler OnHeadingUpdate;
+
+        public delegate void OnHeadingUpdateSlowHandler(object sender, HeadingUpdatedEventArgs e);
+        public event OnHeadingUpdateSlowHandler OnSlowHeadingUpdated;
+
+        private Compass comp;
+
+        private CompassReading hdn;
+        public CompassReading Heading { get { return hdn; } }
+
+        private CompassReading lastreading;
+        private double lastreadingtime;
+
+        public CompassTracker()
+        {
+            comp = Compass.GetDefault();
+
+            // Assign an event handler for the compass reading-changed event
+            if (comp != null)
+            {
+                // Establish the report interval for all scenarios
+                uint minReportInterval = comp.MinimumReportInterval;
+                uint reportInterval = minReportInterval > 16 ? minReportInterval : 16;
+                comp.ReportInterval = reportInterval;
+                comp.ReadingChanged += Comp_ReadingChanged;
+                hdn = comp.GetCurrentReading();
+            }
+        }
+
+        private void Comp_ReadingChanged(Compass sender, CompassReadingChangedEventArgs args)
+        {
+            UpdateHeading(args.Reading);
+            UpdateSlowHeading(args.Reading);
+        }
+
+        private void UpdateHeading(CompassReading r)
+        {
+            hdn = r;
+
+            //Make sure someone is listening
+            if (OnHeadingUpdate == null) return;
+
+            OnHeadingUpdate(this, new HeadingUpdatedEventArgs(r));
+        }
+
+        private void UpdateSlowHeading(CompassReading r)
+        {
+            if (lastreading == null) { lastreading = r; lastreadingtime = Util.Now; }
+
+            if (Math.Abs(r.HeadingMagneticNorth - lastreading.HeadingMagneticNorth) > 10 && Util.Now - lastreadingtime > 25)
+            {
+                lastreading = r;
+                lastreadingtime = Util.Now;
+
+                //Make sure someone is listening
+                if (OnSlowHeadingUpdated == null) return;
+
+                OnSlowHeadingUpdated(this, new HeadingUpdatedEventArgs(r));
+            }
+        }
+    }
+
+    public class HeadingUpdatedEventArgs : EventArgs
+    {
+        public CompassReading Heading;
+
+        public HeadingUpdatedEventArgs(CompassReading heading)
+        {
+            Heading = heading;
+        }
+    }
+}

+ 177 - 0
YJMPD-UWP/Model/GeoTracker.cs

@@ -0,0 +1,177 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Windows.Devices.Geolocation;
+using Windows.Devices.Geolocation.Geofencing;
+using Windows.System;
+
+namespace YJMPD_UWP.Model
+{
+    public class GeoTracker
+    {
+        private Geolocator geo;
+
+        private PositionStatus _status;
+        public PositionStatus Status { get { return _status; } }
+
+        private Geoposition _position;
+        public Geoposition Position { get { return _position; } }
+
+        public bool? Connected { get; private set; }
+
+        private List<Geoposition> _history;
+        public List<Geoposition> History
+        {
+            get
+            {
+                return _history;
+            }
+        }
+
+        //Events
+        public delegate void PositionUpdateHandler(object sender, PositionUpdatedEventArgs e);
+        public event PositionUpdateHandler OnPositionUpdate;
+
+        public delegate void StatusUpdateHandler(object sender, StatusUpdatedEventArgs e);
+        public event StatusUpdateHandler OnStatusUpdate;
+
+        public GeoTracker()
+        {
+            _status = PositionStatus.NotInitialized;
+            Connected = false;
+            _history = new List<Geoposition>();
+            StartTracking();
+        }
+
+        public async void ForceRefresh()
+        {
+            if (geo == null)
+                await StartTracking();
+            else
+                _position = await geo.GetGeopositionAsync();
+        }
+
+        public async void TryConnectIfNull()
+        {
+            if (geo == null)
+                await StartTracking();
+        }
+
+        public void ClearHistory()
+        {
+            _history.Clear();
+        }
+
+        public async Task<String> StartTracking()
+        {
+            // Request permission to access location
+            if (Status != PositionStatus.NotAvailable && Status != PositionStatus.NotInitialized)
+                return "Already Connected";
+
+            var accessStatus = await Geolocator.RequestAccessAsync();
+
+            switch (accessStatus)
+            {
+                case GeolocationAccessStatus.Allowed:
+                    geo = new Geolocator
+                    {
+                        DesiredAccuracy = PositionAccuracy.High,
+                        MovementThreshold = 3
+                        //ReportInterval = 1500
+                    };
+
+                    ClearHistory();
+
+                    Connected = true;
+
+                    geo.PositionChanged += Geo_PositionChanged;
+                    geo.StatusChanged += Geo_StatusChanged;
+
+                    GeofenceMonitor.Current.Geofences.Clear();
+
+                    _position = await geo.GetGeopositionAsync();
+
+                    return "Connected";
+
+                case GeolocationAccessStatus.Denied:
+                    Connected = false;
+                    _status = PositionStatus.NotAvailable;
+                    bool result = await Launcher.LaunchUriAsync(new Uri("ms-settings:privacy-location"));
+                    return "Denied";
+
+                default:
+                case GeolocationAccessStatus.Unspecified:
+                    Connected = false;
+                    _status = PositionStatus.NotAvailable;
+                    return "Error";
+            }
+        }
+
+        private void Geo_StatusChanged(Geolocator sender, StatusChangedEventArgs args)
+        {
+            if (args.Status == PositionStatus.Disabled)
+            {
+                Connected = false;
+                _position = null;
+            }
+            else if (!(bool)Connected)
+                Connected = true;
+
+            UpdateStatus(args.Status);
+        }
+
+        private void Geo_PositionChanged(Geolocator sender, PositionChangedEventArgs args)
+        {
+            if (_history.Count > 0)
+                UpdatePosition(_history.Last(), args.Position);
+            else
+            {
+                _position = args.Position;
+                UpdatePosition(args.Position, args.Position);
+            }
+
+            _history.Add(args.Position);
+        }
+
+        private void UpdateStatus(PositionStatus s)
+        {
+            _status = s;
+
+            if (OnStatusUpdate == null) return;
+
+            OnStatusUpdate(this, new StatusUpdatedEventArgs(s));
+        }
+
+        private void UpdatePosition(Geoposition old, Geoposition newp)
+        {
+            _position = newp;
+
+            if (OnPositionUpdate == null) return;
+
+            OnPositionUpdate(this, new PositionUpdatedEventArgs(old, newp));
+        }
+    }
+
+    public class PositionUpdatedEventArgs : EventArgs
+    {
+        public Geoposition Old { get; private set; }
+        public Geoposition New { get; private set; }
+
+        public PositionUpdatedEventArgs(Geoposition old, Geoposition notold)
+        {
+            Old = old;
+            New = notold;
+        }
+    }
+
+    public class StatusUpdatedEventArgs : EventArgs
+    {
+        public PositionStatus Status { get; private set; }
+
+        public StatusUpdatedEventArgs(PositionStatus status)
+        {
+            Status = status;
+        }
+    }
+}

+ 10 - 0
YJMPD-UWP/Themes/DarkTheme.xaml

@@ -0,0 +1,10 @@
+<ResourceDictionary
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="using:YJMPD_UWP.Themes">
+
+    <Style TargetType="RelativePanel" x:Key="DarkModeFix">
+        <Setter Property="Background" Value="{ThemeResource SystemControlBackgroundChromeMediumLowBrush}" />
+    </Style>
+
+</ResourceDictionary>

+ 21 - 0
YJMPD-UWP/Themes/DefaultStyles.xaml

@@ -0,0 +1,21 @@
+<ResourceDictionary
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="using:YJMPD_UWP.Themes">
+
+    <Style TargetType="SymbolIcon" x:Key="InfoIcon">
+        <Setter Property="Foreground" Value="Gray" />
+    </Style>
+    <Style TargetType="TextBlock" x:Key="InfoText">
+        <Setter Property="Foreground" Value="Gray" />
+        <Setter Property="FontSize" Value="16" />
+        <Setter Property="Margin" Value="5,0,0,0" />
+    </Style>
+
+    <Style TargetType="TextBlock" x:Key="Header">
+        <Setter Property="FontSize" Value="20" />
+        <Setter Property="FontWeight" Value="Bold" />
+        <Setter Property="Margin" Value="0,0,0,3" />
+    </Style>
+    
+</ResourceDictionary>

+ 10 - 0
YJMPD-UWP/Themes/LightTheme.xaml

@@ -0,0 +1,10 @@
+<ResourceDictionary
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="using:YJMPD_UWP.Themes">
+
+    <Style TargetType="RelativePanel" x:Key="DarkModeFix">
+        <Setter Property="Background" Value="Transparent" />
+    </Style>
+
+</ResourceDictionary>

+ 72 - 0
YJMPD-UWP/ViewModels/HelpVM.cs

@@ -0,0 +1,72 @@
+using YJMPD_UWP.Helpers;
+
+namespace YJMPD_UWP.ViewModels
+{
+    public class HelpVM : TemplateVM
+    {
+        public HelpVM() : base(Util.Loader.GetString("Help"))
+        {
+
+        }
+
+        protected override void UpdatePropertiesToNewLanguage()
+        {
+            NotifyPropertyChanged(nameof(HelpItem1Header));
+            NotifyPropertyChanged(nameof(HelpItem1Text));
+
+            NotifyPropertyChanged(nameof(HelpItem2Header));
+            NotifyPropertyChanged(nameof(HelpItem2Text));
+
+            NotifyPropertyChanged(nameof(HelpItem3Header));
+            NotifyPropertyChanged(nameof(HelpItem3Text));
+        }
+
+        public string HelpItem1Header
+        {
+            get
+            {
+                return Util.Loader.GetString("HelpItem1Header");
+            }
+        }
+
+        public string HelpItem1Text
+        {
+            get
+            {
+                return Util.Loader.GetString("HelpItem1Text");
+            }
+        }
+
+        public string HelpItem2Header
+        {
+            get
+            {
+                return Util.Loader.GetString("HelpItem2Header");
+            }
+        }
+
+        public string HelpItem2Text
+        {
+            get
+            {
+                return Util.Loader.GetString("HelpItem2Text");
+            }
+        }
+
+        public string HelpItem3Header
+        {
+            get
+            {
+                return Util.Loader.GetString("HelpItem3Header");
+            }
+        }
+
+        public string HelpItem3Text
+        {
+            get
+            {
+                return Util.Loader.GetString("HelpItem3Text");
+            }
+        }
+    }
+}

+ 184 - 0
YJMPD-UWP/ViewModels/MainPageVM.cs

@@ -0,0 +1,184 @@
+using System;
+using Windows.Devices.Geolocation;
+using Windows.UI.Core;
+using YJMPD_UWP;
+using YJMPD_UWP.Helpers;
+using YJMPD_UWP.ViewModels;
+
+namespace YJMPD_UWP.ViewModels
+{
+    public class MainPageVM : TemplateVM
+    {
+        public MainPageVM() : base(Util.Loader.GetString("Loading"))
+        {
+            App.Geo.OnPositionUpdate += Geo_OnPositionUpdate;
+            App.Geo.OnStatusUpdate += Geo_OnStatusUpdate;
+        }
+
+        protected override void UpdatePropertiesToNewLanguage()
+        {
+            NotifyPropertyChanged(nameof(Map));
+            NotifyPropertyChanged(nameof(Help));
+            NotifyPropertyChanged(nameof(Route));
+            NotifyPropertyChanged(nameof(Landmarks));
+            NotifyPropertyChanged(nameof(Search));
+            NotifyPropertyChanged(nameof(Settings));
+            NotifyPropertyChanged(nameof(Status));
+            NotifyPropertyChanged(nameof(Source));
+            NotifyPropertyChanged(nameof(Accuracy));
+            NotifyPropertyChanged(nameof(GPSInfo));
+            NotifyPropertyChanged(nameof(BackText));
+        }
+
+        public string BackText
+        {
+            get
+            {
+                return Util.Loader.GetString("BackTwiceText");
+            }
+        }
+
+
+        public string Map
+        {
+            get
+            {
+                return Util.Loader.GetString("Map");
+            }
+        }
+
+        public string Help
+        {
+            get
+            {
+                return Util.Loader.GetString("Help");
+            }
+        }
+
+        public string Route
+        {
+            get
+            {
+                return Util.Loader.GetString("Route");
+            }
+        }
+
+        public string Landmarks
+        {
+            get
+            {
+                return Util.Loader.GetString("Landmarks");
+            }
+        }
+
+        public string Search
+        {
+            get
+            {
+                return Util.Loader.GetString("Search");
+            }
+        }
+
+        public string Settings
+        {
+            get
+            {
+                return Util.Loader.GetString("Settings");
+            }
+        }
+
+        private void Geo_OnStatusUpdate(object sender, YJMPD_UWP.Model.StatusUpdatedEventArgs e)
+        {
+            dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
+            {
+                NotifyPropertyChanged(nameof(Status));
+            });
+        }
+
+        private void Geo_OnPositionUpdate(object sender, YJMPD_UWP.Model.PositionUpdatedEventArgs e)
+        {
+            dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
+            {
+                NotifyPropertyChanged(nameof(Source));
+                NotifyPropertyChanged(nameof(Accuracy));
+            });
+        }
+
+        public string GPSInfo
+        {
+            get
+            {
+                return Util.Loader.GetString("GPSInfo");
+            }
+        }
+
+        public string Status
+        {
+            get
+            {
+                switch (App.Geo.Status)
+                {
+                    case PositionStatus.Disabled:
+                        return Util.Loader.GetString("Disabled");
+                    case PositionStatus.Initializing:
+                        return Util.Loader.GetString("Initializing");
+                    case PositionStatus.NoData:
+                        return Util.Loader.GetString("NoData");
+                    default:
+                    case PositionStatus.NotAvailable:
+                        return Util.Loader.GetString("NotAvailable");
+                    case PositionStatus.NotInitialized:
+                        return Util.Loader.GetString("NotInitialized");
+                    case PositionStatus.Ready:
+                        return Util.Loader.GetString("Ready");
+                }
+            }
+        }
+
+        public string Source
+        {
+            get
+            {
+                if (App.Geo.Connected == true && App.Geo.Position != null)
+                    switch (App.Geo.Position.Coordinate.PositionSource)
+                    {
+                        case PositionSource.Cellular:
+                            return Util.Loader.GetString("Cellular");
+                        case PositionSource.IPAddress:
+                            return Util.Loader.GetString("IPAddress");
+                        case PositionSource.Satellite:
+                            return Util.Loader.GetString("Satellite");
+                        case PositionSource.WiFi:
+                            return Util.Loader.GetString("WiFi");
+                        default:
+                        case PositionSource.Unknown:
+                            return Util.Loader.GetString("Unknown");
+
+                    }
+                else
+                    return Util.Loader.GetString("Unknown");
+            }
+        }
+
+        public string Accuracy
+        {
+            get
+            {
+
+                if (App.Geo.Connected == true && App.Geo.Position != null)
+                    return App.Geo.Position.Coordinate.Accuracy.ToString() + "m";
+                else
+                    return Util.Loader.GetString("Unknown");
+            }
+        }
+
+        public string Year
+        {
+            get
+            {
+                int year = DateTime.Now.Year;
+                return year.ToString();
+            }
+        }
+    }
+}

+ 45 - 0
YJMPD-UWP/ViewModels/SettingsVM.cs

@@ -0,0 +1,45 @@
+using YJMPD_UWP.Helpers;
+
+namespace YJMPD_UWP.ViewModels
+{
+    public class SettingsVM : TemplateVM
+    {
+
+        public SettingsVM() : base(Util.Loader.GetString("Settings"))
+        {
+
+        }
+
+        protected override void UpdatePropertiesToNewLanguage()
+        {
+            NotifyPropertyChanged(nameof(Language));
+            NotifyPropertyChanged(nameof(Reset));
+            NotifyPropertyChanged(nameof(ResetHeader));
+            App.MainPage.Title = Util.Loader.GetString("Settings");
+        }
+
+        public string Language
+        {
+            get
+            {
+                return Util.Loader.GetString("Language");
+            }
+        }
+
+        public string ResetHeader
+        {
+            get
+            {
+                return Util.Loader.GetString("Reset");
+            }
+        }
+
+        public string Reset
+        {
+            get
+            {
+                return Util.Loader.GetString("Reset") + " " + Util.Loader.GetString("Application");
+            }
+        }
+    }
+}

+ 41 - 0
YJMPD-UWP/ViewModels/TemplateVM.cs

@@ -0,0 +1,41 @@
+using YJMPD_UWP.Helpers;
+using System;
+using System.ComponentModel;
+using Windows.UI.Core;
+
+namespace YJMPD_UWP.ViewModels
+{
+    public class TemplateVM : INotifyPropertyChanged
+    {
+        protected CoreDispatcher dispatcher;
+
+        public TemplateVM(string title)
+        {
+            dispatcher = App.Dispatcher;
+            Settings.OnLanguageUpdate += Settings_OnLanguageUpdate;
+
+            if (App.MainPage != null)
+                App.MainPage.Title = title;
+        }
+
+        private void Settings_OnLanguageUpdate(EventArgs e)
+        {
+            dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
+            {
+                UpdatePropertiesToNewLanguage();
+            });
+        }
+
+        protected virtual void UpdatePropertiesToNewLanguage()
+        {
+            //to implement in underlying class
+        }
+
+        public event PropertyChangedEventHandler PropertyChanged;
+
+        protected void NotifyPropertyChanged(string propertyName)
+        {
+            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
+        }
+    }
+}

+ 112 - 0
YJMPD-UWP/Views/HelpView.xaml

@@ -0,0 +1,112 @@
+<Page
+    x:Class="YJMPD_UWP.Views.HelpView"
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="using:YJMPD_UWP.Views"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    mc:Ignorable="d">
+
+    <Page.Resources>
+        <Style TargetType="StackPanel" x:Key="HelpPanel">
+            <Setter Property="Margin" Value="10,10,10,0" />
+            <Setter Property="Padding" Value="0,0,0,10" />
+            <Setter Property="BorderBrush" Value="{ThemeResource SystemControlBackgroundChromeMediumLowBrush}" />
+            <Setter Property="BorderThickness" Value="0,0,0,2" />
+        </Style>
+
+        <Style TargetType="TextBlock" x:Key="HelpText">
+            <Setter Property="RelativePanel.AlignTopWithPanel" Value="True" />
+            <Setter Property="RelativePanel.AlignLeftWithPanel" Value="True" />
+            <Setter Property="TextWrapping" Value="WrapWholeWords" />
+            <Setter Property="TextAlignment" Value="Left" />
+        </Style>
+
+        <Style TargetType="TextBlock" x:Key="HelpTextImage">
+            <Setter Property="RelativePanel.AlignTopWithPanel" Value="True" />
+            <Setter Property="RelativePanel.AlignLeftWithPanel" Value="True" />
+            <Setter Property="TextWrapping" Value="WrapWholeWords" />
+            <Setter Property="Margin" Value="0,0,60,0" />
+            <Setter Property="TextAlignment" Value="Left" />
+        </Style>
+
+        <Style TargetType="Image" x:Key="HelpImageSmall">
+            <Setter Property="RelativePanel.AlignRightWithPanel" Value="True" />
+            <Setter Property="RelativePanel.AlignVerticalCenterWithPanel" Value="True" />
+            <Setter Property="Width" Value="50" />
+            <Setter Property="Height" Value="50" />
+            <Setter Property="Stretch" Value="UniformToFill"/>
+        </Style>
+
+        <Style TargetType="SymbolIcon" x:Key="HelpSymbolSmall">
+            <Setter Property="RelativePanel.AlignRightWithPanel" Value="True" />
+            <Setter Property="RelativePanel.AlignVerticalCenterWithPanel" Value="True" />
+            <Setter Property="Width" Value="50" />
+            <Setter Property="Height" Value="50" />
+        </Style>
+
+        <Style TargetType="TextBlock" x:Key="HelpIconSmall">
+            <Setter Property="RelativePanel.AlignRightWithPanel" Value="True" />
+            <Setter Property="RelativePanel.AlignVerticalCenterWithPanel" Value="True" />
+            <Setter Property="FontFamily" Value="Segoe MDL2 Assets" />
+            <Setter Property="FontSize" Value="40" />
+        </Style>
+
+        <Style TargetType="Image" x:Key="HelpImageLarge">
+            <Setter Property="Stretch" Value="UniformToFill"/>
+            <Setter Property="Margin" Value="0,5,0,0" />
+        </Style>
+    </Page.Resources>
+
+    <ScrollViewer HorizontalScrollMode="Disabled" VerticalScrollMode="Enabled" VerticalSnapPointsAlignment="Near">
+        <Grid>
+            <Grid.RowDefinitions>
+                <RowDefinition Height="Auto" />
+                <RowDefinition Height="Auto" />
+                <RowDefinition Height="Auto" />
+                <RowDefinition Height="Auto" />
+                <RowDefinition Height="Auto" />
+                <RowDefinition Height="Auto" />
+                <RowDefinition Height="Auto" />
+            </Grid.RowDefinitions>
+
+            <!-- Position -->
+            <StackPanel Grid.Row="0" Style="{StaticResource HelpPanel}">
+                <TextBlock Text="{Binding HelpItem1Header}" Style="{StaticResource Header}" />
+                <RelativePanel>
+                    <TextBlock Text="{Binding HelpItem1Text}" Style="{StaticResource HelpTextImage}" />
+                    <Image Source="/Assets/CurrentLocationRound.png" Style="{StaticResource HelpImageSmall}" />
+                </RelativePanel>
+            </StackPanel>
+
+            <!-- Page Navigation -->
+            <StackPanel Grid.Row="1" Style="{StaticResource HelpPanel}">
+                <TextBlock Text="{Binding HelpItem2Header}" Style="{StaticResource Header}" />
+                <RelativePanel>
+                    <TextBlock Text="{Binding HelpItem2Text}" Style="{StaticResource HelpText}" />
+                </RelativePanel>
+                <Image Source="/Assets/Help/HelpItem2Image.png" Style="{StaticResource HelpImageLarge}" />
+            </StackPanel>
+
+            <!-- GPS Information -->
+            <StackPanel Grid.Row="2" Style="{StaticResource HelpPanel}">
+                <TextBlock Text="{Binding HelpItem3Header}" Style="{StaticResource Header}" />
+                <RelativePanel>
+                    <TextBlock Text="{Binding HelpItem3Text}" Style="{StaticResource HelpText}" />
+                </RelativePanel>
+                <Image Source="/Assets/Help/HelpItem3Image.png" Style="{StaticResource HelpImageLarge}" />
+            </StackPanel>
+
+            <!-- Map + Controls (Tilt,zoom,pan,rotate) -->
+            <!-- Route -->
+            <!-- Help -->
+            <!-- Settings -->
+            <!-- Landmark -->
+            <!-- Visited / Not Visited -->
+            <!-- Starting a route -->
+            <!-- Stopping a route -->
+            <!-- What happens when you walk -->
+            <!-- Buttons and text during navigation -->
+        </Grid>
+    </ScrollViewer>
+</Page>

+ 17 - 0
YJMPD-UWP/Views/HelpView.xaml.cs

@@ -0,0 +1,17 @@
+using YJMPD_UWP.ViewModels;
+using Windows.UI.Xaml.Controls;
+
+namespace YJMPD_UWP.Views
+{
+    public sealed partial class HelpView : Page
+    {
+        HelpVM helpvm;
+
+        public HelpView()
+        {
+            helpvm = new HelpVM();
+            this.DataContext = helpvm;
+            this.InitializeComponent();
+        }
+    }
+}

+ 36 - 0
YJMPD-UWP/Views/SettingsView.xaml

@@ -0,0 +1,36 @@
+<Page
+    x:Class="YJMPD_UWP.Views.SettingsView"
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="using:YJMPD_UWP.Views"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    mc:Ignorable="d">
+
+    <ScrollViewer>
+        <StackPanel HorizontalAlignment="Stretch">
+            <StackPanel Margin="10">
+                <TextBlock Text="{Binding Language}" Style="{StaticResource Header}"/>
+                <ComboBox Name="Language" SelectionChanged="Language_SelectionChanged" HorizontalAlignment="Stretch">
+                    <ComboBoxItem>English</ComboBoxItem>
+                    <ComboBoxItem>Nederlands</ComboBoxItem>
+                    <ComboBoxItem>Deutsch</ComboBoxItem>
+                    <!-- <ComboBoxItem>日本語</ComboBoxItem> -->
+                </ComboBox>
+            </StackPanel>
+
+            <StackPanel Margin="10">
+                <TextBlock Text="{Binding ResetHeader}" Style="{StaticResource Header}"/>
+                <StackPanel Orientation="Horizontal">
+                    <Button Name="ResetButton" Click="ResetButton_Click">
+                        <StackPanel Orientation="Horizontal">
+                            <TextBlock FontFamily="Segoe MDL2 Assets" Text="&#xE895;" Margin="0,3,10,0" />
+                            <TextBlock Text="{Binding Reset}" />
+                        </StackPanel>
+                    </Button>
+                    <ProgressRing Name="ResetProgress" IsActive="False" Margin="15,0,0,0"/>
+                </StackPanel>
+            </StackPanel>
+        </StackPanel>
+    </ScrollViewer>
+</Page>

+ 82 - 0
YJMPD-UWP/Views/SettingsView.xaml.cs

@@ -0,0 +1,82 @@
+using YJMPD_UWP.Helpers;
+using YJMPD_UWP.ViewModels;
+using System.Diagnostics;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Navigation;
+
+namespace YJMPD_UWP.Views
+{
+    public sealed partial class SettingsView : Page
+    {
+        SettingsVM settingsvm;
+
+        public SettingsView()
+        {
+            this.InitializeComponent();
+            settingsvm = new SettingsVM();
+            this.DataContext = settingsvm;
+        }
+
+        protected override void OnNavigatedTo(NavigationEventArgs e)
+        {
+            switch (Settings.CurrentLanguage)
+            {
+                default:
+                    Debug.WriteLine("Unsupported language: " + Settings.CurrentLanguage);
+                    Language.SelectedIndex = 0;
+                    break;
+                case "en":
+                    Language.SelectedIndex = 0;
+                    break;
+                case "nl":
+                    Language.SelectedIndex = 1;
+                    break;
+                case "de":
+                    Language.SelectedIndex = 2;
+                    break;
+                case "ja":
+                    Language.SelectedIndex = 3;
+                    break;
+            }
+        }
+
+        private void Language_SelectionChanged(object sender, SelectionChangedEventArgs e)
+        {
+            switch (Language.SelectedIndex)
+            {
+                default:
+                    Language.SelectedIndex = 0;
+                    break;
+                case 0:
+                    if (Settings.CurrentLanguage != "en")
+                        Settings.ChangeLanguage("en");
+                    break;
+                case 1:
+                    if (Settings.CurrentLanguage != "nl")
+                        Settings.ChangeLanguage("nl");
+                    break;
+                case 2:
+                    if (Settings.CurrentLanguage != "de")
+                        Settings.ChangeLanguage("de");
+                    break;
+                case 3:
+                    if (Settings.CurrentLanguage != "ja")
+                        Settings.ChangeLanguage("ja");
+                    break;
+            }
+        }
+
+        private async void ResetButton_Click(object sender, RoutedEventArgs e)
+        {
+            bool confirm = await Util.ShowConfirmDialog(Util.Loader.GetString("Reset"), Util.Loader.GetString("ResetConfirmation"), Util.DialogType.YESNO);
+
+            if (confirm)
+            {
+                ResetProgress.IsActive = true;
+                Language.SelectedIndex = 0;
+                ResetProgress.IsActive = false;
+            }
+        }
+    }
+}

+ 104 - 9
YJMPD-UWP/YJMPD-UWP.csproj

@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
     <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
-    <ProjectGuid>{7be4d70c-7653-4757-800b-73dc1f8d19f7}</ProjectGuid>
+    <ProjectGuid>{7BE4D70C-7653-4757-800B-73DC1F8D19F7}</ProjectGuid>
     <OutputType>AppContainerExe</OutputType>
     <AppDesignerFolder>Properties</AppDesignerFolder>
     <RootNamespace>YJMPD_UWP</RootNamespace>
@@ -16,9 +16,7 @@
     <MinimumVisualStudioVersion>14</MinimumVisualStudioVersion>
     <FileAlignment>512</FileAlignment>
     <ProjectTypeGuids>{A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
-    
     <PackageCertificateKeyFile>YJMPD-UWP_TemporaryKey.pfx</PackageCertificateKeyFile>
-    
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
     <DebugSymbols>true</DebugSymbols>
@@ -97,18 +95,73 @@
     <Compile Include="App.xaml.cs">
       <DependentUpon>App.xaml</DependentUpon>
     </Compile>
+    <Compile Include="Helpers\Comparer\LandmarkAlphaComparer.cs" />
+    <Compile Include="Helpers\Comparer\LandmarkAlphaReversedComparer.cs" />
+    <Compile Include="Helpers\Comparer\LandmarkNotVisitedComparer.cs" />
+    <Compile Include="Helpers\Comparer\LandmarkVisitedComparer.cs" />
+    <Compile Include="Helpers\Comparer\SearchLandmarkComparer.cs" />
+    <Compile Include="Helpers\Comparer\SearchRouteComparer.cs" />
+    <Compile Include="Helpers\Converter\BoolToVisibilityConverter.cs" />
+    <Compile Include="Helpers\Converter\StatusToIconConverter.cs" />
+    <Compile Include="Helpers\Extensions.cs" />
+    <Compile Include="Helpers\RouteParser.cs" />
+    <Compile Include="Helpers\Settings.cs" />
+    <Compile Include="Helpers\Util.cs" />
     <Compile Include="MainPage.xaml.cs">
       <DependentUpon>MainPage.xaml</DependentUpon>
     </Compile>
+    <Compile Include="Model\CompassTracker.cs" />
+    <Compile Include="Model\GeoTracker.cs" />
+    <Compile Include="Model\Object\Image.cs" />
+    <Compile Include="Model\Object\Landmark.cs" />
+    <Compile Include="Model\Object\Route.cs" />
+    <Compile Include="Model\Object\Waypoint.cs" />
+    <Compile Include="Model\RouteManager.cs" />
+    <Compile Include="Model\SearchHandler.cs" />
+    <Compile Include="Model\Search\LandmarkResult.cs" />
+    <Compile Include="Model\Search\RouteResult.cs" />
+    <Compile Include="Model\Search\SearchResult.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="ViewModels\HelpVM.cs" />
+    <Compile Include="ViewModels\LandmarkDetailVM.cs" />
+    <Compile Include="ViewModels\LandmarkVM.cs" />
+    <Compile Include="ViewModels\MainPageVM.cs" />
+    <Compile Include="ViewModels\MapVM.cs" />
+    <Compile Include="ViewModels\RouteDetailVM.cs" />
+    <Compile Include="ViewModels\RouteVM.cs" />
+    <Compile Include="ViewModels\SearchVM.cs" />
+    <Compile Include="ViewModels\SettingsVM.cs" />
+    <Compile Include="ViewModels\TemplateVM.cs" />
+    <Compile Include="Views\HelpView.xaml.cs">
+      <DependentUpon>HelpView.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="Views\LandmarkDetailView.xaml.cs">
+      <DependentUpon>LandmarkDetailView.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="Views\LandmarkView.xaml.cs">
+      <DependentUpon>LandmarkView.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="Views\MapView.xaml.cs">
+      <DependentUpon>MapView.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="Views\RouteDetailView.xaml.cs">
+      <DependentUpon>RouteDetailView.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="Views\RouteView.xaml.cs">
+      <DependentUpon>RouteView.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="Views\SearchView.xaml.cs">
+      <DependentUpon>SearchView.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="Views\SettingsView.xaml.cs">
+      <DependentUpon>SettingsView.xaml</DependentUpon>
+    </Compile>
   </ItemGroup>
   <ItemGroup>
     <AppxManifest Include="Package.appxmanifest">
       <SubType>Designer</SubType>
     </AppxManifest>
-    
     <None Include="YJMPD-UWP_TemporaryKey.pfx" />
-    
   </ItemGroup>
   <ItemGroup>
     <Content Include="Properties\Default.rd.xml" />
@@ -129,12 +182,54 @@
       <Generator>MSBuild:Compile</Generator>
       <SubType>Designer</SubType>
     </Page>
+    <Page Include="Themes\DarkTheme.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
+    <Page Include="Themes\DefaultStyles.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
+    <Page Include="Themes\LightTheme.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
+    <Page Include="Views\HelpView.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
+    <Page Include="Views\LandmarkDetailView.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
+    <Page Include="Views\LandmarkView.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
+    <Page Include="Views\MapView.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
+    <Page Include="Views\RouteDetailView.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
+    <Page Include="Views\RouteView.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
+    <Page Include="Views\SearchView.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
+    <Page Include="Views\SettingsView.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
   </ItemGroup>
-  
   <PropertyGroup Condition=" '$(VisualStudioVersion)' == '' or '$(VisualStudioVersion)' &lt; '14.0' ">
     <VisualStudioVersion>14.0</VisualStudioVersion>
   </PropertyGroup>
-
   <Import Project="$(MSBuildExtensionsPath)\Microsoft\WindowsXaml\v$(VisualStudioVersion)\Microsoft.Windows.UI.Xaml.CSharp.targets" />
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.
@@ -143,4 +238,4 @@
   <Target Name="AfterBuild">
   </Target>
   -->
-</Project>
+</Project>

+ 2 - 1
YJMPD-UWP/project.json

@@ -1,6 +1,7 @@
 {
   "dependencies": {
-    "Microsoft.NETCore.UniversalWindowsPlatform": "5.0.0"
+    "Microsoft.NETCore.UniversalWindowsPlatform": "5.0.0",
+    "Newtonsoft.Json": "8.0.2"
   },
   "frameworks": {
     "uap10.0": {}