samuelchassot/SDP-SwissTeam

View on GitHub
app/src/main/java/ch/epfl/swissteam/services/view/activities/PostsMapActivity.java

Summary

Maintainability
A
2 hrs
Test Coverage
package ch.epfl.swissteam.services.view.activities;

import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.location.Location;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.MapView;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.squareup.picasso.Picasso;
import com.squareup.picasso.Target;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import ch.epfl.swissteam.services.view.builders.PostAdapter;
import ch.epfl.swissteam.services.R;
import ch.epfl.swissteam.services.providers.SettingsDBUtility;
import ch.epfl.swissteam.services.utils.SettingsDbHelper;
import ch.epfl.swissteam.services.models.Post;
import ch.epfl.swissteam.services.models.User;
import ch.epfl.swissteam.services.providers.DBCallBack;
import ch.epfl.swissteam.services.providers.DBUtility;
import ch.epfl.swissteam.services.providers.GoogleSignInSingleton;
import ch.epfl.swissteam.services.providers.LocationManager;

/**
 * Activity to show a map with markers_ corresponding to posts
 *
 * @author Adrian Baudat
 */
public class PostsMapActivity extends NavigationDrawerActivity implements OnMapReadyCallback {

    private static final String MAPVIEW_BUNDLE_KEY = "MapViewBundleKeyPosts";

    private GoogleMap googleMap_;
    private MapView mapView_;
    private CustomInfoWindowAdapter infoWindow_;
    private List<Marker> markers_ = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_postsmap);
        super.onCreateDrawer(ToogleState.MAIN);

        Bundle mapViewBundle = null;
        if (savedInstanceState != null) {
            mapViewBundle = savedInstanceState.getBundle(MAPVIEW_BUNDLE_KEY);
        }

        mapView_ = findViewById(R.id.mapview_postsmap_map);
        mapView_.onCreate(mapViewBundle);
        mapView_.getMapAsync(this);

        infoWindow_ = new PostsMapActivity.CustomInfoWindowAdapter();

        invalidateOptionsMenu();
    }


    @Override
    public boolean onPrepareOptionsMenu(Menu menu){
        boolean toReturn = super.onPrepareOptionsMenu(menu);

        //Enable the button to switch to posts list
        menu.setGroupEnabled(R.id.group_switchtoposts, true);
        menu.setGroupVisible(R.id.group_switchtoposts, true);

        //Enable the refresh button
        menu.setGroupEnabled(R.id.group_refresh, true);
        menu.setGroupVisible(R.id.group_refresh, true);
        return toReturn;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();

        if(id == R.id.action_switchtoposts) {
            startActivity(new Intent(this, MainActivity.class));
        }
        else if(id == R.id.action_refresh) {
            updateMapView();
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onStart() {
        super.onStart();
        mapView_.onStart();
    }

    @Override
    public void onResume() {
        super.onResume();
        mapView_.onResume();
    }

    @Override
    public void onStop() {
        super.onStop();
        mapView_.onStop();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mapView_.onDestroy();
    }

    @Override
    public void onPause() {
        super.onPause();
        mapView_.onPause();
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
        mapView_.onLowMemory();
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        Bundle mapViewBundle = outState.getBundle(MAPVIEW_BUNDLE_KEY);
        if (mapViewBundle == null) {
            mapViewBundle = new Bundle();
            outState.putBundle(MAPVIEW_BUNDLE_KEY, mapViewBundle);
        }

        mapView_.onSaveInstanceState(mapViewBundle);
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        super.onMapReady(googleMap);
        googleMap_ = googleMap;
        googleMap_.setMinZoomPreference(12);
        double zoomLevel = calculateZoomLevel();
        googleMap_.moveCamera(CameraUpdateFactory.zoomTo((float)zoomLevel));
        googleMap_.setMinZoomPreference(6);
        googleMap_.setMaxZoomPreference(20);
        googleMap_.setInfoWindowAdapter(infoWindow_);

        googleMap_.setOnMarkerClickListener(marker -> {
            marker.showInfoWindow();
            return false;
        });
        googleMap_.setOnInfoWindowClickListener(marker -> {
            Post post = (Post)marker.getTag();
            Intent intent = new Intent(this, PostActivity.class);
            intent.putExtra(PostAdapter.POST_TAG, post);
            startActivity(intent);
        });


        updateMapView();
    }

    private double calculateZoomLevel() {
        DisplayMetrics metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);
        int screenWidth = metrics.widthPixels;
        int radius = SettingsDBUtility.retrieveRadius(new SettingsDbHelper(this), GoogleSignInSingleton.get().getClientUniqueID());
        double equatorLength = 40075004; // in meters
        double zoom256 = Math.log(equatorLength/radius)/Math.log(2);
        int x = (int) (Math.log(screenWidth/256)/Math.log(2));
        double zoom = zoom256 + x;
        return zoom;
    }

    private void updateMapView() {
        Location currentLocation = LocationManager.get().getCurrentLocation_();

        if(currentLocation != null) {
            //Move camera to the current location
            LatLng newLatLng = new LatLng(currentLocation.getLatitude(), currentLocation.getLongitude());
            googleMap_.moveCamera(CameraUpdateFactory.newLatLng(newLatLng));

            //Remove all markers
            for(Marker marker : markers_) {
                marker.remove();
            }

            DBUtility.get().getPostsFeed(new DBCallBack<ArrayList<Post>>() {
                @Override
                public void onCallBack(ArrayList<Post> value) {
                    //For each post in the feed, load the username and the image asynchronously, then create a marker at the post location
                    for (Post post : value) {
                        MarkerOptions newMarkerOptions = new MarkerOptions().position(new LatLng(post.getLatitude_(), post.getLongitude_()));
                        DBUtility.get().getUser(post.getGoogleId_(), user -> {
                            Picasso.get().load(user.getImageUrl_()).into(new Target() {
                                @Override
                                public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
                                    infoWindow_.addUser(post.getGoogleId_(), user, bitmap);
                                    Marker newMarker = googleMap_.addMarker(newMarkerOptions);
                                    newMarker.setTag(post);
                                    markers_.add(newMarker);
                                }

                                @Override
                                public void onBitmapFailed(Exception e, Drawable errorDrawable) {

                                }

                                @Override
                                public void onPrepareLoad(Drawable placeHolderDrawable) {

                                }
                            });
                        });
                    }
                }
            }, currentLocation, new SettingsDbHelper(this));
        }
    }

    /**
     * Info window to show when a marker is clicked on the map
     *
     * @author Adrian Baudat
     */
    class CustomInfoWindowAdapter implements GoogleMap.InfoWindowAdapter {
        private final View mContents_;

        private Map<String, User> users = new HashMap<>();
        private Map<String, Bitmap> pictures = new HashMap<>();

        CustomInfoWindowAdapter() {
            mContents_ = getLayoutInflater().inflate(R.layout.mapinfo_window, null);
        }

        public void addUser(String googleId, User user, Bitmap picture){
            users.put(googleId, user);
            pictures.put(googleId, picture);
        }

        @Override
        public View getInfoContents(Marker marker) {
            return null;
        }

        @Override
        public View getInfoWindow(Marker marker) {
            Post post = (Post)marker.getTag();
            ((TextView)mContents_.findViewById(R.id.textview_mapinfo_post)).setText(post.getTitle_());
            if(users.containsKey(post.getGoogleId_())) {
                User user = users.get(post.getGoogleId_());
                ((TextView) mContents_.findViewById(R.id.textview_mapinfo_name)).setText(user.getName_());
            }
            else{
                ((TextView) mContents_.findViewById(R.id.textview_mapinfo_name)).setText(getResources().getString(R.string.map_info_unknownuser));
            }
            if(pictures.containsKey(post.getGoogleId_())) {
                Bitmap bitmap = pictures.get(post.getGoogleId_());
                ((ImageView) mContents_.findViewById(R.id.imageview_mapinfo_picture)).setImageBitmap(bitmap);
            }
            else{
                ((ImageView) mContents_.findViewById(R.id.imageview_mapinfo_picture)).setImageBitmap(null);
            }
            return mContents_;
        }
    }
}