diff --git a/.gitignore b/.gitignore index e54ea2551..7fa4767a7 100644 --- a/.gitignore +++ b/.gitignore @@ -46,4 +46,5 @@ captures/* # Test and other output app/jacoco.exec -app/CommonsContributions \ No newline at end of file +app/CommonsContributions +app/.* diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.java b/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.java index 03027f287..047943721 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.java @@ -207,6 +207,9 @@ public class MainActivity extends BaseActivity private boolean loadFragment(Fragment fragment, boolean showBottom) { //showBottom so that we do not show the bottom tray again when constructing //from the saved instance state. + + freeUpFragments(); + if (fragment instanceof ContributionsFragment) { if (activeFragment == ActiveFragment.CONTRIBUTIONS) { // scroll to top if already on the Contributions tab @@ -256,6 +259,31 @@ public class MainActivity extends BaseActivity return false; } + /** + * loadFragment() overload that supports passing extras to fragments + **/ + private boolean loadFragment(Fragment fragment, boolean showBottom, Bundle args) { + if (fragment != null && args != null) { + fragment.setArguments(args); + } + + return loadFragment(fragment, showBottom); + } + + /** + * Old implementation of loadFragment() was causing memory leaks, due to MainActivity holding + * references to cleared fragments. This function frees up all fragment references. + *
+ * Called in loadFragment() before doing the actual loading.
+ **/
+ public void freeUpFragments() {
+ // free all fragments except contributionsFragment because several tests depend on it.
+ // hence, contributionsFragment is probably still a leak
+ nearbyParentFragment = null;
+ exploreFragment = null;
+ bookmarkFragment = null;
+ }
+
public void hideTabs() {
binding.fragmentMainNavTabLayout.setVisibility(View.GONE);
}
@@ -432,6 +460,42 @@ public class MainActivity extends BaseActivity
});
}
+ /**
+ * Launch the Explore fragment from Nearby fragment. This method is called when a user clicks
+ * the 'Show in Explore' option in the 3-dots menu in Nearby.
+ *
+ * @param zoom current zoom of Nearby map
+ * @param latitude current latitude of Nearby map
+ * @param longitude current longitude of Nearby map
+ **/
+ public void loadExploreMapFromNearby(double zoom, double latitude, double longitude) {
+ Bundle bundle = new Bundle();
+ bundle.putDouble("prev_zoom", zoom);
+ bundle.putDouble("prev_latitude", latitude);
+ bundle.putDouble("prev_longitude", longitude);
+
+ loadFragment(ExploreFragment.newInstance(), false, bundle);
+ setSelectedItemId(NavTab.EXPLORE.code());
+ }
+
+ /**
+ * Launch the Nearby fragment from Explore fragment. This method is called when a user clicks
+ * the 'Show in Nearby' option in the 3-dots menu in Explore.
+ *
+ * @param zoom current zoom of Explore map
+ * @param latitude current latitude of Explore map
+ * @param longitude current longitude of Explore map
+ **/
+ public void loadNearbyMapFromExplore(double zoom, double latitude, double longitude) {
+ Bundle bundle = new Bundle();
+ bundle.putDouble("prev_zoom", zoom);
+ bundle.putDouble("prev_latitude", latitude);
+ bundle.putDouble("prev_longitude", longitude);
+
+ loadFragment(NearbyParentFragment.newInstance(), false, bundle);
+ setSelectedItemId(NavTab.NEARBY.code());
+ }
+
@Override
protected void onResume() {
super.onResume();
diff --git a/app/src/main/java/fr/free/nrw/commons/explore/ExploreFragment.java b/app/src/main/java/fr/free/nrw/commons/explore/ExploreFragment.java
index d444148d4..223d028dc 100644
--- a/app/src/main/java/fr/free/nrw/commons/explore/ExploreFragment.java
+++ b/app/src/main/java/fr/free/nrw/commons/explore/ExploreFragment.java
@@ -1,5 +1,7 @@
package fr.free.nrw.commons.explore;
+import static androidx.viewpager.widget.ViewPager.SCROLL_STATE_IDLE;
+
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -42,9 +44,13 @@ public class ExploreFragment extends CommonsDaggerSupportFragment {
@Named("default_preferences")
public JsonKvStore applicationKvStore;
- public void setScroll(boolean canScroll){
- if (binding != null)
- {
+ // Nearby map state (for if we came from Nearby fragment)
+ private double prevZoom;
+ private double prevLatitude;
+ private double prevLongitude;
+
+ public void setScroll(boolean canScroll) {
+ if (binding != null) {
binding.viewPager.setCanScroll(canScroll);
}
}
@@ -60,6 +66,7 @@ public class ExploreFragment extends CommonsDaggerSupportFragment {
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ loadNearbyMapData();
binding = FragmentExploreBinding.inflate(inflater, container, false);
viewPagerAdapter = new ViewPagerAdapter(getChildFragmentManager());
@@ -89,6 +96,11 @@ public class ExploreFragment extends CommonsDaggerSupportFragment {
});
setTabs();
setHasOptionsMenu(true);
+
+ // if we came from 'Show in Explore' in Nearby, jump to Map tab
+ if (isCameFromNearbyMap()) {
+ binding.viewPager.setCurrentItem(2);
+ }
return binding.getRoot();
}
@@ -108,6 +120,13 @@ public class ExploreFragment extends CommonsDaggerSupportFragment {
Bundle mapArguments = new Bundle();
mapArguments.putString("categoryName", EXPLORE_MAP);
+ // if we came from 'Show in Explore' in Nearby, pass on zoom and center to Explore map root
+ if (isCameFromNearbyMap()) {
+ mapArguments.putDouble("prev_zoom", prevZoom);
+ mapArguments.putDouble("prev_latitude", prevLatitude);
+ mapArguments.putDouble("prev_longitude", prevLongitude);
+ }
+
featuredRootFragment = new ExploreListRootFragment(featuredArguments);
mobileRootFragment = new ExploreListRootFragment(mobileArguments);
mapRootFragment = new ExploreMapRootFragment(mapArguments);
@@ -120,13 +139,35 @@ public class ExploreFragment extends CommonsDaggerSupportFragment {
fragmentList.add(mapRootFragment);
titleList.add(getString(R.string.explore_tab_title_map).toUpperCase(Locale.ROOT));
- ((MainActivity)getActivity()).showTabs();
+ ((MainActivity) getActivity()).showTabs();
((BaseActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(false);
viewPagerAdapter.setTabData(fragmentList, titleList);
viewPagerAdapter.notifyDataSetChanged();
}
+ /**
+ * Fetch Nearby map camera data from fragment arguments if any.
+ */
+ public void loadNearbyMapData() {
+ // get fragment arguments
+ if (getArguments() != null) {
+ prevZoom = getArguments().getDouble("prev_zoom");
+ prevLatitude = getArguments().getDouble("prev_latitude");
+ prevLongitude = getArguments().getDouble("prev_longitude");
+ }
+ }
+
+ /**
+ * Checks if fragment arguments contain data from Nearby map. if present, then the user
+ * navigated from Nearby using 'Show in Explore'.
+ *
+ * @return true if user navigated from Nearby map
+ **/
+ public boolean isCameFromNearbyMap() {
+ return prevZoom != 0.0 || prevLatitude != 0.0 || prevLongitude != 0.0;
+ }
+
public boolean onBackPressed() {
if (binding.tabLayout.getSelectedTabPosition() == 0) {
if (featuredRootFragment.backPressed()) {
@@ -155,7 +196,38 @@ public class ExploreFragment extends CommonsDaggerSupportFragment {
*/
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- inflater.inflate(R.menu.menu_search, menu);
+ // if logged in 'Show in Nearby' menu item is visible
+ if (applicationKvStore.getBoolean("login_skipped") == false) {
+ inflater.inflate(R.menu.explore_fragment_menu, menu);
+
+ MenuItem others = menu.findItem(R.id.list_item_show_in_nearby);
+
+ if (binding.viewPager.getCurrentItem() == 2) {
+ others.setVisible(true);
+ }
+
+ // if on Map tab, show all menu options, else only show search
+ binding.viewPager.addOnPageChangeListener(new OnPageChangeListener() {
+ @Override
+ public void onPageScrolled(int position, float positionOffset,
+ int positionOffsetPixels) {
+ }
+
+ @Override
+ public void onPageSelected(int position) {
+ others.setVisible((position == 2));
+ }
+
+ @Override
+ public void onPageScrollStateChanged(int state) {
+ if (state == SCROLL_STATE_IDLE && binding.viewPager.getCurrentItem() == 2) {
+ onPageSelected(2);
+ }
+ }
+ });
+ } else {
+ inflater.inflate(R.menu.menu_search, menu);
+ }
super.onCreateOptionsMenu(menu, inflater);
}
@@ -171,6 +243,9 @@ public class ExploreFragment extends CommonsDaggerSupportFragment {
case R.id.action_search:
ActivityUtils.startActivityWithFlags(getActivity(), SearchActivity.class);
return true;
+ case R.id.list_item_show_in_nearby:
+ mapRootFragment.loadNearbyMapFromExplore();
+ return true;
default:
return super.onOptionsItemSelected(item);
}
diff --git a/app/src/main/java/fr/free/nrw/commons/explore/ExploreMapRootFragment.java b/app/src/main/java/fr/free/nrw/commons/explore/ExploreMapRootFragment.java
index 2653b4409..abf02758d 100644
--- a/app/src/main/java/fr/free/nrw/commons/explore/ExploreMapRootFragment.java
+++ b/app/src/main/java/fr/free/nrw/commons/explore/ExploreMapRootFragment.java
@@ -39,10 +39,22 @@ public class ExploreMapRootFragment extends CommonsDaggerSupportFragment impleme
}
public ExploreMapRootFragment(Bundle bundle) {
+ // get fragment arguments
String title = bundle.getString("categoryName");
+ double zoom = bundle.getDouble("prev_zoom");
+ double latitude = bundle.getDouble("prev_latitude");
+ double longitude = bundle.getDouble("prev_longitude");
+
mapFragment = new ExploreMapFragment();
Bundle featuredArguments = new Bundle();
featuredArguments.putString("categoryName", title);
+
+ // if we came from 'Show in Explore' in Nearby, pass on zoom and center
+ if (zoom != 0.0 || latitude != 0.0 || longitude != 0.0) {
+ featuredArguments.putDouble("prev_zoom", zoom);
+ featuredArguments.putDouble("prev_latitude", latitude);
+ featuredArguments.putDouble("prev_longitude", longitude);
+ }
mapFragment.setArguments(featuredArguments);
}
@@ -198,7 +210,8 @@ public class ExploreMapRootFragment extends CommonsDaggerSupportFragment impleme
((MainActivity) getActivity()).showTabs();
return true;
- } if (mapFragment != null && mapFragment.isVisible()) {
+ }
+ if (mapFragment != null && mapFragment.isVisible()) {
if (mapFragment.backButtonClicked()) {
// Explore map fragment handled the event no further action required.
return true;
@@ -213,6 +226,10 @@ public class ExploreMapRootFragment extends CommonsDaggerSupportFragment impleme
return false;
}
+ public void loadNearbyMapFromExplore() {
+ mapFragment.loadNearbyMapFromExplore();
+ }
+
@Override
public void onDestroy() {
super.onDestroy();
diff --git a/app/src/main/java/fr/free/nrw/commons/explore/map/ExploreMapFragment.java b/app/src/main/java/fr/free/nrw/commons/explore/map/ExploreMapFragment.java
index ad42d9518..e64b96190 100644
--- a/app/src/main/java/fr/free/nrw/commons/explore/map/ExploreMapFragment.java
+++ b/app/src/main/java/fr/free/nrw/commons/explore/map/ExploreMapFragment.java
@@ -38,6 +38,7 @@ import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao;
+import fr.free.nrw.commons.contributions.MainActivity;
import fr.free.nrw.commons.databinding.FragmentExploreMapBinding;
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
import fr.free.nrw.commons.explore.ExploreMapRootFragment;
@@ -115,6 +116,11 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment
SystemThemeUtils systemThemeUtils;
LocationPermissionsHelper locationPermissionsHelper;
+ // Nearby map state (if we came from Nearby)
+ private double prevZoom;
+ private double prevLatitude;
+ private double prevLongitude;
+
private ExploreMapPresenter presenter;
public FragmentExploreMapBinding binding;
@@ -160,6 +166,7 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment
ViewGroup container,
Bundle savedInstanceState
) {
+ loadNearbyMapData();
binding = FragmentExploreMapBinding.inflate(getLayoutInflater());
return binding.getRoot();
}
@@ -169,12 +176,14 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment
super.onViewCreated(view, savedInstanceState);
setSearchThisAreaButtonVisibility(false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
- binding.tvAttribution.setText(Html.fromHtml(getString(R.string.map_attribution), Html.FROM_HTML_MODE_LEGACY));
+ binding.tvAttribution.setText(
+ Html.fromHtml(getString(R.string.map_attribution), Html.FROM_HTML_MODE_LEGACY));
} else {
binding.tvAttribution.setText(Html.fromHtml(getString(R.string.map_attribution)));
}
initNetworkBroadCastReceiver();
- locationPermissionsHelper = new LocationPermissionsHelper(getActivity(),locationManager,this);
+ locationPermissionsHelper = new LocationPermissionsHelper(getActivity(), locationManager,
+ this);
if (presenter == null) {
presenter = new ExploreMapPresenter(bookmarkLocationDao);
}
@@ -204,9 +213,14 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment
scaleBarOverlay.setBackgroundPaint(barPaint);
scaleBarOverlay.enableScaleBar();
binding.mapView.getOverlays().add(scaleBarOverlay);
- binding.mapView.getZoomController().setVisibility(CustomZoomButtonsController.Visibility.NEVER);
+ binding.mapView.getZoomController()
+ .setVisibility(CustomZoomButtonsController.Visibility.NEVER);
binding.mapView.setMultiTouchControls(true);
- binding.mapView.getController().setZoom(ZOOM_LEVEL);
+
+ if (!isCameFromNearbyMap()) {
+ binding.mapView.getController().setZoom(ZOOM_LEVEL);
+ }
+
performMapReadyActions();
binding.mapView.getOverlays().add(new MapEventsOverlay(new MapEventsReceiver() {
@@ -295,7 +309,7 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment
unregisterNetworkReceiver();
}
-
+
/**
* Unregisters the networkReceiver
*/
@@ -328,11 +342,51 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment
isPermissionDenied = true;
}
lastKnownLocation = MapUtils.getDefaultLatLng();
- moveCameraToPosition(
- new GeoPoint(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude()));
+
+ // if we came from 'Show in Explore' in Nearby, load Nearby map center and zoom
+ if (isCameFromNearbyMap()) {
+ moveCameraToPosition(
+ new GeoPoint(prevLatitude, prevLongitude),
+ prevZoom,
+ 1L
+ );
+ } else {
+ moveCameraToPosition(
+ new GeoPoint(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude()));
+ }
presenter.onMapReady(exploreMapController);
}
+ /**
+ * Fetch Nearby map camera data from fragment arguments if any.
+ */
+ public void loadNearbyMapData() {
+ // get fragment arguments
+ if (getArguments() != null) {
+ prevZoom = getArguments().getDouble("prev_zoom");
+ prevLatitude = getArguments().getDouble("prev_latitude");
+ prevLongitude = getArguments().getDouble("prev_longitude");
+ }
+ }
+
+ /**
+ * Checks if fragment arguments contain data from Nearby map, indicating that the user navigated
+ * from Nearby using 'Show in Explore'.
+ *
+ * @return true if user navigated from Nearby map
+ **/
+ public boolean isCameFromNearbyMap() {
+ return prevZoom != 0.0 || prevLatitude != 0.0 || prevLongitude != 0.0;
+ }
+
+ public void loadNearbyMapFromExplore() {
+ ((MainActivity) getContext()).loadNearbyMapFromExplore(
+ binding.mapView.getZoomLevelDouble(),
+ binding.mapView.getMapCenter().getLatitude(),
+ binding.mapView.getMapCenter().getLongitude()
+ );
+ }
+
private void initViews() {
Timber.d("init views called");
initBottomSheets();
@@ -346,7 +400,8 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment
*/
@SuppressLint("ClickableViewAccessibility")
private void initBottomSheets() {
- bottomSheetDetailsBehavior = BottomSheetBehavior.from(binding.bottomSheetDetailsBinding.getRoot());
+ bottomSheetDetailsBehavior = BottomSheetBehavior.from(
+ binding.bottomSheetDetailsBinding.getRoot());
bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_HIDDEN);
binding.bottomSheetDetailsBinding.getRoot().setVisibility(View.VISIBLE);
}
@@ -404,7 +459,8 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment
if (currentLatLng == null) {
return;
}
- if (currentLatLng.equals(getLastMapFocus())) { // Means we are checking around current location
+ if (currentLatLng.equals(
+ getLastMapFocus())) { // Means we are checking around current location
nearbyPlacesInfoObservable = presenter.loadAttractionsFromLocation(currentLatLng,
getLastMapFocus(), true);
} else {
@@ -416,11 +472,12 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment
.observeOn(AndroidSchedulers.mainThread())
.subscribe(explorePlacesInfo -> {
mediaList = explorePlacesInfo.mediaList;
- if(mediaList == null) {
+ if (mediaList == null) {
showResponseMessage(getString(R.string.no_pictures_in_this_area));
}
updateMapMarkers(explorePlacesInfo);
- lastMapFocus = new GeoPoint(currentLatLng.getLatitude(), currentLatLng.getLongitude());
+ lastMapFocus = new GeoPoint(currentLatLng.getLatitude(),
+ currentLatLng.getLongitude());
},
throwable -> {
Timber.d(throwable);
@@ -474,9 +531,9 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment
locationManager.requestLocationUpdatesFromProvider(LocationManager.NETWORK_PROVIDER);
locationManager.requestLocationUpdatesFromProvider(LocationManager.GPS_PROVIDER);
setProgressBarVisibility(true);
- }
- else {
- locationPermissionsHelper.showLocationOffDialog(getActivity(), R.string.ask_to_turn_location_on_text);
+ } else {
+ locationPermissionsHelper.showLocationOffDialog(getActivity(),
+ R.string.ask_to_turn_location_on_text);
}
presenter.onMapReady(exploreMapController);
registerUnregisterLocationListener(false);
@@ -508,7 +565,8 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment
recenterToUserLocation = true;
return;
}
- recenterMarkerToPosition(new GeoPoint(currentLatLng.getLatitude(), currentLatLng.getLongitude()));
+ recenterMarkerToPosition(
+ new GeoPoint(currentLatLng.getLatitude(), currentLatLng.getLongitude()));
binding.mapView.getController()
.animateTo(new GeoPoint(currentLatLng.getLatitude(), currentLatLng.getLongitude()));
if (lastMapFocus != null) {
@@ -549,7 +607,8 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment
view -> Utils.handleGeoCoordinates(getActivity(),
place.getLocation(), binding.mapView.getZoomLevelDouble()));
- binding.bottomSheetDetailsBinding.commonsButton.setVisibility(place.hasCommonsLink() ? View.VISIBLE : View.GONE);
+ binding.bottomSheetDetailsBinding.commonsButton.setVisibility(
+ place.hasCommonsLink() ? View.VISIBLE : View.GONE);
binding.bottomSheetDetailsBinding.commonsButton.setOnClickListener(
view -> Utils.handleWebUrl(getContext(), place.siteLinks.getCommonsLink()));
@@ -563,7 +622,8 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment
}
index++;
}
- binding.bottomSheetDetailsBinding.title.setText(place.name.substring(5, place.name.lastIndexOf(".")));
+ binding.bottomSheetDetailsBinding.title.setText(
+ place.name.substring(5, place.name.lastIndexOf(".")));
binding.bottomSheetDetailsBinding.category.setText(place.distance);
// Remove label since it is double information
String descriptionText = place.getLongDescription()
@@ -641,40 +701,43 @@ public class ExploreMapFragment extends CommonsDaggerSupportFragment
* @param nearbyBaseMarker The NearbyBaseMarker object representing the marker to be added.
*/
private void addMarkerToMap(BaseMarker nearbyBaseMarker) {
- ArrayList