Add some map elements like FABs and give their actions

This commit is contained in:
neslihanturan 2019-09-05 18:35:18 +03:00
parent c7261ca823
commit 7a06073185
6 changed files with 350 additions and 8 deletions

View file

@ -1,6 +1,7 @@
package fr.free.nrw.commons.nearby; package fr.free.nrw.commons.nearby;
import android.Manifest; import android.Manifest;
import android.app.AlertDialog;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
@ -11,15 +12,21 @@ import android.view.Gravity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ProgressBar;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentTransaction; import androidx.fragment.app.FragmentTransaction;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar; import com.google.android.material.snackbar.Snackbar;
import com.mapbox.mapboxsdk.Mapbox; import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.maps.MapboxMapOptions; import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
@ -29,17 +36,22 @@ import com.mapbox.mapboxsdk.maps.Style;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.R; import fr.free.nrw.commons.R;
import fr.free.nrw.commons.contributions.MainActivity; import fr.free.nrw.commons.contributions.MainActivity;
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
import fr.free.nrw.commons.kvstore.JsonKvStore; import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.location.LocationServiceManager; import fr.free.nrw.commons.location.LocationServiceManager;
import fr.free.nrw.commons.nearby.mvp.contract.NearbyParentFragmentContract; import fr.free.nrw.commons.nearby.mvp.contract.NearbyParentFragmentContract;
import fr.free.nrw.commons.nearby.mvp.fragments.NearbyParentFragment;
import fr.free.nrw.commons.nearby.mvp.presenter.NearbyParentFragmentPresenter; import fr.free.nrw.commons.nearby.mvp.presenter.NearbyParentFragmentPresenter;
import fr.free.nrw.commons.theme.NavigationBaseActivity;
import fr.free.nrw.commons.utils.FragmentUtils; import fr.free.nrw.commons.utils.FragmentUtils;
import fr.free.nrw.commons.utils.NetworkUtils; import fr.free.nrw.commons.utils.NetworkUtils;
import fr.free.nrw.commons.utils.PermissionUtils; import fr.free.nrw.commons.utils.PermissionUtils;
import fr.free.nrw.commons.utils.ViewUtil;
import io.reactivex.Observable; import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers; import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers; import io.reactivex.schedulers.Schedulers;
@ -52,6 +64,25 @@ import static fr.free.nrw.commons.nearby.NearbyTestFragmentLayersActivity.CONTRI
public class NearbyTestLayersFragment extends CommonsDaggerSupportFragment implements NearbyParentFragmentContract.View { public class NearbyTestLayersFragment extends CommonsDaggerSupportFragment implements NearbyParentFragmentContract.View {
@BindView(R.id.fab_plus)
FloatingActionButton fabPlus;
@BindView(R.id.fab_camera)
FloatingActionButton fabCamera;
@BindView(R.id.fab_gallery)
FloatingActionButton fabGallery;
@BindView(R.id.fab_recenter)
FloatingActionButton fabRecenter;
@BindView(R.id.bottom_sheet)
View bottomSheetList;
@BindView(R.id.bottom_sheet_details)
View bottomSheetDetails;
@Inject @Inject
LocationServiceManager locationManager; LocationServiceManager locationManager;
@ -61,17 +92,32 @@ public class NearbyTestLayersFragment extends CommonsDaggerSupportFragment imple
@Inject @Inject
@Named("default_preferences") @Named("default_preferences")
JsonKvStore applicationKvStore; JsonKvStore applicationKvStore;
private BottomSheetBehavior bottomSheetListBehavior;
private BottomSheetBehavior bottomSheetDetailsBehavior;
private Animation rotate_backward;
private Animation fab_close;
private Animation fab_open;
private Animation rotate_forward;
private static final double ZOOM_LEVEL = 14f; private static final double ZOOM_LEVEL = 14f;
private final String NETWORK_INTENT_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; private final String NETWORK_INTENT_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
private BroadcastReceiver broadcastReceiver; private BroadcastReceiver broadcastReceiver;
private boolean isNetworkErrorOccurred = false; private boolean isNetworkErrorOccurred = false;
private Snackbar snackbar; private Snackbar snackbar;
FragmentTransaction transaction;
View view; View view;
NearbyParentFragmentPresenter nearbyParentFragmentPresenter; NearbyParentFragmentPresenter nearbyParentFragmentPresenter;
SupportMapFragment mapFragment; SupportMapFragment mapFragment;
boolean isDarkTheme; boolean isDarkTheme;
boolean isFabOpen;
boolean isBottomListSheetExpanded;
private final double CAMERA_TARGET_SHIFT_FACTOR_PORTRAIT = 0.06;
private final double CAMERA_TARGET_SHIFT_FACTOR_LANDSCAPE = 0.04;
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
@ -86,7 +132,24 @@ public class NearbyTestLayersFragment extends CommonsDaggerSupportFragment imple
@Override @Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState); super.onViewCreated(view, savedInstanceState);
setMapFragment(savedInstanceState);
}
public void initViews() {
Timber.d("init views called");
ButterKnife.bind(this, view);
bottomSheetListBehavior = BottomSheetBehavior.from(bottomSheetList);
bottomSheetDetailsBehavior = BottomSheetBehavior.from(bottomSheetDetails);
bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
bottomSheetDetails.setVisibility(View.VISIBLE);
fab_open = AnimationUtils.loadAnimation(getActivity(), R.anim.fab_open);
fab_close = AnimationUtils.loadAnimation(getActivity(), R.anim.fab_close);
rotate_forward = AnimationUtils.loadAnimation(getActivity(), R.anim.rotate_forward);
rotate_backward = AnimationUtils.loadAnimation(getActivity(), R.anim.rotate_backward);
}
public void setMapFragment(Bundle savedInstanceState) {
// Mapbox access token is configured here. This needs to be called either in your application // Mapbox access token is configured here. This needs to be called either in your application
// object or in the same activity which contains the mapview. // object or in the same activity which contains the mapview.
Mapbox.getInstance(getActivity(), getString(R.string.mapbox_commons_app_token)); Mapbox.getInstance(getActivity(), getString(R.string.mapbox_commons_app_token));
@ -95,7 +158,7 @@ public class NearbyTestLayersFragment extends CommonsDaggerSupportFragment imple
if (savedInstanceState == null) { if (savedInstanceState == null) {
// Create fragment // Create fragment
FragmentTransaction transaction = getChildFragmentManager().beginTransaction(); transaction = getChildFragmentManager().beginTransaction();
// Build mapboxMap // Build mapboxMap
isDarkTheme = applicationKvStore.getBoolean("theme", false); isDarkTheme = applicationKvStore.getBoolean("theme", false);
@ -145,12 +208,16 @@ public class NearbyTestLayersFragment extends CommonsDaggerSupportFragment imple
* it is attached. * it is attached.
*/ */
public void childMapFragmentAttached() { public void childMapFragmentAttached() {
Log.d("denemeTest","this:"+this+", location manager is:"+locationManager); Log.d("denemeTest","this:"+this+", location manager is:"+locationManager);
nearbyParentFragmentPresenter = new NearbyParentFragmentPresenter nearbyParentFragmentPresenter = new NearbyParentFragmentPresenter
(this, mapFragment, locationManager); (this, mapFragment, locationManager);
Timber.d("Child fragment attached"); Timber.d("Child fragment attached");
nearbyParentFragmentPresenter.nearbyFragmentsAreReady(); nearbyParentFragmentPresenter.nearbyFragmentsAreReady();
//checkPermissionsAndPerformAction(this::registerLocationUpdates); //checkPermissionsAndPerformAction(this::registerLocationUpdates);
initViews();
nearbyParentFragmentPresenter.setActionListeners(applicationKvStore);
} }
@Override @Override
@ -292,4 +359,87 @@ public class NearbyTestLayersFragment extends CommonsDaggerSupportFragment imple
public void resumeFragment() { public void resumeFragment() {
} }
/**
* Starts animation of fab plus (turning on opening) and other FABs
* @param isFabOpen state of FAB buttons, open when clicked on fab button, closed on other click
*/
@Override
public void animateFABs() {
this.isFabOpen = !isFabOpen;
if (fabPlus.isShown()){
if (isFabOpen) {
fabPlus.startAnimation(rotate_backward);
fabCamera.startAnimation(fab_close);
fabGallery.startAnimation(fab_close);
fabCamera.hide();
fabGallery.hide();
} else {
fabPlus.startAnimation(rotate_forward);
fabCamera.startAnimation(fab_open);
fabGallery.startAnimation(fab_open);
fabCamera.show();
fabGallery.show();
}
this.isFabOpen=!isFabOpen;
}
}
@Override
public void displayLoginSkippedWarning() {
if (applicationKvStore.getBoolean("login_skipped", false)) {
// prompt the user to login
new AlertDialog.Builder(getContext())
.setMessage(R.string.login_alert_message)
.setPositiveButton(R.string.login, (dialog, which) -> {
// logout of the app
//TODO:
// ((NavigationBaseActivity)getActivity()).BaseLogoutListener logoutListener = new ((NavigationBaseActivity)getActivity()).BaseLogoutListener();
// CommonsApplication app = (CommonsApplication) getActivity().getApplication();
// app.clearApplicationData(getContext(), logoutListener);
})
.show();
}
}
@Override
public void setFABPlusAction(View.OnClickListener onClickListener) {
fabPlus.setOnClickListener(onClickListener);
}
@Override
public void setFABRecenterAction(View.OnClickListener onClickListener) {
fabRecenter.setOnClickListener(onClickListener);
}
@Override
public void recenterMap(fr.free.nrw.commons.location.LatLng curLatLng) {
CameraPosition position;
if (ViewUtil.isPortrait(getActivity())){
position = new CameraPosition.Builder()
.target(isBottomListSheetExpanded ?
new LatLng(curLatLng.getLatitude() - CAMERA_TARGET_SHIFT_FACTOR_PORTRAIT,
curLatLng.getLongitude())
: new LatLng(curLatLng.getLatitude(), curLatLng.getLongitude(), 0)) // Sets the new camera position
.zoom(isBottomListSheetExpanded ?
ZOOM_LEVEL
:mapFragment.getMapboxMap().getCameraPosition().zoom) // Same zoom level
.build();
}else {
position = new CameraPosition.Builder()
.target(isBottomListSheetExpanded ?
new LatLng(curLatLng.getLatitude() - CAMERA_TARGET_SHIFT_FACTOR_LANDSCAPE,
curLatLng.getLongitude())
: new LatLng(curLatLng.getLatitude(), curLatLng.getLongitude(), 0)) // Sets the new camera position
.zoom(isBottomListSheetExpanded ?
ZOOM_LEVEL
:mapFragment.getMapboxMap().getCameraPosition().zoom) // Same zoom level
.build();
}
mapFragment.getMapboxMap().animateCamera(CameraUpdateFactory.newCameraPosition(position), 1000);
}
} }

View file

@ -475,7 +475,7 @@ public class SupportMapFragment extends CommonsDaggerSupportFragment
@Override @Override
public MapboxMap getMapboxMap() { public MapboxMap getMapboxMap() {
return null; return mapboxMap;
} }
@Override @Override

View file

@ -1,7 +1,10 @@
package fr.free.nrw.commons.nearby.mvp.contract; package fr.free.nrw.commons.nearby.mvp.contract;
import android.view.View;
import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.MapboxMap;
import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.location.LatLng; import fr.free.nrw.commons.location.LatLng;
import fr.free.nrw.commons.location.LocationServiceManager; import fr.free.nrw.commons.location.LocationServiceManager;
@ -21,6 +24,11 @@ public interface NearbyParentFragmentContract {
void setSearchThisAreaProgressVisibility(boolean isVisible); void setSearchThisAreaProgressVisibility(boolean isVisible);
void checkPermissionsAndPerformAction(Runnable runnable); void checkPermissionsAndPerformAction(Runnable runnable);
void resumeFragment(); void resumeFragment();
void displayLoginSkippedWarning();
void setFABPlusAction(android.view.View.OnClickListener onClickListener);
void setFABRecenterAction(android.view.View.OnClickListener onClickListener);
void animateFABs();
void recenterMap(LatLng curLatLng);
} }
interface UserActions { interface UserActions {
@ -30,6 +38,7 @@ public interface NearbyParentFragmentContract {
void updateMapAndList(LocationServiceManager.LocationChangeType locationChangeType, LatLng cameraTarget); void updateMapAndList(LocationServiceManager.LocationChangeType locationChangeType, LatLng cameraTarget);
void lockNearby(boolean isNearbyLocked); void lockNearby(boolean isNearbyLocked);
MapboxMap.OnCameraMoveListener onCameraMove(MapboxMap mapboxMap); MapboxMap.OnCameraMoveListener onCameraMove(MapboxMap mapboxMap);
void setActionListeners(JsonKvStore applicationKvStore);
} }
interface ViewsAreReadyCallback { interface ViewsAreReadyCallback {

View file

@ -322,6 +322,31 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
addNetworkBroadcastReceiver(); addNetworkBroadcastReceiver();
}
@Override
public void displayLoginSkippedWarning() {
}
@Override
public void setFABPlusAction(View.OnClickListener onClickListener) {
}
@Override
public void setFABRecenterAction(View.OnClickListener onClickListener) {
}
@Override
public void animateFABs() {
}
@Override
public void recenterMap(LatLng curLatLng) {
} }
@Override @Override

View file

@ -5,6 +5,7 @@ import android.view.View;
import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.MapboxMap;
import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.location.LatLng; import fr.free.nrw.commons.location.LatLng;
import fr.free.nrw.commons.location.LocationServiceManager; import fr.free.nrw.commons.location.LocationServiceManager;
import fr.free.nrw.commons.location.LocationUpdateListener; import fr.free.nrw.commons.location.LocationUpdateListener;
@ -153,6 +154,25 @@ public class NearbyParentFragmentPresenter
this.nearbyMapFragmentView.addOnCameraMoveListener(onCameraMove(getMapboxMap())); this.nearbyMapFragmentView.addOnCameraMoveListener(onCameraMove(getMapboxMap()));
} }
/**
* Sets click listeners of FABs, and 2 bottom sheets
*/
@Override
public void setActionListeners(JsonKvStore applicationKvStore) {
nearbyParentFragmentView.setFABPlusAction(v -> {
if (applicationKvStore.getBoolean("login_skipped", false)) {
// prompt the user to login
nearbyParentFragmentView.displayLoginSkippedWarning();
}else {
nearbyParentFragmentView.animateFABs();
}
});
nearbyParentFragmentView.setFABRecenterAction(v -> {
nearbyParentFragmentView.recenterMap(curLatLng);
});
}
/** /**
* Nearby updates takes time, since they are network operations. During update time, we don't * Nearby updates takes time, since they are network operations. During update time, we don't

View file

@ -1,5 +1,16 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/status_bar_blue">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent" android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
@ -8,4 +19,131 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent" />
</LinearLayout> </LinearLayout>
<View
android:id="@+id/transparentView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/toolbar"
android:layout_alignParentLeft="true"
android:background="#aa969696"
android:visibility="gone"
android:elevation="6dp">
</View>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_recenter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/toolbar"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:clickable="true"
android:visibility="visible"
app:backgroundTint="@color/main_background_light"
app:elevation="6dp"
app:fabSize="normal"
app:layout_anchorGravity="top|right|end"
app:srcCompat="@drawable/ic_my_location_black_24dp"
app:useCompatPadding="true" />
</RelativeLayout>
<include layout="@layout/bottom_sheet_nearby" />
<include
android:id="@+id/bottom_sheet_details"
layout="@layout/bottom_sheet_details" />
<Button
android:id="@+id/search_this_area_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_gravity="center_horizontal"
android:layout_margin="8dp"
android:background="@color/white"
android:padding="8dp"
android:singleLine="true"
android:text="@string/search_this_area"
android:textColor="@color/status_bar_blue"
android:visibility="gone"
app:elevation="6dp" />
<ProgressBar
android:id="@+id/search_this_area_button_progress_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:visibility="gone" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_plus"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_marginEnd="12dp"
android:layout_marginRight="12dp"
android:clickable="true"
android:visibility="invisible"
app:backgroundTint="@color/button_blue"
app:elevation="8dp"
app:fabSize="normal"
app:layout_anchor="@id/bottom_sheet_details"
app:layout_anchorGravity="top|right|end"
app:pressedTranslationZ="12dp"
app:srcCompat="@drawable/ic_add_white_24dp"
app:useCompatPadding="true" />
<View
android:id="@+id/empty_view1"
android:layout_width="56dp"
android:layout_height="174dp"
android:visibility="invisible"
app:layout_anchor="@id/fab_plus"
app:layout_anchorGravity="center_horizontal" />
<View
android:id="@+id/empty_view"
android:layout_width="56dp"
android:layout_height="46dp"
android:visibility="invisible"
app:layout_anchor="@id/fab_plus"
app:layout_anchorGravity="center_horizontal" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_camera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="center"
android:tint="@color/button_blue"
android:visibility="invisible"
app:backgroundTint="@color/main_background_light"
app:elevation="6dp"
app:fabSize="mini"
app:layout_anchor="@id/empty_view1"
app:layout_anchorGravity="center_horizontal"
app:pressedTranslationZ="12dp"
app:srcCompat="@drawable/ic_photo_camera_white_24dp" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_gallery"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="center"
android:tint="@color/button_blue"
android:visibility="invisible"
app:backgroundTint="@color/main_background_light"
app:elevation="6dp"
app:fabSize="mini"
app:layout_anchor="@id/empty_view"
app:layout_anchorGravity="center_horizontal"
app:pressedTranslationZ="12dp"
app:srcCompat="@drawable/ic_photo_white_24dp" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>