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; namespace Xamarin.Forms.Maps.Tizen { 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(); } } } }