From 28ad177fd48d37e4110b636cc17330d8dd08eb5f Mon Sep 17 00:00:00 2001 From: chungryeol lim Date: Tue, 20 Dec 2016 20:16:18 +0900 Subject: Add MapRenderer to enable Xamarin.Forms.Maps on Tizen - Implementation of MapRenderer under Xamarin.Forms.Maps.Tizen - Implementation of FormsMaps to initialize Tizen Map - Implementation of GeocoderBackend TASK=TCAPI2044 Change-Id: I4b6f15b5190767ca0c92bb27c383af5f66ae5328 --- Xamarin.Forms.Maps.Tizen/FormsMaps.cs | 54 +++- Xamarin.Forms.Maps.Tizen/GeocoderBackend.cs | 41 +-- Xamarin.Forms.Maps.Tizen/MapControl.cs | 14 - Xamarin.Forms.Maps.Tizen/MapRenderer.cs | 287 ++++++++++++++++++--- .../Xamarin.Forms.Maps.Tizen.csproj | 1 - .../Xamarin.Forms.Maps.Tizen.project.json | 6 +- Xamarin.Forms.Maps/Properties/AssemblyInfo.cs | 1 + 7 files changed, 316 insertions(+), 88 deletions(-) mode change 100644 => 100755 Xamarin.Forms.Maps.Tizen/GeocoderBackend.cs delete mode 100755 Xamarin.Forms.Maps.Tizen/MapControl.cs mode change 100644 => 100755 Xamarin.Forms.Maps.Tizen/Xamarin.Forms.Maps.Tizen.csproj mode change 100644 => 100755 Xamarin.Forms.Maps/Properties/AssemblyInfo.cs diff --git a/Xamarin.Forms.Maps.Tizen/FormsMaps.cs b/Xamarin.Forms.Maps.Tizen/FormsMaps.cs index b41b50d8..0fd7029c 100755 --- a/Xamarin.Forms.Maps.Tizen/FormsMaps.cs +++ b/Xamarin.Forms.Maps.Tizen/FormsMaps.cs @@ -1,19 +1,49 @@ -using Xamarin.Forms.Maps.Tizen; +using System.Diagnostics; +using Tizen.Maps; +using Xamarin.Forms.Maps.Tizen; namespace Xamarin { - public static class FormsMaps - { - public static bool IsInitialized { get; private set; } + public static class FormsMaps + { + static MapService _mapService = null; - public static void Init() - { - if (IsInitialized) - return; + static string ProviderName { get; set; } - IsInitialized = true; + static string AuthenticationToken { get; set; } - GeocoderBackend.Register(); - } - } + internal static bool IsInitialized { get; private set; } + + internal static MapService MapService + { + get + { + Debug.Assert(_mapService != null, "FormsMaps is not initialized"); + return _mapService; + } + } + + public static void Init(string provider, string authenticationToken) + { + ProviderName = provider; + AuthenticationToken = authenticationToken; + Init(); + } + + internal static async void Init() + { + if (IsInitialized) + return; + var requestResult = await MapService.RequestUserConsent(ProviderName); + if (requestResult) + { + _mapService = new MapService(ProviderName, AuthenticationToken); + if (_mapService != null) + { + GeocoderBackend.Register(); + IsInitialized = true; + } + } + } + } } \ No newline at end of file diff --git a/Xamarin.Forms.Maps.Tizen/GeocoderBackend.cs b/Xamarin.Forms.Maps.Tizen/GeocoderBackend.cs old mode 100644 new mode 100755 index a18990d4..dbf93979 --- a/Xamarin.Forms.Maps.Tizen/GeocoderBackend.cs +++ b/Xamarin.Forms.Maps.Tizen/GeocoderBackend.cs @@ -1,25 +1,32 @@ using System.Collections.Generic; using System.Threading.Tasks; -using System; namespace Xamarin.Forms.Maps.Tizen { - public class Position {}; + internal class GeocoderBackend + { + public static void Register() + { + Geocoder.GetPositionsForAddressAsyncFunc = GetPositionsForAddressAsync; + Geocoder.GetAddressesForPositionFuncAsync = GetAddressesForPositionAsync; + } - internal class GeocoderBackend - { - public static void Register() - { - } + public static async Task> GetPositionsForAddressAsync(string address) + { + var request = FormsMaps.MapService.CreateGeocodeRequest(address); + var positions = new List(); + foreach (var result in await request.GetResponseAsync()) + positions.Add(new Position(result.Latitude, result.Longitude)); + return positions; + } - public static async Task> GetPositionsForAddressAsync(string address) - { - return new Position[]{}; - } - - public static async Task> GetAddressesForPositionAsync(Position position) - { - return new String[]{"Not supported"}; - } - } + public static async Task> GetAddressesForPositionAsync(Position position) + { + var request = FormsMaps.MapService.CreateReverseGeocodeRequest(position.Latitude, position.Longitude); + var addresses = new List(); + foreach (var result in await request.GetResponseAsync()) + addresses.Add(result.Freetext); + return addresses; + } + } } \ No newline at end of file diff --git a/Xamarin.Forms.Maps.Tizen/MapControl.cs b/Xamarin.Forms.Maps.Tizen/MapControl.cs deleted file mode 100755 index a10bb804..00000000 --- a/Xamarin.Forms.Maps.Tizen/MapControl.cs +++ /dev/null @@ -1,14 +0,0 @@ -using TLabel = Xamarin.Forms.Platform.Tizen.Native.Label; - -namespace Xamarin.Forms.Maps.Tizen -{ - public class MapControl : TLabel - { - public MapControl(ElmSharp.EvasObject parent) : base(parent) - { - Text = "Can not supported Maps"; - TextColor = ElmSharp.Color.Red; - } - } -} - diff --git a/Xamarin.Forms.Maps.Tizen/MapRenderer.cs b/Xamarin.Forms.Maps.Tizen/MapRenderer.cs index b7278dcc..d61f6a27 100755 --- a/Xamarin.Forms.Maps.Tizen/MapRenderer.cs +++ b/Xamarin.Forms.Maps.Tizen/MapRenderer.cs @@ -1,47 +1,250 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.ComponentModel; +using ElmSharp; +using Tizen.Location; +using Tizen.Maps; using Xamarin.Forms.Platform.Tizen; -using TForms = Xamarin.Forms.Platform.Tizen.Forms; namespace Xamarin.Forms.Maps.Tizen { - public class MapRenderer : ViewRenderer - { - public MapRenderer() - { - RegisterPropertyHandler(Map.MapTypeProperty, UpdateMapType); - RegisterPropertyHandler(Map.IsShowingUserProperty, UpdateIsShowingUser); - RegisterPropertyHandler(Map.HasScrollEnabledProperty, UpdateHasScrollEnabled); - RegisterPropertyHandler(Map.HasZoomEnabledProperty, UpdateHasZoomEnabled); - } - - protected override void OnElementChanged(ElementChangedEventArgs e) - { - base.OnElementChanged(e); - - if (Control == null) - { - var mapControl = new MapControl(TForms.Context.MainWindow); - SetNativeControl(mapControl); - } - } - - void UpdateMapType() - { - // TODO - } - - void UpdateIsShowingUser() - { - // TODO - } - - void UpdateHasScrollEnabled() - { - // TODO - } - - void UpdateHasZoomEnabled() - { - // TODO - } - } + public class MapRenderer : ViewRenderer + { + const string MoveMessageName = "MapMoveToRegion"; + + bool _disposed; + Overlay _marker; + bool _isLocatorStarted = false; + Lazy _locator = new Lazy(InitializeLocator); + Dictionary _pins = new Dictionary(); + + static Locator InitializeLocator() + { + var locator = new Locator(LocationType.Hybrid) + { + // Set the default interval to 15s same as UWP + Interval = 15 + }; + return locator; + } + + public MapRenderer() + { + } + + protected override void OnElementChanged(ElementChangedEventArgs e) + { + if (Control == null) + { + var mapControl = new MapView(Platform.Tizen.Forms.Context.MainWindow, FormsMaps.MapService); + SetNativeControl(mapControl); + } + + if (e.OldElement != null) + { + ((ObservableCollection)e.OldElement.Pins).CollectionChanged -= OnCollectionChanged; + + MessagingCenter.Unsubscribe(this, MoveMessageName); + } + if (e.NewElement != null) + { + ((ObservableCollection)e.NewElement.Pins).CollectionChanged += OnCollectionChanged; + if (e.NewElement.Pins.Count > 0) + { + AddPins(e.NewElement.Pins); + } + + MessagingCenter.Subscribe(this, MoveMessageName, OnMoveToRegion, e.NewElement); + + UpdateMapType(); + UpdateHasScrollEnabled(); + UpdateHasZoomEnabled(); + UpdateIsShowingUser(); + } + base.OnElementChanged(e); + } + + protected override void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + + _disposed = true; + + if (disposing) + { + MessagingCenter.Unsubscribe(this, "MapMoveToRegion"); + if (Element != null) + { + ((ObservableCollection)Element.Pins).CollectionChanged -= OnCollectionChanged; + } + Control.Unrealize(); + } + base.Dispose(disposing); + } + + protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) + { + base.OnElementPropertyChanged(sender, e); + + if (e.PropertyName == Map.MapTypeProperty.PropertyName) + UpdateMapType(); + else if (e.PropertyName == Map.IsShowingUserProperty.PropertyName) + UpdateIsShowingUser(); + else if (e.PropertyName == Map.HasScrollEnabledProperty.PropertyName) + UpdateHasScrollEnabled(); + else if (e.PropertyName == Map.HasZoomEnabledProperty.PropertyName) + UpdateHasZoomEnabled(); + } + + void OnMoveToRegion(Map map, MapSpan span) + { + var newCenter = new Geocoordinates(span.Center.Latitude, span.Center.Longitude); + Control.Center = newCenter; + } + + + void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + if (e.NewItems != null) + { + AddPins(e.NewItems); + } + if (e.OldItems != null) + { + RemovePins(e.OldItems); + } + if (e.Action == NotifyCollectionChangedAction.Reset) + { + ClearPins(); + } + } + + void AddPins(IEnumerable pins) + { + foreach (Pin pin in pins) + { + var coordinates = new Geocoordinates(pin.Position.Latitude, pin.Position.Longitude); + var rectangle = new Background(Platform.Tizen.Forms.Context.MainWindow); + // TODO: Need to change BubbleOverlay to default Marker + // TODO: Need to handle Pin.Clicked event + var nativePin = new BubbleOverlay(coordinates, rectangle); + Control.Add(nativePin); + _pins.Add(pin, nativePin); + } + } + + void RemovePins(IEnumerable pins) + { + foreach (Pin pin in pins) + { + if (_pins.ContainsKey(pin)) + { + Control.Remove(_pins[pin]); + _pins.Remove(pin); + } + } + } + + void ClearPins() + { + foreach (var pin in _pins) + { + Control.Remove(pin.Value); + } + _pins.Clear(); + } + + void UpdateHasZoomEnabled() + { + if (Element.HasZoomEnabled == true) + Control.ZoomChanged += Dummy; + else + Control.ZoomChanged -= Dummy; + } + + void UpdateHasScrollEnabled() + { + if (Element.HasScrollEnabled == true) + Control.Scrolled += Dummy; + else + Control.Scrolled -= Dummy; + } + + void Dummy(object sender, MapGestureEventArgs e) + { + //TODO: The implementation of Tizen.Maps needs to be changed to remove this method + } + + void ApplyIsShowingUser(Geocoordinates coordinates) + { + if (_marker == null) + { + var rectangle = new Background(Platform.Tizen.Forms.Context.MainWindow); + // TODO: Need to change BubbleOverlay to Default Overlay + _marker = new BubbleOverlay(coordinates, rectangle); + _marker.IsVisible = false; + Control.Add(_marker); + } + _marker.Coordinates = coordinates; + + if (!_marker.IsVisible) + { + _marker.IsVisible = true; + Control.Center = coordinates; + Control.ZoomLevel = 13; + } + } + void UpdateIsShowingUser() + { + if (Element.IsShowingUser) + { + _locator.Value.LocationChanged += OnLocationChanged; + if (!_isLocatorStarted) + { + _locator.Value.Start(); + _isLocatorStarted = true; + } + } + else + { + if (_locator.IsValueCreated) + { + _locator.Value.LocationChanged -= OnLocationChanged; + _locator.Value.Stop(); + _isLocatorStarted = false; + } + if (_marker != null) + _marker.IsVisible = false; + } + } + + void OnLocationChanged(object sender, LocationChangedEventArgs e) + { + ApplyIsShowingUser(new Geocoordinates(e.Location.Latitude, e.Location.Longitude)); + } + + void UpdateMapType() + { + switch (Element.MapType) + { + case MapType.Street: + Control.MapType = MapTypes.Normal; + break; + case MapType.Satellite: + Control.MapType = MapTypes.Satellite; + break; + case MapType.Hybrid: + Control.MapType = MapTypes.Hybrid; + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + } } diff --git a/Xamarin.Forms.Maps.Tizen/Xamarin.Forms.Maps.Tizen.csproj b/Xamarin.Forms.Maps.Tizen/Xamarin.Forms.Maps.Tizen.csproj old mode 100644 new mode 100755 index 9b163767..98733eeb --- a/Xamarin.Forms.Maps.Tizen/Xamarin.Forms.Maps.Tizen.csproj +++ b/Xamarin.Forms.Maps.Tizen/Xamarin.Forms.Maps.Tizen.csproj @@ -40,7 +40,6 @@ - diff --git a/Xamarin.Forms.Maps.Tizen/Xamarin.Forms.Maps.Tizen.project.json b/Xamarin.Forms.Maps.Tizen/Xamarin.Forms.Maps.Tizen.project.json index f4511fe7..c381ec60 100755 --- a/Xamarin.Forms.Maps.Tizen/Xamarin.Forms.Maps.Tizen.project.json +++ b/Xamarin.Forms.Maps.Tizen/Xamarin.Forms.Maps.Tizen.project.json @@ -2,11 +2,13 @@ "dependencies": { "ElmSharp": "1.1.0-*", "NETStandard.Library": "1.6.0", - "Tizen.Applications": "1.0.2" + "Tizen.Applications": "1.0.2", + "Tizen.Location": "1.0.3", + "Tizen.Maps": "1.0.1" }, "frameworks": { "netstandard1.6": { "imports": "portable-net45+win8+wpa81+wp8" } } -} +} \ No newline at end of file diff --git a/Xamarin.Forms.Maps/Properties/AssemblyInfo.cs b/Xamarin.Forms.Maps/Properties/AssemblyInfo.cs old mode 100644 new mode 100755 index 1e3c2f37..48d3c847 --- a/Xamarin.Forms.Maps/Properties/AssemblyInfo.cs +++ b/Xamarin.Forms.Maps/Properties/AssemblyInfo.cs @@ -17,6 +17,7 @@ using Xamarin.Forms.Internals; [assembly: InternalsVisibleTo("Xamarin.Forms.Maps.iOS")] [assembly: InternalsVisibleTo("Xamarin.Forms.Maps.iOS.Classic")] [assembly: InternalsVisibleTo("Xamarin.Forms.Maps.Android")] +[assembly: InternalsVisibleTo("Xamarin.Forms.Maps.Tizen")] [assembly: InternalsVisibleTo("Xamarin.Forms.Maps.WP8")] [assembly: InternalsVisibleTo("Xamarin.Forms.Maps.UWP")] [assembly: InternalsVisibleTo("Xamarin.Forms.Maps.WinRT.Phone")] -- cgit v1.2.3