Skip to content
This repository has been archived by the owner on May 15, 2024. It is now read-only.

Commit

Permalink
GH-287 OpenMaps Implementation (#361) (#404)
Browse files Browse the repository at this point in the history
* GH-287 Maps Implementation (#361)

* Implemented maps as mentioned in branch name issue. also fixed a spelling mistake

* Added samples

* Added doc stubs

* Added comments for map types

* Refactored code

* Formatting of docs

* Added tests

* Changed coordinates to display something recognisable

* Added uri escaping, thus removing duplicate code. also had to turn off a warning due to inconsistent style cop and vs warning behaviour.

* Removed ref until in is added in c# 7.2

* Adressed issues in pr

* Updated launch code

* Adressed method to onliner

* Updated docs

* Removed ClearTop intent, added sample with adress

* Rename to align names. Added extensions and additional paramaters.

* Update tests

* Throw if options are null.

* Add overload for lat/long without options
  • Loading branch information
jamesmontemagno authored Jul 25, 2018
1 parent 6603686 commit 1c14a29
Show file tree
Hide file tree
Showing 33 changed files with 1,116 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Geocoding_Tests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Geolocation_Tests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)MainThread_Tests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Maps_Tests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Permissions_Tests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)PhoneDialer_Tests.cs" />
<Compile Include="$(MSBuildThisFileDirectory)ScreenLock_Tests.cs" />
Expand Down
69 changes: 69 additions & 0 deletions DeviceTests/DeviceTests.Shared/Maps_Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System;
using System.Threading.Tasks;
using Xamarin.Essentials;
using Xunit;

namespace DeviceTests
{
public class Maps_Tests
{
const double testLatitude = 47.645160;
const double testLongitude = -122.1306032;
const string mapName = "Microsoft Building 25";

[Fact]
[Trait(Traits.InteractionType, Traits.InteractionTypes.Human)]
public async Task LaunchMap_CoordinatesDisplayCorrectPlace()
{
await Maps.OpenAsync(testLatitude, testLongitude, new MapsLaunchOptions { Name = mapName });
}

[Fact]
[Trait(Traits.InteractionType, Traits.InteractionTypes.Human)]
public async Task LaunchMap_PlacemarkDisplayCorrectPlace()
{
var placemark = new Placemark
{
CountryName = "United States",
AdminArea = "WA",
Thoroughfare = "Microsoft Building 25",
Locality = "Redmond"
};
await Maps.OpenAsync(placemark, new MapsLaunchOptions { Name = mapName });
}

[Fact]
public async Task LaunchMap_NullLocation()
{
Location location = null;
await Assert.ThrowsAsync<ArgumentNullException>(() => Maps.OpenAsync(location));
}

[Fact]
public async Task LaunchMap_NullOptionsLocation()
{
var location = new Location(testLatitude, testLongitude);
await Assert.ThrowsAsync<ArgumentNullException>(() => Maps.OpenAsync(location, null));
}

[Fact]
public async Task LaunchMap_NullPlacemark()
{
Placemark location = null;
await Assert.ThrowsAsync<ArgumentNullException>(() => Maps.OpenAsync(location));
}

[Fact]
public async Task LaunchMap_NullOptionsPlacemark()
{
var placemark = new Placemark
{
CountryName = "United States",
AdminArea = "WA",
Thoroughfare = "Microsoft Building 25",
Locality = "Redmond"
};
await Assert.ThrowsAsync<ArgumentNullException>(() => Maps.OpenAsync(placemark, null));
}
}
}
44 changes: 44 additions & 0 deletions Samples/Samples/View/MapsPage.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<views:BasePage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:Samples.View"
xmlns:viewmodels="clr-namespace:Samples.ViewModel"
x:Class="Samples.View.MapsPage"
Title="Maps">
<views:BasePage.BindingContext>
<viewmodels:MapsViewModel />
</views:BasePage.BindingContext>

<ScrollView>
<StackLayout Padding="10">
<Label Text="Open location in maps." FontAttributes="Bold"/>

<Label Text="Options:"/>
<Label Text="Navigation Mode (iOS Only)"/>
<Picker HorizontalOptions="FillAndExpand"
ItemsSource="{Binding DirectionModes}"
SelectedIndex="{Binding DirectionMode, Mode=TwoWay}" />
<Label Text="Name"/>
<Entry Text="{Binding Name}"/>



<Label Text="Latitude" Margin="0,24,0,0" />
<Entry Keyboard="Numeric" Text="{Binding Latitude}" />
<Label Text="Longitude" />
<Entry Keyboard="Numeric" Text="{Binding Longitude}" />
<Button Text="Open coordinates" Command="{Binding MapsCommand}"/>

<Label Text="Thoroughfare" Margin="0,24,0,0"/>
<Entry Text="{Binding Thoroughfare}"/>
<Label Text="Locality"/>
<Entry Text="{Binding Locality}"/>
<Label Text="Admin Area"/>
<Entry Text="{Binding AdminArea}"/>
<Label Text="Country Name"/>
<Entry Text="{Binding Country}"/>

<Button Text="Open address" Command="{Binding LaunchPlacemarkCommand}"/>
</StackLayout>
</ScrollView>

</views:BasePage>
13 changes: 13 additions & 0 deletions Samples/Samples/View/MapsPage.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Xamarin.Forms.Xaml;

namespace Samples.View
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MapsPage : BasePage
{
public MapsPage()
{
InitializeComponent();
}
}
}
6 changes: 6 additions & 0 deletions Samples/Samples/ViewModel/HomeViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ public HomeViewModel()
typeof(MagnetometerPage),
"Detect device's orientation relative to Earth's magnetic field.",
new[] { "compass", "magnetometer", "sensors", "hardware", "device" }),
new SampleItem(
"📍",
"Launch Maps",
typeof(MapsPage),
"Easily launch maps with coordinates.",
new[] { "geocoding", "geolocation", "position", "address", "mapping", "maps", "route", "navigation" }),
new SampleItem(
"📏",
"Orientation Sensor",
Expand Down
110 changes: 110 additions & 0 deletions Samples/Samples/ViewModel/MapsViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
using System.Collections.Generic;
using System.Windows.Input;
using Xamarin.Essentials;
using Xamarin.Forms;

namespace Samples.ViewModel
{
public class MapsViewModel : BaseViewModel
{
string name = "Microsoft Building 25";

public string Name
{
get => name;
set => SetProperty(ref name, value);
}

string longitude = "-122.130603";

public string Longitude
{
get => longitude;
set => SetProperty(ref longitude, value);
}

string latitude = "47.645160";

public string Latitude
{
get => latitude;
set => SetProperty(ref latitude, value);
}

string locality = "Redmond";

public string Locality
{
get => locality;
set => SetProperty(ref locality, value);
}

string adminArea = "WA";

public string AdminArea
{
get => adminArea;
set => SetProperty(ref adminArea, value);
}

string thoroughfare = "Microsoft Building 25";

public string Thoroughfare
{
get => thoroughfare;
set => SetProperty(ref thoroughfare, value);
}

string country = "United States";

public string Country
{
get => country;
set => SetProperty(ref country, value);
}

public List<string> DirectionModes { get; } =
new List<string>
{
"Default",
"Driving",
"Transit",
"Walking"
};

int directionMode;

public int DirectionMode
{
get => directionMode;
set => SetProperty(ref directionMode, value);
}

public ICommand MapsCommand { get; }

public ICommand LaunchPlacemarkCommand { get; }

public MapsViewModel()
{
MapsCommand = new Command(OpenLocation);
LaunchPlacemarkCommand = new Command(OpenPlacemark);
}

async void OpenLocation()
{
await Maps.OpenAsync(double.Parse(Latitude), double.Parse(Longitude), new MapsLaunchOptions { Name = Name, MapDirectionsMode = (MapDirectionsMode)DirectionMode });
}

async void OpenPlacemark()
{
var placemark = new Placemark
{
Locality = Locality,
AdminArea = AdminArea,
CountryName = Country,
Thoroughfare = Thoroughfare
};
await Maps.OpenAsync(placemark, new MapsLaunchOptions() { Name = Name, MapDirectionsMode = (MapDirectionsMode)DirectionMode });
}
}
}
70 changes: 70 additions & 0 deletions Tests/Maps_Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System;
using System.Threading.Tasks;
using Xamarin.Essentials;
using Xunit;

namespace Tests
{
public class Maps_Tests
{
const double testLatitude = 47.645160;
const double testLongitude = -122.1306032;
const string mapName = "Microsoft Building 25";

[Fact]
public async Task Open_Map_LatLong_NetStandard() =>
await Assert.ThrowsAsync<NotImplementedInReferenceAssemblyException>(
() => Maps.OpenAsync(
testLatitude,
testLongitude,
new MapsLaunchOptions { Name = mapName }));

[Fact]
public async Task Open_Map_Location_NetStandard() =>
await Assert.ThrowsAsync<NotImplementedInReferenceAssemblyException>(
() => Maps.OpenAsync(
new Location(testLatitude, testLongitude),
new MapsLaunchOptions { Name = mapName }));

[Fact]
public async Task Open_Map_Placemark_NetStandard() =>
await Assert.ThrowsAsync<NotImplementedInReferenceAssemblyException>(
() => Maps.OpenAsync(
new Placemark(),
new MapsLaunchOptions { Name = mapName }));

[Fact]
public async Task LaunchMap_NullLocation()
{
Location location = null;
await Assert.ThrowsAsync<ArgumentNullException>(() => Maps.OpenAsync(location));
}

[Fact]
public async Task LaunchMap_NullOptionsLocation()
{
var location = new Location(testLatitude, testLongitude);
await Assert.ThrowsAsync<ArgumentNullException>(() => Maps.OpenAsync(location, null));
}

[Fact]
public async Task LaunchMap_NullPlacemark()
{
Placemark location = null;
await Assert.ThrowsAsync<ArgumentNullException>(() => Maps.OpenAsync(location));
}

[Fact]
public async Task LaunchMap_NullOptionsPlacemark()
{
var placemark = new Placemark
{
CountryName = "United States",
AdminArea = "WA",
Thoroughfare = "Microsoft Building 25",
Locality = "Redmond"
};
await Assert.ThrowsAsync<ArgumentNullException>(() => Maps.OpenAsync(placemark, null));
}
}
}
10 changes: 10 additions & 0 deletions Xamarin.Essentials/Maps/MapDirectionsMode.shared.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace Xamarin.Essentials
{
public enum MapDirectionsMode
{
Default,
Driving,
Transit,
Walking
}
}
9 changes: 9 additions & 0 deletions Xamarin.Essentials/Maps/MapLaunchOptions.shared.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Xamarin.Essentials
{
public class MapsLaunchOptions
{
public MapDirectionsMode MapDirectionsMode { get; set; } = MapDirectionsMode.Default;

public string Name { get; set; } = string.Empty;
}
}
38 changes: 38 additions & 0 deletions Xamarin.Essentials/Maps/Maps.android.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System.Globalization;
using System.Threading.Tasks;
using Android.Content;
using AndroidUri = Android.Net.Uri;

namespace Xamarin.Essentials
{
public static partial class Maps
{
internal static Task PlatformOpenMapsAsync(double latitude, double longitude, MapsLaunchOptions options)
{
var uri = string.Empty;
uri = $"geo:{latitude.ToString(CultureInfo.InvariantCulture)},{longitude.ToString(CultureInfo.InvariantCulture)}?q={latitude.ToString(CultureInfo.InvariantCulture)},{longitude.ToString(CultureInfo.InvariantCulture)}";
if (!string.IsNullOrWhiteSpace(options.Name))
uri += $"({options.Name})";
StartIntent(uri);
return Task.CompletedTask;
}

internal static Task PlatformOpenMapsAsync(Placemark placemark, MapsLaunchOptions options)
{
placemark = placemark.Escape();
var uri = $"geo:0,0?q={placemark.Thoroughfare} {placemark.Locality} {placemark.AdminArea} {placemark.CountryName}";
if (!string.IsNullOrWhiteSpace(options.Name))
uri += $"({options.Name})";
StartIntent(uri);
return Task.CompletedTask;
}

static void StartIntent(string uri)
{
var intent = new Intent(Intent.ActionView, AndroidUri.Parse(uri));
intent.SetFlags(ActivityFlags.ClearTop);
intent.SetFlags(ActivityFlags.NewTask);
Platform.AppContext.StartActivity(intent);
}
}
}
Loading

0 comments on commit 1c14a29

Please sign in to comment.