diff --git a/YJMPD-UWP/App.xaml b/YJMPD-UWP/App.xaml index 17f7ca0..0331a6b 100644 --- a/YJMPD-UWP/App.xaml +++ b/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"> + + + + + + + + + + + + diff --git a/YJMPD-UWP/App.xaml.cs b/YJMPD-UWP/App.xaml.cs index c256890..5c55a17 100644 --- a/YJMPD-UWP/App.xaml.cs +++ b/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 { - /// - /// Provides application-specific behavior to supplement the default Application class. - /// 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 + // =============================== + + /// /// 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(); } diff --git a/YJMPD-UWP/Helpers/Extensions.cs b/YJMPD-UWP/Helpers/Extensions.cs new file mode 100644 index 0000000..c017007 --- /dev/null +++ b/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); + } + } +} diff --git a/YJMPD-UWP/Helpers/Settings.cs b/YJMPD-UWP/Helpers/Settings.cs new file mode 100644 index 0000000..6f8a321 --- /dev/null +++ b/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; } } + } +} diff --git a/YJMPD-UWP/Helpers/Util.cs b/YJMPD-UWP/Helpers/Util.cs new file mode 100644 index 0000000..2cdebb2 --- /dev/null +++ b/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 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 FindWalkingRoute(Geopoint from, Geopoint to) + { + MapRouteFinderResult routeResult = await MapRouteFinder.GetWalkingRouteAsync(from, to); + MapRoute b = routeResult.Route; + return b; + } + + public static async Task FindWalkingRoute(List points) + { + MapRouteFinderResult routeResult = await MapRouteFinder.GetWalkingRouteFromWaypointsAsync(points); + MapRoute b = routeResult.Route; + return b; + } + + public static async Task 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 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 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 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 plist = new List(); + 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 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; + } + } +} diff --git a/YJMPD-UWP/MainPage.xaml b/YJMPD-UWP/MainPage.xaml index 9cf4bef..cd52771 100644 --- a/YJMPD-UWP/MainPage.xaml +++ b/YJMPD-UWP/MainPage.xaml @@ -7,7 +7,150 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/YJMPD-UWP/Views/SettingsView.xaml.cs b/YJMPD-UWP/Views/SettingsView.xaml.cs new file mode 100644 index 0000000..c0ab959 --- /dev/null +++ b/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; + } + } + } +} diff --git a/YJMPD-UWP/YJMPD-UWP.csproj b/YJMPD-UWP/YJMPD-UWP.csproj index e444ad5..cc60dd0 100644 --- a/YJMPD-UWP/YJMPD-UWP.csproj +++ b/YJMPD-UWP/YJMPD-UWP.csproj @@ -1,10 +1,10 @@ - + Debug x86 - {7be4d70c-7653-4757-800b-73dc1f8d19f7} + {7BE4D70C-7653-4757-800B-73DC1F8D19F7} AppContainerExe Properties YJMPD_UWP @@ -16,9 +16,7 @@ 14 512 {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - YJMPD-UWP_TemporaryKey.pfx - true @@ -97,18 +95,73 @@ App.xaml + + + + + + + + + + + + MainPage.xaml + + + + + + + + + + + + + + + + + + + + + + + HelpView.xaml + + + LandmarkDetailView.xaml + + + LandmarkView.xaml + + + MapView.xaml + + + RouteDetailView.xaml + + + RouteView.xaml + + + SearchView.xaml + + + SettingsView.xaml + Designer - - @@ -129,12 +182,54 @@ MSBuild:Compile Designer + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + - 14.0 - - + \ No newline at end of file diff --git a/YJMPD-UWP/project.json b/YJMPD-UWP/project.json index c594939..2c3ee60 100644 --- a/YJMPD-UWP/project.json +++ b/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": {}