diff --git a/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.kt b/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.kt index 8d6efd664..a61567393 100644 --- a/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.kt +++ b/app/src/main/java/fr/free/nrw/commons/contributions/MainActivity.kt @@ -28,6 +28,7 @@ import fr.free.nrw.commons.navtab.NavTabLayout import fr.free.nrw.commons.navtab.NavTabLoggedOut import fr.free.nrw.commons.nearby.Place import fr.free.nrw.commons.nearby.fragments.NearbyParentFragment +import fr.free.nrw.commons.nearby.fragments.NearbyParentFragment.NearbyParentFragmentInstanceReadyCallback import fr.free.nrw.commons.notification.NotificationActivity.Companion.startYourself import fr.free.nrw.commons.notification.NotificationController import fr.free.nrw.commons.quiz.QuizChecker @@ -460,11 +461,12 @@ after opening the app. fun centerMapToPlace(place: Place?) { setSelectedItemId(NavTab.NEARBY.code()) - nearbyParentFragment!!.setNearbyParentFragmentInstanceReadyCallback { - nearbyParentFragment!!.centerMapToPlace( - place - ) - } + nearbyParentFragment!!.setNearbyParentFragmentInstanceReadyCallback( + object : NearbyParentFragmentInstanceReadyCallback { + override fun onReady() { + nearbyParentFragment!!.centerMapToPlace(place) + } + }) } /** diff --git a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java b/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java deleted file mode 100644 index 2b64f0e37..000000000 --- a/app/src/main/java/fr/free/nrw/commons/nearby/fragments/NearbyParentFragment.java +++ /dev/null @@ -1,2468 +0,0 @@ -package fr.free.nrw.commons.nearby.fragments; - -import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.CUSTOM_QUERY; -import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED; -import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED; -import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.MAP_UPDATED; -import static fr.free.nrw.commons.wikidata.WikidataConstants.PLACE_OBJECT; - -import android.Manifest.permission; -import android.annotation.SuppressLint; -import android.app.ProgressDialog; -import android.content.ActivityNotFoundException; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.PackageManager; -import android.content.res.Configuration; -import android.graphics.Color; -import android.graphics.Paint; -import android.graphics.Paint.Style; -import android.graphics.drawable.Drawable; -import android.location.Location; -import android.location.LocationManager; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.os.Environment; -import android.os.Handler; -import android.preference.PreferenceManager; -import android.provider.Settings; -import android.text.Html; -import android.text.method.LinkMovementMethod; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.MenuItem.OnMenuItemClickListener; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.ViewGroup; -import android.view.ViewGroup.LayoutParams; -import android.view.animation.Animation; -import android.view.animation.AnimationUtils; -import android.widget.Toast; -import androidx.activity.result.ActivityResultCallback; -import androidx.activity.result.ActivityResultLauncher; -import androidx.activity.result.contract.ActivityResultContracts.RequestMultiplePermissions; -import androidx.activity.result.contract.ActivityResultContracts.RequestPermission; -import androidx.activity.result.contract.ActivityResultContracts.StartActivityForResult; -import androidx.annotation.DrawableRes; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.app.AlertDialog.Builder; -import androidx.constraintlayout.widget.ConstraintLayout; -import androidx.core.content.ContextCompat; -import androidx.core.content.FileProvider; -import androidx.lifecycle.LifecycleCoroutineScope; -import androidx.lifecycle.LifecycleOwnerKt; -import androidx.recyclerview.widget.DividerItemDecoration; -import androidx.recyclerview.widget.GridLayoutManager; -import androidx.recyclerview.widget.LinearLayoutManager; -import com.google.android.material.bottomsheet.BottomSheetBehavior; -import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback; -import com.google.android.material.snackbar.Snackbar; -import com.jakewharton.rxbinding2.view.RxView; -import com.jakewharton.rxbinding3.appcompat.RxSearchView; -import fr.free.nrw.commons.CommonsApplication; -import fr.free.nrw.commons.CommonsApplication.BaseLogoutListener; -import fr.free.nrw.commons.MapController.NearbyPlacesInfo; -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.ContributionController; -import fr.free.nrw.commons.contributions.MainActivity; -import fr.free.nrw.commons.contributions.MainActivity.ActiveFragment; -import fr.free.nrw.commons.databinding.FragmentNearbyParentBinding; -import fr.free.nrw.commons.di.CommonsDaggerSupportFragment; -import fr.free.nrw.commons.kvstore.JsonKvStore; -import fr.free.nrw.commons.location.LatLng; -import fr.free.nrw.commons.location.LocationPermissionsHelper; -import fr.free.nrw.commons.location.LocationPermissionsHelper.LocationPermissionCallback; -import fr.free.nrw.commons.location.LocationServiceManager; -import fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType; -import fr.free.nrw.commons.location.LocationUpdateListener; -import fr.free.nrw.commons.nearby.BottomSheetAdapter; -import fr.free.nrw.commons.nearby.CheckBoxTriStates; -import fr.free.nrw.commons.nearby.Label; -import fr.free.nrw.commons.nearby.MarkerPlaceGroup; -import fr.free.nrw.commons.nearby.NearbyController; -import fr.free.nrw.commons.nearby.NearbyFilterSearchRecyclerViewAdapter; -import fr.free.nrw.commons.nearby.NearbyFilterState; -import fr.free.nrw.commons.nearby.Place; -import fr.free.nrw.commons.nearby.PlacesRepository; -import fr.free.nrw.commons.nearby.Sitelinks; -import fr.free.nrw.commons.nearby.WikidataFeedback; -import fr.free.nrw.commons.nearby.contract.NearbyParentFragmentContract; -import fr.free.nrw.commons.nearby.fragments.AdvanceQueryFragment.Callback; -import fr.free.nrw.commons.nearby.model.BottomSheetItem; -import fr.free.nrw.commons.nearby.presenter.NearbyParentFragmentPresenter; -import fr.free.nrw.commons.upload.FileUtils; -import fr.free.nrw.commons.utils.DialogUtil; -import fr.free.nrw.commons.utils.ExecutorUtils; -import fr.free.nrw.commons.utils.LayoutUtils; -import fr.free.nrw.commons.utils.MapUtils; -import fr.free.nrw.commons.utils.NearbyFABUtils; -import fr.free.nrw.commons.utils.NetworkUtils; -import fr.free.nrw.commons.utils.SystemThemeUtils; -import fr.free.nrw.commons.utils.ViewUtil; -import fr.free.nrw.commons.wikidata.WikidataEditListener; -import io.reactivex.Completable; -import io.reactivex.Observable; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.TimeUnit; -import javax.inject.Inject; -import javax.inject.Named; -import kotlin.Unit; -import org.jetbrains.annotations.NotNull; -import org.osmdroid.api.IGeoPoint; -import org.osmdroid.events.MapEventsReceiver; -import org.osmdroid.events.MapListener; -import org.osmdroid.events.ScrollEvent; -import org.osmdroid.events.ZoomEvent; -import org.osmdroid.tileprovider.tilesource.TileSourceFactory; -import org.osmdroid.util.GeoPoint; -import org.osmdroid.util.constants.GeoConstants.UnitOfMeasure; -import org.osmdroid.views.CustomZoomButtonsController.Visibility; -import org.osmdroid.views.overlay.MapEventsOverlay; -import org.osmdroid.views.overlay.Marker; -import org.osmdroid.views.overlay.Overlay; -import org.osmdroid.views.overlay.ScaleBarOverlay; -import org.osmdroid.views.overlay.ScaleDiskOverlay; -import org.osmdroid.views.overlay.TilesOverlay; -import timber.log.Timber; - - -public class NearbyParentFragment extends CommonsDaggerSupportFragment - implements NearbyParentFragmentContract.View, - WikidataEditListener.WikidataP18EditListener, LocationUpdateListener, - LocationPermissionCallback, BottomSheetAdapter.ItemClickListener { - - FragmentNearbyParentBinding binding; - - public final MapEventsOverlay mapEventsOverlay = new MapEventsOverlay(new MapEventsReceiver() { - @Override - public boolean singleTapConfirmedHelper(GeoPoint p) { - if (clickedMarker != null) { - clickedMarker.closeInfoWindow(); - } else { - Timber.e("CLICKED MARKER IS NULL"); - } - if (isListBottomSheetExpanded()) { - // Back should first hide the bottom sheet if it is expanded - hideBottomSheet(); - } else if (isDetailsBottomSheetVisible()) { - hideBottomDetailsSheet(); - } - return true; - } - - @Override - public boolean longPressHelper(GeoPoint p) { - return false; - } - }); - - @Inject - LocationServiceManager locationManager; - @Inject - NearbyController nearbyController; - @Inject - @Named("default_preferences") - JsonKvStore applicationKvStore; - @Inject - BookmarkLocationsDao bookmarkLocationDao; - @Inject - PlacesRepository placesRepository; - @Inject - ContributionController controller; - @Inject - WikidataEditListener wikidataEditListener; - @Inject - SystemThemeUtils systemThemeUtils; - @Inject - CommonPlaceClickActions commonPlaceClickActions; - - private LocationPermissionsHelper locationPermissionsHelper; - private NearbyFilterSearchRecyclerViewAdapter nearbyFilterSearchRecyclerViewAdapter; - 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 float ZOOM_LEVEL = 15f; - private final String NETWORK_INTENT_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; - private BroadcastReceiver broadcastReceiver; - private boolean isNetworkErrorOccurred; - private Snackbar snackbar; - private View view; - private LifecycleCoroutineScope scope; - private NearbyParentFragmentPresenter presenter; - private boolean isDarkTheme; - private boolean isFABsExpanded; - private Place selectedPlace; - private Marker clickedMarker; - private ProgressDialog progressDialog; - private final double CAMERA_TARGET_SHIFT_FACTOR_PORTRAIT = 0.005; - private final double CAMERA_TARGET_SHIFT_FACTOR_LANDSCAPE = 0.004; - private boolean isPermissionDenied; - private boolean recenterToUserLocation; - private GeoPoint mapCenter; - IntentFilter intentFilter = new IntentFilter(NETWORK_INTENT_ACTION); - private Place lastPlaceToCenter; - private LatLng lastKnownLocation; - private boolean isVisibleToUser; - private LatLng lastFocusLocation; - private PlaceAdapter adapter; - private GeoPoint lastMapFocus; - private NearbyParentFragmentInstanceReadyCallback nearbyParentFragmentInstanceReadyCallback; - private boolean isAdvancedQueryFragmentVisible = false; - private Place nearestPlace; - private volatile boolean stopQuery; - - // Explore map data (for if we came from Explore) - private double prevZoom; - private double prevLatitude; - private double prevLongitude; - - private final Handler searchHandler = new Handler(); - private Runnable searchRunnable; - - private LatLng updatedLatLng; - private boolean searchable; - - private ConstraintLayout nearbyLegend; - - private GridLayoutManager gridLayoutManager; - private List dataList; - private BottomSheetAdapter bottomSheetAdapter; - - private final ActivityResultLauncher galleryPickLauncherForResult = - registerForActivityResult(new StartActivityForResult(), - result -> { - controller.handleActivityResultWithCallback(requireActivity(), callbacks -> { - controller.onPictureReturnedFromGallery(result, requireActivity(), callbacks); - }); - }); - - private final ActivityResultLauncher customSelectorLauncherForResult = - registerForActivityResult(new StartActivityForResult(), - result -> { - controller.handleActivityResultWithCallback(requireActivity(), callbacks -> { - controller.onPictureReturnedFromCustomSelector(result, requireActivity(), - callbacks); - }); - }); - - private final ActivityResultLauncher cameraPickLauncherForResult = - registerForActivityResult(new StartActivityForResult(), - result -> { - controller.handleActivityResultWithCallback(requireActivity(), callbacks -> { - controller.onPictureReturnedFromCamera(result, requireActivity(), callbacks); - }); - }); - - private ActivityResultLauncher inAppCameraLocationPermissionLauncher = registerForActivityResult( - new RequestMultiplePermissions(), - new ActivityResultCallback>() { - @Override - public void onActivityResult(Map result) { - boolean areAllGranted = true; - for (final boolean b : result.values()) { - areAllGranted = areAllGranted && b; - } - - if (areAllGranted) { - controller.locationPermissionCallback.onLocationPermissionGranted(); - } else { - if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) { - controller.handleShowRationaleFlowCameraLocation(getActivity(), - inAppCameraLocationPermissionLauncher, cameraPickLauncherForResult); - } else { - controller.locationPermissionCallback.onLocationPermissionDenied( - getActivity().getString( - R.string.in_app_camera_location_permission_denied)); - } - } - } - }); - - private ActivityResultLauncher locationPermissionLauncher = registerForActivityResult( - new RequestPermission(), isGranted -> { - if (isGranted) { - locationPermissionGranted(); - } else { - if (shouldShowRequestPermissionRationale(permission.ACCESS_FINE_LOCATION)) { - DialogUtil.showAlertDialog(getActivity(), - getActivity().getString(R.string.location_permission_title), - getActivity().getString(R.string.location_permission_rationale_nearby), - getActivity().getString(android.R.string.ok), - getActivity().getString(android.R.string.cancel), - () -> { - askForLocationPermission(); - }, - null, - null - ); - } else { - if (isPermissionDenied) { - locationPermissionsHelper.showAppSettingsDialog(getActivity(), - R.string.nearby_needs_location); - } - Timber.d("The user checked 'Don't ask again' or denied the permission twice"); - isPermissionDenied = true; - } - } - }); - - /** - * WLM URL - */ - public static final String WLM_URL = "https://commons.wikimedia.org/wiki/Commons:Mobile_app/Contributing_to_WLM_using_the_app"; - - @NonNull - public static NearbyParentFragment newInstance() { - NearbyParentFragment fragment = new NearbyParentFragment(); - fragment.setRetainInstance(true); - return fragment; - } - - @Override - public View onCreateView(@NonNull final LayoutInflater inflater, final ViewGroup container, - final Bundle savedInstanceState) { - loadExploreMapData(); - - binding = FragmentNearbyParentBinding.inflate(inflater, container, false); - view = binding.getRoot(); - - initNetworkBroadCastReceiver(); - scope = LifecycleOwnerKt.getLifecycleScope(getViewLifecycleOwner()); - presenter = new NearbyParentFragmentPresenter(bookmarkLocationDao, placesRepository, - nearbyController); - progressDialog = new ProgressDialog(getActivity()); - progressDialog.setCancelable(false); - progressDialog.setMessage("Saving in progress..."); - setHasOptionsMenu(true); - - // Inflate the layout for this fragment - return view; - - } - - @Override - public void onCreateOptionsMenu(@NonNull final Menu menu, - @NonNull final MenuInflater inflater) { - inflater.inflate(R.menu.nearby_fragment_menu, menu); - MenuItem refreshButton = menu.findItem(R.id.item_refresh); - MenuItem listMenu = menu.findItem(R.id.list_sheet); - MenuItem showInExploreButton = menu.findItem(R.id.list_item_show_in_explore); - MenuItem saveAsGPXButton = menu.findItem(R.id.list_item_gpx); - MenuItem saveAsKMLButton = menu.findItem(R.id.list_item_kml); - refreshButton.setOnMenuItemClickListener(new OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem item) { - try { - emptyCache(); - } catch (Exception e) { - throw new RuntimeException(e); - } - return false; - } - }); - listMenu.setOnMenuItemClickListener(new OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(MenuItem item) { - listOptionMenuItemClicked(); - return false; - } - }); - showInExploreButton.setOnMenuItemClickListener(new OnMenuItemClickListener() { - @Override - public boolean onMenuItemClick(@NonNull MenuItem item) { - ((MainActivity) getContext()).loadExploreMapFromNearby( - binding.map.getZoomLevelDouble(), - binding.map.getMapCenter().getLatitude(), - binding.map.getMapCenter().getLongitude() - ); - return false; - } - }); - saveAsGPXButton.setOnMenuItemClickListener(new OnMenuItemClickListener() { - - @Override - public boolean onMenuItemClick(@NonNull MenuItem item) { - try { - progressDialog.setTitle(getString(R.string.saving_gpx_file)); - progressDialog.show(); - savePlacesAsGPX(); - } catch (Exception e) { - throw new RuntimeException(e); - } - return false; - } - }); - saveAsKMLButton.setOnMenuItemClickListener(new OnMenuItemClickListener() { - - @Override - public boolean onMenuItemClick(@NonNull MenuItem item) { - try { - progressDialog.setTitle(getString(R.string.saving_kml_file)); - progressDialog.show(); - savePlacesAsKML(); - } catch (Exception e) { - throw new RuntimeException(e); - } - return false; - } - }); - } - - @Override - public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - isDarkTheme = systemThemeUtils.isDeviceInNightMode(); - if (Utils.isMonumentsEnabled(new Date())) { - binding.rlContainerWlmMonthMessage.setVisibility(View.VISIBLE); - } else { - binding.rlContainerWlmMonthMessage.setVisibility(View.GONE); - } - locationPermissionsHelper = new LocationPermissionsHelper(getActivity(), locationManager, - this); - - // Set up the floating activity button to toggle the visibility of the legend - binding.fabLegend.setOnClickListener(v -> { - if (binding.nearbyLegendLayout.getRoot().getVisibility() == View.VISIBLE) { - binding.nearbyLegendLayout.getRoot().setVisibility(View.GONE); - } else { - binding.nearbyLegendLayout.getRoot().setVisibility(View.VISIBLE); - } - }); - - presenter.attachView(this); - isPermissionDenied = false; - recenterToUserLocation = false; - initThemePreferences(); - initViews(); - presenter.setActionListeners(applicationKvStore); - org.osmdroid.config.Configuration.getInstance().load(this.getContext(), - PreferenceManager.getDefaultSharedPreferences(this.getContext())); - - // Use the Wikimedia tile server, rather than OpenStreetMap (Mapnik) which has various - // restrictions that we do not satisfy. - binding.map.setTileSource(TileSourceFactory.WIKIMEDIA); - binding.map.setTilesScaledToDpi(true); - - // Add referer HTTP header because the Wikimedia tile server requires it. - // This was suggested by Dmitry Brant within an email thread between us and WMF. - org.osmdroid.config.Configuration.getInstance().getAdditionalHttpRequestProperties().put( - "Referer", "http://maps.wikimedia.org/" - ); - - if (applicationKvStore.getString("LastLocation") - != null) { // Checking for last searched location - String[] locationLatLng = applicationKvStore.getString("LastLocation").split(","); - lastMapFocus = new GeoPoint(Double.valueOf(locationLatLng[0]), - Double.valueOf(locationLatLng[1])); - } else { - lastMapFocus = new GeoPoint(51.50550, -0.07520); - } - ScaleBarOverlay scaleBarOverlay = new ScaleBarOverlay(binding.map); - scaleBarOverlay.setScaleBarOffset(15, 25); - Paint barPaint = new Paint(); - barPaint.setARGB(200, 255, 250, 250); - scaleBarOverlay.setBackgroundPaint(barPaint); - scaleBarOverlay.enableScaleBar(); - binding.map.getOverlays().add(scaleBarOverlay); - binding.map.getZoomController().setVisibility(Visibility.NEVER); - binding.map.getController().setZoom(ZOOM_LEVEL); - // if we came from Explore map using 'Show in Nearby', load Explore map camera position - if (isCameFromExploreMap()) { - moveCameraToPosition( - new GeoPoint(prevLatitude, prevLongitude), - prevZoom, - 1L - ); - } - binding.map.getOverlays().add(mapEventsOverlay); - - binding.map.addMapListener(new MapListener() { - @Override - public boolean onScroll(ScrollEvent event) { - presenter.handleMapScrolled(scope, !isNetworkErrorOccurred); - return true; - } - - @Override - public boolean onZoom(ZoomEvent event) { - return false; - } - - }); - - binding.map.setMultiTouchControls(true); - if (nearbyParentFragmentInstanceReadyCallback != null) { - nearbyParentFragmentInstanceReadyCallback.onReady(); - } - initNearbyFilter(); - addCheckBoxCallback(); - if (!isCameFromExploreMap()) { - moveCameraToPosition(lastMapFocus); - } - initRvNearbyList(); - onResume(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - binding.tvAttribution.setText( - Html.fromHtml(getString(R.string.map_attribution), Html.FROM_HTML_MODE_LEGACY)); - } else { - //noinspection deprecation - binding.tvAttribution.setText(Html.fromHtml(getString(R.string.map_attribution))); - } - binding.tvAttribution.setMovementMethod(LinkMovementMethod.getInstance()); - binding.nearbyFilterList.btnAdvancedOptions.setOnClickListener(v -> { - binding.nearbyFilter.searchViewLayout.searchView.clearFocus(); - showHideAdvancedQueryFragment(true); - final AdvanceQueryFragment fragment = new AdvanceQueryFragment(); - final Bundle bundle = new Bundle(); - try { - bundle.putString("query", - FileUtils.INSTANCE.readFromResource( - "/queries/radius_query_for_upload_wizard.rq") - ); - } catch (IOException e) { - Timber.e(e); - } - fragment.setArguments(bundle); - fragment.callback = new Callback() { - @Override - public void close() { - showHideAdvancedQueryFragment(false); - } - - @Override - public void reset() { - presenter.setAdvancedQuery(null); - presenter.updateMapAndList(LOCATION_SIGNIFICANTLY_CHANGED); - showHideAdvancedQueryFragment(false); - } - - @Override - public void apply(@NotNull final String query) { - presenter.setAdvancedQuery(query); - presenter.updateMapAndList(CUSTOM_QUERY); - showHideAdvancedQueryFragment(false); - } - }; - getChildFragmentManager().beginTransaction() - .replace(R.id.fl_container_nearby_children, fragment) - .commit(); - }); - - binding.tvLearnMore.setOnClickListener(v -> onLearnMoreClicked()); - - if (!locationPermissionsHelper.checkLocationPermission(getActivity())) { - askForLocationPermission(); - } - } - - /** - * Fetch Explore map camera data from fragment arguments if any. - */ - public void loadExploreMapData() { - // 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 Explore map. if present, then the user - * navigated from Explore using 'Show in Nearby'. - * - * @return true if user navigated from Explore map - **/ - public boolean isCameFromExploreMap() { - return prevZoom != 0.0 || prevLatitude != 0.0 || prevLongitude != 0.0; - } - - /** - * Initialise background based on theme, this should be doe ideally via styles, that would need - * another refactor - */ - private void initThemePreferences() { - if (isDarkTheme) { - binding.bottomSheetNearby.rvNearbyList.setBackgroundColor( - getContext().getResources().getColor(R.color.contributionListDarkBackground)); - binding.nearbyFilterList.checkboxTriStates.setTextColor( - getContext().getResources().getColor(android.R.color.white)); - binding.nearbyFilterList.checkboxTriStates.setTextColor( - getContext().getResources().getColor(android.R.color.white)); - binding.nearbyFilterList.getRoot().setBackgroundColor( - getContext().getResources().getColor(R.color.contributionListDarkBackground)); - binding.map.getOverlayManager().getTilesOverlay() - .setColorFilter(TilesOverlay.INVERT_COLORS); - } else { - binding.bottomSheetNearby.rvNearbyList.setBackgroundColor( - getContext().getResources().getColor(android.R.color.white)); - binding.nearbyFilterList.checkboxTriStates.setTextColor( - getContext().getResources().getColor(R.color.contributionListDarkBackground)); - binding.nearbyFilterList.getRoot().setBackgroundColor( - getContext().getResources().getColor(android.R.color.white)); - binding.nearbyFilterList.getRoot().setBackgroundColor( - getContext().getResources().getColor(android.R.color.white)); - } - } - - private void initRvNearbyList() { - binding.bottomSheetNearby.rvNearbyList.setLayoutManager( - new LinearLayoutManager(getContext())); - adapter = new PlaceAdapter(bookmarkLocationDao, - place -> { - moveCameraToPosition( - new GeoPoint(place.location.getLatitude(), place.location.getLongitude())); - return Unit.INSTANCE; - }, - (place, isBookmarked) -> { - presenter.toggleBookmarkedStatus(place); - return Unit.INSTANCE; - }, - commonPlaceClickActions, - inAppCameraLocationPermissionLauncher, - galleryPickLauncherForResult, - cameraPickLauncherForResult - ); - binding.bottomSheetNearby.rvNearbyList.setAdapter(adapter); - } - - private void addCheckBoxCallback() { - binding.nearbyFilterList.checkboxTriStates.setCallback( - (o, state, b, b1) -> presenter.filterByMarkerType(o, state, b, b1)); - } - - private void performMapReadyActions() { - if (((MainActivity) getActivity()).activeFragment == ActiveFragment.NEARBY) { - if (applicationKvStore.getBoolean("doNotAskForLocationPermission", false) && - !locationPermissionsHelper.checkLocationPermission(getActivity())) { - isPermissionDenied = true; - } - } - presenter.onMapReady(); - } - - @Override - public void askForLocationPermission() { - Timber.d("Asking for location permission"); - locationPermissionLauncher.launch(permission.ACCESS_FINE_LOCATION); - } - - private void locationPermissionGranted() { - isPermissionDenied = false; - applicationKvStore.putBoolean("doNotAskForLocationPermission", false); - lastKnownLocation = locationManager.getLastLocation(); - LatLng target = lastKnownLocation; - if (lastKnownLocation != null) { - GeoPoint targetP = new GeoPoint(target.getLatitude(), target.getLongitude()); - mapCenter = targetP; - binding.map.getController().setCenter(targetP); - recenterMarkerToPosition(targetP); - if (!isCameFromExploreMap()) { - moveCameraToPosition(targetP); - } - } else if (locationManager.isGPSProviderEnabled() - || locationManager.isNetworkProviderEnabled()) { - locationManager.requestLocationUpdatesFromProvider(LocationManager.NETWORK_PROVIDER); - locationManager.requestLocationUpdatesFromProvider(LocationManager.GPS_PROVIDER); - setProgressBarVisibility(true); - } else { - locationPermissionsHelper.showLocationOffDialog(getActivity(), - R.string.ask_to_turn_location_on_text); - } - presenter.onMapReady(); - registerUnregisterLocationListener(false); - } - - @Override - public void onResume() { - super.onResume(); - binding.map.onResume(); - presenter.attachView(this); - registerNetworkReceiver(); - if (isResumed() && ((MainActivity) getActivity()).activeFragment == ActiveFragment.NEARBY) { - if (locationPermissionsHelper.checkLocationPermission(getActivity())) { - locationPermissionGranted(); - } else { - startMapWithoutPermission(); - } - } - } - - /** - * Starts the map without GPS and without permission By default it points to 51.50550,-0.07520 - * coordinates, other than that it points to the last known location which can be get by the key - * "LastLocation" from applicationKvStore - */ - private void startMapWithoutPermission() { - if (applicationKvStore.getString("LastLocation") != null) { - final String[] locationLatLng - = applicationKvStore.getString("LastLocation").split(","); - lastKnownLocation - = new LatLng(Double.parseDouble(locationLatLng[0]), - Double.parseDouble(locationLatLng[1]), 1f); - } else { - lastKnownLocation = MapUtils.getDefaultLatLng(); - } - if (binding.map != null && !isCameFromExploreMap()) { - moveCameraToPosition( - new GeoPoint(lastKnownLocation.getLatitude(), lastKnownLocation.getLongitude())); - } - presenter.onMapReady(); - } - - private void registerNetworkReceiver() { - if (getActivity() != null) { - getActivity().registerReceiver(broadcastReceiver, intentFilter); - } - } - - @Override - public void onPause() { - super.onPause(); - binding.map.onPause(); - getCompositeDisposable().clear(); - presenter.detachView(); - registerUnregisterLocationListener(true); - try { - if (broadcastReceiver != null && getActivity() != null) { - getContext().unregisterReceiver(broadcastReceiver); - } - - if (locationManager != null && presenter != null) { - locationManager.removeLocationListener(presenter); - locationManager.unregisterLocationManager(); - } - } catch (final Exception e) { - Timber.e(e); - //Broadcast receivers should always be unregistered inside catch, you never know if they were already registered or not - } - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - searchHandler.removeCallbacks(searchRunnable); - presenter.removeNearbyPreferences(applicationKvStore); - } - - private void initViews() { - Timber.d("init views called"); - initBottomSheets(); - loadAnimations(); - setBottomSheetCallbacks(); - addActionToTitle(); - if (!Utils.isMonumentsEnabled(new Date())) { - NearbyFilterState.setWlmSelected(false); - } - } - - /** - * a) Creates bottom sheet behaviours from bottom sheets, sets initial states and visibility b) - * Gets the touch event on the map to perform following actions: if fab is open then close fab. - * if bottom sheet details are expanded then collapse bottom sheet details. if bottom sheet - * details are collapsed then hide the bottom sheet details. if listBottomSheet is open then - * hide the list bottom sheet. - */ - @SuppressLint("ClickableViewAccessibility") - private void initBottomSheets() { - bottomSheetListBehavior = BottomSheetBehavior.from(binding.bottomSheetNearby.bottomSheet); - bottomSheetDetailsBehavior = BottomSheetBehavior.from(binding.bottomSheetDetails.getRoot()); - bottomSheetDetailsBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); - binding.bottomSheetDetails.getRoot().setVisibility(View.VISIBLE); - bottomSheetListBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); - } - - /** - * Determines the number of spans (columns) in the RecyclerView based on device orientation and - * adapter item count. - * - * @return The number of spans to be used in the RecyclerView. - */ - private int getSpanCount() { - int orientation = getResources().getConfiguration().orientation; - if (bottomSheetAdapter != null) { - return (orientation == Configuration.ORIENTATION_PORTRAIT) ? 3 - : bottomSheetAdapter.getItemCount(); - } else { - return (orientation == Configuration.ORIENTATION_PORTRAIT) ? 3 : 6; - } - } - - public void initNearbyFilter() { - binding.nearbyFilterList.getRoot().setVisibility(View.GONE); - hideBottomSheet(); - binding.nearbyFilter.searchViewLayout.searchView.setOnQueryTextFocusChangeListener( - (v, hasFocus) -> { - LayoutUtils.setLayoutHeightAlignedToWidth(1.25, - binding.nearbyFilterList.getRoot()); - if (hasFocus) { - binding.nearbyFilterList.getRoot().setVisibility(View.VISIBLE); - presenter.searchViewGainedFocus(); - } else { - binding.nearbyFilterList.getRoot().setVisibility(View.GONE); - } - }); - binding.nearbyFilterList.searchListView.setHasFixedSize(true); - binding.nearbyFilterList.searchListView.addItemDecoration( - new DividerItemDecoration(getContext(), - DividerItemDecoration.VERTICAL)); - final LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity()); - linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL); - binding.nearbyFilterList.searchListView.setLayoutManager(linearLayoutManager); - nearbyFilterSearchRecyclerViewAdapter = new NearbyFilterSearchRecyclerViewAdapter( - getContext(), new ArrayList<>(Label.valuesAsList()), - binding.nearbyFilterList.searchListView); - nearbyFilterSearchRecyclerViewAdapter.setCallback( - new NearbyFilterSearchRecyclerViewAdapter.Callback() { - @Override - public void setCheckboxUnknown() { - presenter.setCheckboxUnknown(); - } - - @Override - public void filterByMarkerType(final ArrayList