private void RefreshView(AddRemoveCollection addRemoveCollection, CancellationToken token) { if (token.IsCancellationRequested) { return; } // remove out of view items foreach (var station in Items.Where(t => addRemoveCollection.ToRemove.Contains(t)).ToList()) { var item = StationControls.First(c => c.Station.Latitude == station.Latitude && c.Station.Longitude == station.Longitude); _clusterManager.RemoveItem(item); StationControls.Remove(item); Items.Remove(station); station.Control = null; if (station.IsInRefreshPool) { _contractService.RemoveStationFromRefreshingPool(station); } if (token.IsCancellationRequested) { return; } } foreach (var station in addRemoveCollection.ToAdd.Where(t => !Items.Contains(t)).ToList()) { var item = new ClusterItem(station.Latitude, station.Longitude) { Station = station }; StationControls.Add(item); _clusterManager.AddItem(item); Items.Add(station); if (token.IsCancellationRequested) { return; } } _clusterManager.Cluster(); }
public async void OnMapReady(GoogleMap googleMap) { _gettingMap = false; // TODO TO HELP DEBUG auto download paris to help dev on performances //var contractToTest = "Paris"; //var contractService = SimpleIoc.Default.GetInstance<IContractService>(); //var contract = contractService.GetCountries().First(country => country.Contracts.Any(c => c.Name == contractToTest)).Contracts.First(c => c.Name == contractToTest); //await SimpleIoc.Default.GetInstance<ContractsViewModel>().AddOrRemoveContract(contract); _contractService = SimpleIoc.Default.GetInstance<IContractService>(); _contractService.ContractRefreshed += OnContractRefreshed; _contractService.StationRefreshed += OnStationRefreshed; // set the initial visual state of the bike/parking buttons SwitchModeStationParkingVisualState(); _map = googleMap; _maxZoom = _map.MaxZoomLevel; LoadPreviousTile(); //Setup and customize your Google Map _map.UiSettings.CompassEnabled = true; _map.UiSettings.MyLocationButtonEnabled = false; _map.UiSettings.MapToolbarEnabled = false; _map.MyLocationEnabled = true; // add padding to prevent action bar to hide the position button //var dp = (int)(48 * Resources.DisplayMetrics.Xdpi / Resources.DisplayMetrics.Density); //_map.SetPadding(0, dp, 0, 0); //_map.vie //View locationButton = suppormanagerObj.getView().findViewById(2); //var rlp = (RelativeLayout.LayoutParams)locationButton.getLayoutParams(); //// position on right bottom //rlp.addRule(RelativeLayout.ALIGN_PARENT_TOP, 0); rlp.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, RelativeLayout.TRUE); // Initialize the camera position SetViewPoint(await GetStartingCameraPosition(), false); // Initialize the marker with the stations _clusterManager = new ClusterManager(this, _map); _clusterRender = new StationRenderer(this, _map, _clusterManager); _clusterManager.SetRenderer(_clusterRender); _map.SetOnCameraChangeListener(_clusterManager); // this disable the rest of the event handlers // so there is no way to distinct a click on a cluster and a marker _map.MarkerClick += _map_MarkerClick; //_map.SetOnMarkerClickListener(new OnMarkerClickListener()); //_clusterManager.SetOnClusterClickListener(this); //_clusterManager.SetOnClusterItemClickListener(this); // check if the app contains a least one city, otherwise, tells the user to download one MainViewModel.MainPageLoadedCommand.Execute(null); // On long click, display the address on a info window Observable.FromEventPattern<GoogleMap.MapLongClickEventArgs>(_map, "MapLongClick") .Subscribe(e => { AddPlaceMarker(e.EventArgs.Point, null, null); SelectItem(e.EventArgs.Point); //IList<Address> addresses = new List<Address>(); //try //{ // // Convert latitude and longitude to an address (GeoCoder) // addresses = await (new Geocoder(this).GetFromLocationAsync(currentMarkerPosition.Latitude, currentMarkerPosition.Longitude, 1)); //} //catch (Exception ex) //{ // Log.Debug("MyActivity", "Geocoder crashed: " + ex.Message); //} //return new AddressesFromLocationDTO { Addresses = addresses, Location = FormatLatLng(e.EventArgs.Point) }; }); _map.MapClick += _map_MapClick; if (_parameterLat != 0 && _parameterLon != 0) { ShowIntentLocation(); } else { // center the map on last user location GetPreviousLastUserLocation(); } // Initialize the behavior when long clicking somewhere on the map //_map.MapLongClick += async (sender, e) => //{ // // On long click, display the address on a info window // if (longClickMarker != null) // { // // Remove a previously created marker // longClickMarker.Remove(); // } // IList<Address> addresses = new List<Address>(); // currentMarkerPosition = e.Point; // var latLongString = $"(latitude: { Math.Round(currentMarkerPosition.Latitude)}, longitude: { Math.Round(currentMarkerPosition.Longitude, 4)})"; // try // { // // Resolve the addresses (can throw an exception) // var task = new Geocoder(this).GetFromLocationAsync(currentMarkerPosition.Latitude, currentMarkerPosition.Longitude, 1); // AddressesFromLocationStream.OnNext(new AddressesFromLocationDTO { AddressesTask = task, Location = currentMarkerPosition }); // } // catch (Exception) // { // // Ignore // } // finally // { // AddressesFromLocationStream.OnNext(new AddressesFromLocationDTO { Addresses = addresses, Location = currentMarkerPosition }); // } //}; _contractService = SimpleIoc.Default.GetInstance<IContractService>(); var mapObserver = Observable.FromEventPattern(_map, "CameraChange"); TaskCompletionSource<bool> tcs; mapObserver .Do((e) => { if (_map.CameraPosition.Zoom > _maxZoom) { _map.MoveCamera(CameraUpdateFactory.ZoomTo(_maxZoom)); } cts.Cancel(); cts = new CancellationTokenSource(); }).Throttle(throttleTime) .Select(async x => { var stations = _contractService.GetStations(); // some services can provide wrong values in lat or lon... just take care of it foreach (var station in stations.Where(s => s.Location == null)) { station.Location = new LatLng(station.Latitude, station.Longitude); } LatLngBounds bounds = null; tcs = new TaskCompletionSource<bool>(); RunOnUiThread(() => { try { // can return null bounds = _map.Projection.VisibleRegion.LatLngBounds; } catch { } tcs.SetResult(true); }); await tcs.Task; var collection = new AddRemoveCollection(); if (bounds != null) { // extends slightly the bound view // to provide a better experience //bounds = MapHelper.extendLimits(bounds, 1); collection.ToRemove = Items.Where(t => !bounds.Contains((LatLng)t.Location)).ToList(); collection.ToAdd = stations.Where(t => !Items.Contains(t) && bounds.Contains((LatLng)t.Location)).Take(MAX_CONTROLS).ToList(); if (Items.Count > MAX_CONTROLS + collection.ToRemove.Count) collection.ToAdd.Clear(); } // precalculate the items offset (that deffer well calculation) //foreach (var velib in collection.ToAdd) //{ // velib.GetOffsetLocation2(leftCornerLocation, zoomLevel); //} return collection; }) .Switch() .Subscribe(x => { if (x == null) return; RunOnUiThread(() => { RefreshView(x, cts.Token); }); }); }