Refactor: Migrate WikidataItemDetailsActivity and explore/maps package to Kotlin

The `WikidataItemDetailsActivity` has been migrated from Java to Kotlin. This includes updating the activity's structure, handling intents, setting up tabs and view pager, managing the media detail fragment, and implementing bookmark functionality. Additionally, the logic for displaying and interacting with depicted items' details, media, child classes, and parent classes has been adapted for the Kotlin implementation.
This commit is contained in:
Saifuddin 2025-02-21 19:39:34 +05:30
parent dd7973cbbf
commit a4109eb37c
10 changed files with 1261 additions and 1362 deletions

View file

@ -697,12 +697,12 @@ class ContributionsFragment
}
}
override fun onLocationChangedSignificantly(latLng: LatLng) {
override fun onLocationChangedSignificantly(latLng: LatLng?) {
// Will be called if location changed more than 1000 meter
updateClosestNearbyCardViewInfo()
}
override fun onLocationChangedSlightly(latLng: LatLng) {
override fun onLocationChangedSlightly(latLng: LatLng?) {
/* Update closest nearby notification card onLocationChangedSlightly
*/
try {
@ -712,7 +712,7 @@ class ContributionsFragment
}
}
override fun onLocationChangedMedium(latLng: LatLng) {
override fun onLocationChangedMedium(latLng: LatLng?) {
// Update closest nearby card view if location changed more than 500 meters
updateClosestNearbyCardViewInfo()
}

View file

@ -144,8 +144,8 @@ public class ExploreMapRootFragment extends CommonsDaggerSupportFragment impleme
*/
@Override
public Media getMediaAtPosition(int i) {
if (mapFragment != null && mapFragment.mediaList != null) {
return mapFragment.mediaList.get(i);
if (mapFragment != null && mapFragment.getMediaList() != null) {
return mapFragment.getMediaList().get(i);
} else {
return null;
}
@ -159,8 +159,8 @@ public class ExploreMapRootFragment extends CommonsDaggerSupportFragment impleme
*/
@Override
public int getTotalMediaCount() {
if (mapFragment != null && mapFragment.mediaList != null) {
return mapFragment.mediaList.size();
if (mapFragment != null && mapFragment.getMediaList() != null) {
return mapFragment.getMediaList().size();
} else {
return 0;
}

View file

@ -1,161 +1,159 @@
package fr.free.nrw.commons.explore.depictions;
package fr.free.nrw.commons.explore.depictions
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.FrameLayout;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.tabs.TabLayout;
import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.ViewPagerAdapter;
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsDao;
import fr.free.nrw.commons.category.CategoryImagesCallback;
import fr.free.nrw.commons.databinding.ActivityWikidataItemDetailsBinding;
import fr.free.nrw.commons.explore.depictions.child.ChildDepictionsFragment;
import fr.free.nrw.commons.explore.depictions.media.DepictedImagesFragment;
import fr.free.nrw.commons.explore.depictions.parent.ParentDepictionsFragment;
import fr.free.nrw.commons.media.MediaDetailPagerFragment;
import fr.free.nrw.commons.theme.BaseActivity;
import fr.free.nrw.commons.upload.structure.depictions.DepictModel;
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem;
import fr.free.nrw.commons.wikidata.WikidataConstants;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.View
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import com.google.android.material.snackbar.Snackbar
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.R
import fr.free.nrw.commons.Utils
import fr.free.nrw.commons.ViewPagerAdapter
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsDao
import fr.free.nrw.commons.category.CategoryImagesCallback
import fr.free.nrw.commons.databinding.ActivityWikidataItemDetailsBinding
import fr.free.nrw.commons.explore.depictions.child.ChildDepictionsFragment
import fr.free.nrw.commons.explore.depictions.media.DepictedImagesFragment
import fr.free.nrw.commons.explore.depictions.parent.ParentDepictionsFragment
import fr.free.nrw.commons.media.MediaDetailPagerFragment
import fr.free.nrw.commons.theme.BaseActivity
import fr.free.nrw.commons.upload.structure.depictions.DepictModel
import fr.free.nrw.commons.upload.structure.depictions.DepictedItem
import fr.free.nrw.commons.wikidata.WikidataConstants
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import javax.inject.Inject
/**
* Activity to show depiction media, parent classes and child classes of depicted items in Explore
*/
public class WikidataItemDetailsActivity extends BaseActivity implements MediaDetailPagerFragment.MediaDetailProvider,
CategoryImagesCallback {
private FragmentManager supportFragmentManager;
private DepictedImagesFragment depictionImagesListFragment;
private MediaDetailPagerFragment mediaDetailPagerFragment;
class WikidataItemDetailsActivity : BaseActivity(),
MediaDetailPagerFragment.MediaDetailProvider, CategoryImagesCallback {
private lateinit var supportFragmentManager: FragmentManager
private lateinit var depictionImagesListFragment: DepictedImagesFragment
private var mediaDetailPagerFragment: MediaDetailPagerFragment? = null
/**
* Name of the depicted item
* Ex: Rabbit
*/
@Inject BookmarkItemsDao bookmarkItemsDao;
private CompositeDisposable compositeDisposable;
@Inject
DepictModel depictModel;
private String wikidataItemName;
private ActivityWikidataItemDetailsBinding binding;
lateinit var bookmarkItemsDao: BookmarkItemsDao
ViewPagerAdapter viewPagerAdapter;
private DepictedItem wikidataItem;
@Inject
lateinit var depictModel: DepictModel
private var wikidataItemName: String? = null
private lateinit var binding: ActivityWikidataItemDetailsBinding
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
private lateinit var viewPagerAdapter: ViewPagerAdapter
private var wikidataItem: DepictedItem? = null
binding = ActivityWikidataItemDetailsBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
compositeDisposable = new CompositeDisposable();
supportFragmentManager = getSupportFragmentManager();
viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
binding.viewPager.setAdapter(viewPagerAdapter);
binding.viewPager.setOffscreenPageLimit(2);
binding.tabLayout.setupWithViewPager(binding.viewPager);
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
final DepictedItem depictedItem = getIntent().getParcelableExtra(
WikidataConstants.BOOKMARKS_ITEMS);
wikidataItem = depictedItem;
setSupportActionBar(binding.toolbarBinding.toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
setTabs();
setPageTitle();
binding = ActivityWikidataItemDetailsBinding.inflate(layoutInflater)
setContentView(binding.root)
supportFragmentManager = getSupportFragmentManager()
viewPagerAdapter = ViewPagerAdapter(supportFragmentManager)
binding.viewPager.adapter = viewPagerAdapter
binding.viewPager.offscreenPageLimit = 2
binding.tabLayout.setupWithViewPager(binding.viewPager)
wikidataItem = intent.getParcelableExtra(WikidataConstants.BOOKMARKS_ITEMS)
setSupportActionBar(binding.toolbarBinding.toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
setTabs()
setPageTitle()
}
/**
* Gets the passed wikidataItemName from the intents and displays it as the page title
* Gets the passed wikidataItemName from the intent and displays it as the page title
*/
private void setPageTitle() {
if (getIntent() != null && getIntent().getStringExtra("wikidataItemName") != null) {
setTitle(getIntent().getStringExtra("wikidataItemName"));
private fun setPageTitle() {
intent.getStringExtra("wikidataItemName")?.let {
title = it
}
}
/**
* This method is called on success of API call for featured Images.
* The viewpager will notified that number of items have changed.
* This method is called on success of API call for featured images.
* The ViewPager will be notified that the number of items has changed.
*/
@Override
public void viewPagerNotifyDataSetChanged() {
if (mediaDetailPagerFragment !=null){
mediaDetailPagerFragment.notifyDataSetChanged();
}
override fun viewPagerNotifyDataSetChanged() {
mediaDetailPagerFragment?.notifyDataSetChanged()
}
/**
* This activity contains 3 tabs and a viewpager. This method is used to set the titles of tab,
* Set the fragments according to the tab selected in the viewPager.
* This activity contains 3 tabs and a ViewPager.
* This method is used to set the titles of tabs and the fragments according to the selected tab
*/
private void setTabs() {
List<Fragment> fragmentList = new ArrayList<>();
List<String> titleList = new ArrayList<>();
depictionImagesListFragment = new DepictedImagesFragment();
ChildDepictionsFragment childDepictionsFragment = new ChildDepictionsFragment();
ParentDepictionsFragment parentDepictionsFragment = new ParentDepictionsFragment();
wikidataItemName = getIntent().getStringExtra("wikidataItemName");
String entityId = getIntent().getStringExtra("entityId");
if (getIntent() != null && wikidataItemName != null) {
Bundle arguments = new Bundle();
arguments.putString("wikidataItemName", wikidataItemName);
arguments.putString("entityId", entityId);
depictionImagesListFragment.setArguments(arguments);
parentDepictionsFragment.setArguments(arguments);
childDepictionsFragment.setArguments(arguments);
private fun setTabs() {
val fragmentList = mutableListOf<Fragment>()
val titleList = mutableListOf<String>()
depictionImagesListFragment = DepictedImagesFragment()
val childDepictionsFragment = ChildDepictionsFragment()
val parentDepictionsFragment = ParentDepictionsFragment()
wikidataItemName = intent.getStringExtra("wikidataItemName")
val entityId = intent.getStringExtra("entityId")
if (!wikidataItemName.isNullOrEmpty()) {
val arguments = Bundle().apply {
putString("wikidataItemName", wikidataItemName)
putString("entityId", entityId)
}
depictionImagesListFragment.arguments = arguments
parentDepictionsFragment.arguments = arguments
childDepictionsFragment.arguments = arguments
}
fragmentList.add(depictionImagesListFragment);
titleList.add(getResources().getString(R.string.title_for_media));
fragmentList.add(childDepictionsFragment);
titleList.add(getResources().getString(R.string.title_for_child_classes));
fragmentList.add(parentDepictionsFragment);
titleList.add(getResources().getString(R.string.title_for_parent_classes));
viewPagerAdapter.setTabData(fragmentList, titleList);
binding.viewPager.setOffscreenPageLimit(2);
viewPagerAdapter.notifyDataSetChanged();
fragmentList.apply {
add(depictionImagesListFragment)
add(childDepictionsFragment)
add(parentDepictionsFragment)
}
titleList.apply {
add(getString(R.string.title_for_media))
add(getString(R.string.title_for_child_classes))
add(getString(R.string.title_for_parent_classes))
}
viewPagerAdapter.setTabData(fragmentList, titleList)
binding.viewPager.offscreenPageLimit = 2
viewPagerAdapter.notifyDataSetChanged()
}
/**
* Shows media detail fragment when user clicks on any image in the list
*/
@Override
public void onMediaClicked(int position) {
binding.tabLayout.setVisibility(View.GONE);
binding.viewPager.setVisibility(View.GONE);
binding.mediaContainer.setVisibility(View.VISIBLE);
if (mediaDetailPagerFragment == null || !mediaDetailPagerFragment.isVisible()) {
// set isFeaturedImage true for featured images, to include author field on media detail
mediaDetailPagerFragment = MediaDetailPagerFragment.newInstance(false, true);
FragmentManager supportFragmentManager = getSupportFragmentManager();
supportFragmentManager
.beginTransaction()
.replace(R.id.mediaContainer, mediaDetailPagerFragment)
.addToBackStack(null)
.commit();
supportFragmentManager.executePendingTransactions();
override fun onMediaClicked(position: Int) {
binding.apply {
tabLayout.visibility = View.GONE
viewPager.visibility = View.GONE
mediaContainer.visibility = View.VISIBLE
}
mediaDetailPagerFragment.showImage(position);
if (mediaDetailPagerFragment == null || mediaDetailPagerFragment?.isVisible == false) {
mediaDetailPagerFragment = MediaDetailPagerFragment.newInstance(false, true)
supportFragmentManager = getSupportFragmentManager()
supportFragmentManager.beginTransaction()
.replace(R.id.mediaContainer, mediaDetailPagerFragment!!)
.addToBackStack(null)
.commit()
supportFragmentManager.executePendingTransactions()
}
mediaDetailPagerFragment?.showImage(position)
}
/**
@ -164,23 +162,23 @@ public class WikidataItemDetailsActivity extends BaseActivity implements MediaDe
* current index of viewPager.
* @return Media Object
*/
@Override
public Media getMediaAtPosition(int i) {
return depictionImagesListFragment.getMediaAtPosition(i);
override fun getMediaAtPosition(i: Int): Media? {
return depictionImagesListFragment.getMediaAtPosition(i)
}
/**
* This method is called on backPressed of anyFragment in the activity.
* If condition is called when mediaDetailFragment is opened.
*/
@Override
public void onBackPressed() {
if (supportFragmentManager.getBackStackEntryCount() == 1){
binding.tabLayout.setVisibility(View.VISIBLE);
binding.viewPager.setVisibility(View.VISIBLE);
binding.mediaContainer.setVisibility(View.GONE);
override fun onBackPressed() {
if (supportFragmentManager.backStackEntryCount == 1) {
binding.apply {
tabLayout.visibility = View.VISIBLE
viewPager.visibility = View.VISIBLE
mediaContainer.visibility = View.GONE
}
}
super.onBackPressed();
super.onBackPressed()
}
/**
@ -188,14 +186,12 @@ public class WikidataItemDetailsActivity extends BaseActivity implements MediaDe
* The viewpager will contain same number of media items as that of media elements in adapter.
* @return Total Media count in the adapter
*/
@Override
public int getTotalMediaCount() {
return depictionImagesListFragment.getTotalMediaCount();
override fun getTotalMediaCount(): Int {
return depictionImagesListFragment.getTotalMediaCount()
}
@Override
public Integer getContributionStateAt(int position) {
return null;
override fun getContributionStateAt(position: Int): Int? {
return null
}
/**
@ -203,107 +199,105 @@ public class WikidataItemDetailsActivity extends BaseActivity implements MediaDe
*
* @param index item position that has been nominated
*/
@Override
public void refreshNominatedMedia(int index) {
if (getSupportFragmentManager().getBackStackEntryCount() == 1) {
onBackPressed();
onMediaClicked(index);
override fun refreshNominatedMedia(index: Int) {
if (supportFragmentManager.backStackEntryCount == 1) {
onBackPressed()
onMediaClicked(index)
}
}
companion object {
/**
* Consumers should be simply using this method to use this activity.
*
* @param context a Context of the application package implementing this class.
* @param depictedItem Name of the depicts for displaying its details
*/
fun startYourself(context: Context, depictedItem: DepictedItem) {
val intent = Intent(context, WikidataItemDetailsActivity::class.java).apply {
putExtra("wikidataItemName", depictedItem.name)
putExtra("entityId", depictedItem.id)
putExtra(WikidataConstants.BOOKMARKS_ITEMS, depictedItem)
}
context.startActivity(intent)
}
}
/**
* Consumers should be simply using this method to use this activity.
*
* @param context A Context of the application package implementing this class.
* @param depictedItem Name of the depicts for displaying its details
* Inflates the menu
*/
public static void startYourself(Context context, DepictedItem depictedItem) {
Intent intent = new Intent(context, WikidataItemDetailsActivity.class);
intent.putExtra("wikidataItemName", depictedItem.getName());
intent.putExtra("entityId", depictedItem.getId());
intent.putExtra(WikidataConstants.BOOKMARKS_ITEMS, depictedItem);
context.startActivity(intent);
}
/**
* This function inflates the menu
*/
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater=getMenuInflater();
menuInflater.inflate(R.menu.menu_wikidata_item,menu);
updateBookmarkState(menu.findItem(R.id.menu_bookmark_current_item));
return super.onCreateOptionsMenu(menu);
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_wikidata_item, menu)
updateBookmarkState(menu.findItem(R.id.menu_bookmark_current_item))
return super.onCreateOptionsMenu(menu)
}
/**
* This method handles the logic on item select in toolbar menu
* Currently only 1 choice is available to open Wikidata item details page in browser
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.browser_actions_menu_items:
String entityId=getIntent().getStringExtra("entityId");
Uri uri = Uri.parse("https://www.wikidata.org/wiki/" + entityId);
Utils.handleWebUrl(this, uri);
return true;
case R.id.menu_bookmark_current_item:
if(getIntent().getStringExtra("fragment") != null) {
compositeDisposable.add(depictModel.getDepictions(
getIntent().getStringExtra("entityId")
).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(depictedItems -> {
final boolean bookmarkExists = bookmarkItemsDao.updateBookmarkItem(
depictedItems.get(0));
final Snackbar snackbar
= bookmarkExists ? Snackbar.make(findViewById(R.id.toolbar_layout),
R.string.add_bookmark, Snackbar.LENGTH_LONG)
: Snackbar.make(findViewById(R.id.toolbar_layout),
R.string.remove_bookmark,
Snackbar.LENGTH_LONG);
snackbar.show();
updateBookmarkState(item);
}));
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.browser_actions_menu_items -> {
val entityId = intent.getStringExtra("entityId")
val uri = Uri.parse("https://www.wikidata.org/wiki/$entityId")
Utils.handleWebUrl(this, uri)
return true
}
R.id.menu_bookmark_current_item -> {
val entityId = intent.getStringExtra("entityId")
if (intent.getStringExtra("fragment") != null) {
compositeDisposable.add(
depictModel.getDepictions(entityId!!)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { depictedItems ->
val bookmarkExists = bookmarkItemsDao
.updateBookmarkItem(depictedItems[0])
val snackbarText = if (bookmarkExists)
R.string.add_bookmark
else
R.string.remove_bookmark
Snackbar.make(
findViewById(R.id.toolbar_layout),
snackbarText,
Snackbar.LENGTH_LONG
).show()
updateBookmarkState(item)
}
)
} else {
final boolean bookmarkExists
= bookmarkItemsDao.updateBookmarkItem(wikidataItem);
final Snackbar snackbar
= bookmarkExists ? Snackbar.make(findViewById(R.id.toolbar_layout),
R.string.add_bookmark, Snackbar.LENGTH_LONG)
: Snackbar.make(findViewById(R.id.toolbar_layout), R.string.remove_bookmark,
Snackbar.LENGTH_LONG);
snackbar.show();
updateBookmarkState(item);
val bookmarkExists = bookmarkItemsDao.updateBookmarkItem(wikidataItem!!)
val snackbarText = if (bookmarkExists)
R.string.add_bookmark
else
R.string.remove_bookmark
Snackbar.make(
findViewById(R.id.toolbar_layout),
snackbarText,
Snackbar.LENGTH_LONG
).show()
updateBookmarkState(item)
}
return true;
case android.R.id.home:
onBackPressed();
return true;
default:
return super.onOptionsItemSelected(item);
return true
}
android.R.id.home -> {
onBackPressed()
return true
}
else -> return super.onOptionsItemSelected(item)
}
}
private void updateBookmarkState(final MenuItem item) {
final boolean isBookmarked;
if(getIntent().getStringExtra("fragment") != null) {
isBookmarked
= bookmarkItemsDao.findBookmarkItem(getIntent().getStringExtra("entityId"));
} else {
isBookmarked = bookmarkItemsDao.findBookmarkItem(wikidataItem.getId());
}
final int icon
= isBookmarked ? R.drawable.menu_ic_round_star_filled_24px
: R.drawable.menu_ic_round_star_border_24px;
item.setIcon(icon);
private fun updateBookmarkState(item: MenuItem) {
val isBookmarked = bookmarkItemsDao.findBookmarkItem(
intent.getStringExtra("entityId") ?: wikidataItem?.id
)
val icon = if (isBookmarked)
R.drawable.menu_ic_round_star_filled_24px
else
R.drawable.menu_ic_round_star_border_24px
item.setIcon(icon)
}
}

View file

@ -1,21 +1,16 @@
package fr.free.nrw.commons.explore.map;
package fr.free.nrw.commons.explore.map
import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.location.LatLng;
import fr.free.nrw.commons.media.MediaClient;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.location.LatLng
import fr.free.nrw.commons.media.MediaClient
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
public class ExploreMapCalls {
class ExploreMapCalls @Inject constructor() {
@Inject
MediaClient mediaClient;
@Inject
public ExploreMapCalls() {
}
lateinit var mediaClient: MediaClient
/**
* Calls method to query Commons for uploads around a location
@ -23,9 +18,8 @@ public class ExploreMapCalls {
* @param currentLatLng coordinates of search location
* @return list of places obtained
*/
List<Media> callCommonsQuery(final LatLng currentLatLng) {
String coordinates = currentLatLng.getLatitude() + "|" + currentLatLng.getLongitude();
return mediaClient.getMediaListFromGeoSearch(coordinates).blockingGet();
fun callCommonsQuery(currentLatLng: LatLng): List<Media> {
val coordinates = "${currentLatLng.latitude}|${currentLatLng.longitude}"
return mediaClient.getMediaListFromGeoSearch(coordinates).blockingGet()
}
}

View file

@ -1,45 +1,43 @@
package fr.free.nrw.commons.explore.map;
package fr.free.nrw.commons.explore.map
import android.content.Context;
import fr.free.nrw.commons.BaseMarker;
import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.location.LatLng;
import fr.free.nrw.commons.location.LocationServiceManager;
import java.util.List;
import android.content.Context
import fr.free.nrw.commons.BaseMarker
import fr.free.nrw.commons.kvstore.JsonKvStore
import fr.free.nrw.commons.location.LatLng
import fr.free.nrw.commons.location.LocationServiceManager
public class ExploreMapContract {
interface ExploreMapContract {
interface View {
boolean isNetworkConnectionEstablished();
void populatePlaces(LatLng curlatLng);
void askForLocationPermission();
void recenterMap(LatLng curLatLng);
void hideBottomDetailsSheet();
LatLng getMapCenter();
LatLng getMapFocus();
LatLng getLastMapFocus();
void addMarkersToMap(final List<BaseMarker> nearbyBaseMarkers);
void clearAllMarkers();
void addSearchThisAreaButtonAction();
void setSearchThisAreaButtonVisibility(boolean isVisible);
void setProgressBarVisibility(boolean isVisible);
boolean isDetailsBottomSheetVisible();
boolean isSearchThisAreaButtonVisible();
Context getContext();
LatLng getLastLocation();
void disableFABRecenter();
void enableFABRecenter();
void setFABRecenterAction(android.view.View.OnClickListener onClickListener);
boolean backButtonClicked();
fun isNetworkConnectionEstablished(): Boolean
fun populatePlaces(curLatLng: LatLng?)
fun askForLocationPermission()
fun recenterMap(curLatLng: LatLng?)
fun hideBottomDetailsSheet()
fun getMapCenter(): LatLng
fun getMapFocus(): LatLng
fun getLastMapFocus(): LatLng
fun addMarkersToMap(nearbyBaseMarkers: List<BaseMarker>)
fun clearAllMarkers()
fun addSearchThisAreaButtonAction()
fun setSearchThisAreaButtonVisibility(isVisible: Boolean)
fun setProgressBarVisibility(isVisible: Boolean)
fun isDetailsBottomSheetVisible(): Boolean
fun isSearchThisAreaButtonVisible(): Boolean
fun getContext(): Context
fun getLastLocation(): LatLng
fun disableFABRecenter()
fun enableFABRecenter()
fun setFABRecenterAction(onClickListener: android.view.View.OnClickListener)
fun backButtonClicked(): Boolean
}
interface UserActions {
void updateMap(LocationServiceManager.LocationChangeType locationChangeType);
void lockUnlockNearby(boolean isNearbyLocked);
void attachView(View view);
void detachView();
void setActionListeners(JsonKvStore applicationKvStore);
boolean backButtonClicked();
fun updateMap(locationChangeType: LocationServiceManager.LocationChangeType)
fun lockUnlockNearby(isNearbyLocked: Boolean)
fun attachView(view: View)
fun detachView()
fun setActionListeners(applicationKvStore: JsonKvStore)
fun backButtonClicked(): Boolean
}
}

View file

@ -1,126 +1,120 @@
package fr.free.nrw.commons.explore.map;
package fr.free.nrw.commons.explore.map
import static fr.free.nrw.commons.utils.LengthUtils.computeDistanceBetween;
import static fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween;
import android.content.Context
import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.transition.Transition
import fr.free.nrw.commons.BaseMarker
import fr.free.nrw.commons.MapController
import fr.free.nrw.commons.Media
import fr.free.nrw.commons.R
import fr.free.nrw.commons.location.LatLng
import fr.free.nrw.commons.nearby.Place
import fr.free.nrw.commons.utils.ImageUtils
import fr.free.nrw.commons.utils.LengthUtils.computeDistanceBetween
import fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween
import fr.free.nrw.commons.utils.LocationUtils
import fr.free.nrw.commons.utils.PlaceUtils
import timber.log.Timber
import javax.inject.Inject
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
import fr.free.nrw.commons.BaseMarker;
import fr.free.nrw.commons.MapController;
import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.location.LatLng;
import fr.free.nrw.commons.nearby.Place;
import fr.free.nrw.commons.utils.ImageUtils;
import fr.free.nrw.commons.utils.LocationUtils;
import fr.free.nrw.commons.utils.PlaceUtils;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import timber.log.Timber;
class ExploreMapController @Inject constructor(
private val exploreMapCalls: ExploreMapCalls
) : MapController() {
public class ExploreMapController extends MapController {
private final ExploreMapCalls exploreMapCalls;
public LatLng latestSearchLocation; // Can be current and camera target on search this area button is used
public LatLng currentLocation; // current location of user
public double latestSearchRadius = 0; // Any last search radius
public double currentLocationSearchRadius = 0; // Search radius of only searches around current location
@Inject
public ExploreMapController(ExploreMapCalls explorePlaces) {
this.exploreMapCalls = explorePlaces;
}
var latestSearchLocation: LatLng? = null // Can be current and camera target when search this
// area button is used
var currentLocation: LatLng? = null // Current location of user
var latestSearchRadius: Double = 0.0 // Any last search radius
var currentLocationSearchRadius: Double = 0.0 // Search radius of only searches around current
// location
/**
* Takes location as parameter and returns ExplorePlaces info that holds currentLatLng, mediaList,
* explorePlaceList and boundaryCoordinates
* Takes location as parameter and returns ExplorePlaces info that holds currentLatLng,
* mediaList, explorePlaceList and boundaryCoordinates
*
* @param currentLatLng is current geolocation
* @param searchLatLng is the location that we want to search around
* @param currentLatLng is current geolocation
* @param searchLatLng is the location that we want to search around
* @param checkingAroundCurrentLocation is a boolean flag. True if we want to check around
* current location, false if another location
* @return explorePlacesInfo info that holds currentLatLng, mediaList, explorePlaceList and
* boundaryCoordinates
*/
public ExplorePlacesInfo loadAttractionsFromLocation(LatLng currentLatLng, LatLng searchLatLng,
boolean checkingAroundCurrentLocation) {
fun loadAttractionsFromLocation(
currentLatLng: LatLng,
searchLatLng: LatLng?,
checkingAroundCurrentLocation: Boolean
): ExplorePlacesInfo? {
if (searchLatLng == null) {
Timber.d("Loading attractions explore map, but search is null");
return null;
Timber.d("Loading attractions explore map, but search is null")
return null
}
ExplorePlacesInfo explorePlacesInfo = new ExplorePlacesInfo();
val explorePlacesInfo = ExplorePlacesInfo()
try {
explorePlacesInfo.currentLatLng = currentLatLng;
latestSearchLocation = searchLatLng;
explorePlacesInfo.currentLatLng = currentLatLng
latestSearchLocation = searchLatLng
List<Media> mediaList = exploreMapCalls.callCommonsQuery(searchLatLng);
LatLng[] boundaryCoordinates = {mediaList.get(0).getCoordinates(), // south
mediaList.get(0).getCoordinates(), // north
mediaList.get(0).getCoordinates(), // west
mediaList.get(0).getCoordinates()};// east, init with a random location
val mediaList = exploreMapCalls.callCommonsQuery(searchLatLng)
val boundaryCoordinates = arrayOf(
mediaList[0].coordinates, // south
mediaList[0].coordinates, // north
mediaList[0].coordinates, // west
mediaList[0].coordinates // east, init with a random location
)
if (searchLatLng != null) {
Timber.d("Sorting places by distance...");
final Map<Media, Double> distances = new HashMap<>();
for (Media media : mediaList) {
distances.put(media,
computeDistanceBetween(media.getCoordinates(), searchLatLng));
// Find boundaries with basic find max approach
if (media.getCoordinates().getLatitude()
< boundaryCoordinates[0].getLatitude()) {
boundaryCoordinates[0] = media.getCoordinates();
}
if (media.getCoordinates().getLatitude()
> boundaryCoordinates[1].getLatitude()) {
boundaryCoordinates[1] = media.getCoordinates();
}
if (media.getCoordinates().getLongitude()
< boundaryCoordinates[2].getLongitude()) {
boundaryCoordinates[2] = media.getCoordinates();
}
if (media.getCoordinates().getLongitude()
> boundaryCoordinates[3].getLongitude()) {
boundaryCoordinates[3] = media.getCoordinates();
}
Timber.d("Sorting places by distance...")
val distances = mutableMapOf<Media, Double>()
for (media in mediaList) {
distances[media] = computeDistanceBetween(media.coordinates!!, searchLatLng)
// Find boundaries with basic find max approach
if (media.coordinates!!.latitude < boundaryCoordinates[0]?.latitude!!) {
boundaryCoordinates[0] = media.coordinates
}
if (media.coordinates!!.latitude > boundaryCoordinates[1]?.latitude!!) {
boundaryCoordinates[1] = media.coordinates
}
if (media.coordinates!!.longitude < boundaryCoordinates[2]?.longitude!!) {
boundaryCoordinates[2] = media.coordinates
}
if (media.coordinates!!.longitude > boundaryCoordinates[3]?.longitude!!) {
boundaryCoordinates[3] = media.coordinates
}
}
explorePlacesInfo.mediaList = mediaList;
explorePlacesInfo.explorePlaceList = PlaceUtils.mediaToExplorePlace(mediaList);
explorePlacesInfo.boundaryCoordinates = boundaryCoordinates;
explorePlacesInfo.mediaList = mediaList
explorePlacesInfo.explorePlaceList = PlaceUtils.mediaToExplorePlace(mediaList)
explorePlacesInfo.boundaryCoordinates = boundaryCoordinates
// Sets latestSearchRadius to maximum distance among boundaries and search location
for (LatLng bound : boundaryCoordinates) {
double distance = LocationUtils.calculateDistance(bound.getLatitude(),
bound.getLongitude(), searchLatLng.getLatitude(), searchLatLng.getLongitude());
for (bound in boundaryCoordinates) {
val distance = LocationUtils.calculateDistance(
bound?.latitude!!, bound.longitude,
searchLatLng.latitude, searchLatLng.longitude
)
if (distance > latestSearchRadius) {
latestSearchRadius = distance;
latestSearchRadius = distance
}
}
// Our radius searched around us, will be used to understand when user search their own location, we will follow them
// Our radius searched around us, will be used to understand when user search
// their own location, we will follow them
if (checkingAroundCurrentLocation) {
currentLocationSearchRadius = latestSearchRadius;
currentLocation = currentLatLng;
currentLocationSearchRadius = latestSearchRadius
currentLocation = currentLatLng
}
} catch (Exception e) {
e.printStackTrace();
} catch (e: Exception) {
e.printStackTrace()
}
return explorePlacesInfo;
return explorePlacesInfo
}
/**
@ -128,86 +122,96 @@ public class ExploreMapController extends MapController {
*
* @return baseMarkerOptions list that holds nearby places with their icons
*/
public static List<BaseMarker> loadAttractionsFromLocationToBaseMarkerOptions(
LatLng currentLatLng,
final List<Place> placeList,
Context context,
NearbyBaseMarkerThumbCallback callback,
ExplorePlacesInfo explorePlacesInfo) {
List<BaseMarker> baseMarkerList = new ArrayList<>();
companion object {
fun loadAttractionsFromLocationToBaseMarkerOptions(
currentLatLng: LatLng,
placeList: List<Place>?,
context: Context,
callback: NearbyBaseMarkerThumbCallback,
explorePlacesInfo: ExplorePlacesInfo
): List<BaseMarker> {
val baseMarkerList = mutableListOf<BaseMarker>()
if (placeList == null) {
return baseMarkerList;
}
VectorDrawableCompat vectorDrawable = null;
try {
vectorDrawable = VectorDrawableCompat.create(
context.getResources(), R.drawable.ic_custom_map_marker_dark, context.getTheme());
} catch (Resources.NotFoundException e) {
// ignore when running tests.
}
if (vectorDrawable != null) {
for (Place explorePlace : placeList) {
final BaseMarker baseMarker = new BaseMarker();
String distance = formatDistanceBetween(currentLatLng, explorePlace.location);
explorePlace.setDistance(distance);
baseMarker.setTitle(
explorePlace.name.substring(5, explorePlace.name.lastIndexOf(".")));
baseMarker.setPosition(
new fr.free.nrw.commons.location.LatLng(
explorePlace.location.getLatitude(),
explorePlace.location.getLongitude(), 0));
baseMarker.setPlace(explorePlace);
Glide.with(context)
.asBitmap()
.load(explorePlace.getThumb())
.placeholder(R.drawable.image_placeholder_96)
.apply(new RequestOptions().override(96, 96).centerCrop())
.into(new CustomTarget<Bitmap>() {
// We add icons to markers when bitmaps are ready
@Override
public void onResourceReady(@NonNull Bitmap resource,
@Nullable Transition<? super Bitmap> transition) {
baseMarker.setIcon(
ImageUtils.addRedBorder(resource, 6, context));
baseMarkerList.add(baseMarker);
if (baseMarkerList.size()
== placeList.size()) { // if true, we added all markers to list and can trigger thumbs ready callback
callback.onNearbyBaseMarkerThumbsReady(baseMarkerList,
explorePlacesInfo);
}
}
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
}
// We add thumbnail icon for images that couldn't be loaded
@Override
public void onLoadFailed(@Nullable final Drawable errorDrawable) {
super.onLoadFailed(errorDrawable);
baseMarker.fromResource(context, R.drawable.image_placeholder_96);
baseMarkerList.add(baseMarker);
if (baseMarkerList.size()
== placeList.size()) { // if true, we added all markers to list and can trigger thumbs ready callback
callback.onNearbyBaseMarkerThumbsReady(baseMarkerList,
explorePlacesInfo);
}
}
});
if (placeList == null) {
return baseMarkerList
}
var vectorDrawable: VectorDrawableCompat? = null
try {
vectorDrawable = VectorDrawableCompat.create(
context.resources, R.drawable.ic_custom_map_marker_dark, context.theme
)
} catch (e: Resources.NotFoundException) {
// Ignore when running tests
}
vectorDrawable?.let {
for (explorePlace in placeList) {
val baseMarker = BaseMarker()
val distance = formatDistanceBetween(currentLatLng, explorePlace.location)
explorePlace.distance = distance
baseMarker.title = explorePlace.name.substring(
5,
explorePlace.name.lastIndexOf(".")
)
baseMarker.position = LatLng(
explorePlace.location.latitude,
explorePlace.location.longitude, 0.0f
)
baseMarker.place = explorePlace
Glide.with(context)
.asBitmap()
.load(explorePlace.thumb)
.placeholder(R.drawable.image_placeholder_96)
.apply(RequestOptions().override(96, 96).centerCrop())
.into(object : CustomTarget<Bitmap>() {
// We add icons to markers when bitmaps are ready
override fun onResourceReady(
resource: Bitmap,
transition: Transition<in Bitmap>?
) {
baseMarker.icon = ImageUtils.addRedBorder(resource, 6, context)
baseMarkerList.add(baseMarker)
if (baseMarkerList.size == placeList.size) {
// If true, we added all markers to list and can trigger thumbs
// ready callback
callback.onNearbyBaseMarkerThumbsReady(
baseMarkerList,
explorePlacesInfo
)
}
}
override fun onLoadCleared(placeholder: Drawable?) {}
// We add thumbnail icon for images that couldn't be loaded
override fun onLoadFailed(errorDrawable: Drawable?) {
super.onLoadFailed(errorDrawable)
baseMarker.fromResource(context, R.drawable.image_placeholder_96)
baseMarkerList.add(baseMarker)
if (baseMarkerList.size == placeList.size) {
// If true, we added all markers to list and can trigger thumbs
// ready callback
callback.onNearbyBaseMarkerThumbsReady(
baseMarkerList,
explorePlacesInfo
)
}
}
})
}
}
return baseMarkerList
}
return baseMarkerList;
}
interface NearbyBaseMarkerThumbCallback {
// Callback to notify thumbnails of explore markers are added as icons and ready
void onNearbyBaseMarkerThumbsReady(List<BaseMarker> baseMarkers,
ExplorePlacesInfo explorePlacesInfo);
fun onNearbyBaseMarkerThumbsReady(
baseMarkers: List<BaseMarker>,
explorePlacesInfo: ExplorePlacesInfo
)
}
}

View file

@ -1,152 +1,139 @@
package fr.free.nrw.commons.explore.map;
package fr.free.nrw.commons.explore.map
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED;
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.SEARCH_CUSTOM_AREA;
import android.location.Location
import android.view.View
import fr.free.nrw.commons.BaseMarker
import fr.free.nrw.commons.MapController
import fr.free.nrw.commons.MapController.ExplorePlacesInfo
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao
import fr.free.nrw.commons.explore.map.ExploreMapController.NearbyBaseMarkerThumbCallback
import fr.free.nrw.commons.kvstore.JsonKvStore
import fr.free.nrw.commons.location.LatLng
import fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType
import io.reactivex.Observable
import java.lang.reflect.Proxy
import timber.log.Timber
class ExploreMapPresenter(
private val bookmarkLocationDao: BookmarkLocationsDao
) : ExploreMapContract.UserActions, ExploreMapController.NearbyBaseMarkerThumbCallback {
import android.location.Location;
import android.view.View;
import fr.free.nrw.commons.BaseMarker;
import fr.free.nrw.commons.MapController;
import fr.free.nrw.commons.MapController.ExplorePlacesInfo;
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao;
import fr.free.nrw.commons.explore.map.ExploreMapController.NearbyBaseMarkerThumbCallback;
import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.location.LatLng;
import fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType;
import io.reactivex.Observable;
import java.lang.reflect.Proxy;
import java.util.List;
import timber.log.Timber;
private var isNearbyLocked: Boolean = false
private var currentLatLng: LatLng? = null
private var exploreMapController: ExploreMapController? = null
public class ExploreMapPresenter
implements ExploreMapContract.UserActions,
NearbyBaseMarkerThumbCallback {
BookmarkLocationsDao bookmarkLocationDao;
private boolean isNearbyLocked;
private LatLng currentLatLng;
private ExploreMapController exploreMapController;
private static final ExploreMapContract.View DUMMY = (ExploreMapContract.View) Proxy
.newProxyInstance(
ExploreMapContract.View.class.getClassLoader(),
new Class[]{ExploreMapContract.View.class}, (proxy, method, args) -> {
if (method.getName().equals("onMyEvent")) {
return null;
} else if (String.class == method.getReturnType()) {
return "";
} else if (Integer.class == method.getReturnType()) {
return Integer.valueOf(0);
} else if (int.class == method.getReturnType()) {
return 0;
} else if (Boolean.class == method.getReturnType()) {
return Boolean.FALSE;
} else if (boolean.class == method.getReturnType()) {
return false;
} else {
return null;
}
companion object {
private val DUMMY: ExploreMapContract.View = Proxy.newProxyInstance(
ExploreMapContract.View::class.java.classLoader,
arrayOf(ExploreMapContract.View::class.java)
) { _, method, _ ->
when (method.returnType) {
String::class.java -> ""
Integer::class.java -> 0
Int::class.java -> 0
Boolean::class.java -> false
Boolean::class.javaPrimitiveType -> false
else -> null
}
);
private ExploreMapContract.View exploreMapFragmentView = DUMMY;
public ExploreMapPresenter(BookmarkLocationsDao bookmarkLocationDao) {
this.bookmarkLocationDao = bookmarkLocationDao;
} as ExploreMapContract.View
}
@Override
public void updateMap(LocationChangeType locationChangeType) {
Timber.d("Presenter updates map and list" + locationChangeType.toString());
private var exploreMapFragmentView: ExploreMapContract.View = DUMMY
override fun updateMap(locationChangeType: LocationChangeType) {
Timber.d("Presenter updates map and list $locationChangeType")
if (isNearbyLocked) {
Timber.d("Nearby is locked, so updateMapAndList returns");
return;
Timber.d("Nearby is locked, so updateMapAndList returns")
return
}
if (!exploreMapFragmentView.isNetworkConnectionEstablished()) {
Timber.d("Network connection is not established");
return;
Timber.d("Network connection is not established")
return
}
/**
* Significant changed - Markers and current location will be updated together
* Slightly changed - Only current position marker will be updated
*/
if (locationChangeType.equals(LOCATION_SIGNIFICANTLY_CHANGED)) {
Timber.d("LOCATION_SIGNIFICANTLY_CHANGED");
lockUnlockNearby(true);
exploreMapFragmentView.setProgressBarVisibility(true);
exploreMapFragmentView.populatePlaces(exploreMapFragmentView.getMapCenter());
} else if (locationChangeType.equals(SEARCH_CUSTOM_AREA)) {
Timber.d("SEARCH_CUSTOM_AREA");
lockUnlockNearby(true);
exploreMapFragmentView.setProgressBarVisibility(true);
exploreMapFragmentView.populatePlaces(exploreMapFragmentView.getMapFocus());
} else { // Means location changed slightly, ie user is walking or driving.
Timber.d("Means location changed slightly");
when (locationChangeType) {
LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED -> {
Timber.d("LOCATION_SIGNIFICANTLY_CHANGED")
lockUnlockNearby(true)
exploreMapFragmentView.setProgressBarVisibility(true)
exploreMapFragmentView.populatePlaces(exploreMapFragmentView.getMapCenter())
}
LocationChangeType.SEARCH_CUSTOM_AREA -> {
Timber.d("SEARCH_CUSTOM_AREA")
lockUnlockNearby(true)
exploreMapFragmentView.setProgressBarVisibility(true)
exploreMapFragmentView.populatePlaces(exploreMapFragmentView.getMapFocus())
}
else -> {
Timber.d("Means location changed slightly")
}
}
}
/**
* Nearby updates takes time, since they are network operations. During update time, we don't
* want to get any other calls from user. So locking nearby.
* Nearby updates take time since they are network operations. During update time, we don't
* want to get any other calls from the user. So locking nearby.
*
* @param isNearbyLocked true means lock, false means unlock
*/
@Override
public void lockUnlockNearby(boolean isNearbyLocked) {
this.isNearbyLocked = isNearbyLocked;
override fun lockUnlockNearby(isNearbyLocked: Boolean) {
this.isNearbyLocked = isNearbyLocked
if (isNearbyLocked) {
exploreMapFragmentView.disableFABRecenter();
exploreMapFragmentView.disableFABRecenter()
} else {
exploreMapFragmentView.enableFABRecenter();
exploreMapFragmentView.enableFABRecenter()
}
}
@Override
public void attachView(ExploreMapContract.View view) {
exploreMapFragmentView = view;
override fun attachView(view: ExploreMapContract.View) {
exploreMapFragmentView = view
}
@Override
public void detachView() {
exploreMapFragmentView = DUMMY;
override fun detachView() {
exploreMapFragmentView = DUMMY
}
/**
* Sets click listener of FAB
*/
@Override
public void setActionListeners(JsonKvStore applicationKvStore) {
exploreMapFragmentView.setFABRecenterAction(v -> {
exploreMapFragmentView.recenterMap(currentLatLng);
});
}
@Override
public boolean backButtonClicked() {
return exploreMapFragmentView.backButtonClicked();
}
public void onMapReady(ExploreMapController exploreMapController) {
this.exploreMapController = exploreMapController;
if (null != exploreMapFragmentView) {
exploreMapFragmentView.addSearchThisAreaButtonAction();
initializeMapOperations();
override fun setActionListeners(applicationKvStore: JsonKvStore) {
exploreMapFragmentView.setFABRecenterAction {
currentLatLng?.let { it1 -> exploreMapFragmentView.recenterMap(it1) }
}
}
public void initializeMapOperations() {
lockUnlockNearby(false);
updateMap(LOCATION_SIGNIFICANTLY_CHANGED);
override fun backButtonClicked(): Boolean {
return exploreMapFragmentView.backButtonClicked()
}
public Observable<ExplorePlacesInfo> loadAttractionsFromLocation(LatLng currentLatLng,
LatLng searchLatLng, boolean checkingAroundCurrent) {
return Observable
.fromCallable(() -> exploreMapController
.loadAttractionsFromLocation(currentLatLng, searchLatLng, checkingAroundCurrent));
fun onMapReady(exploreMapController: ExploreMapController) {
this.exploreMapController = exploreMapController
exploreMapFragmentView.addSearchThisAreaButtonAction()
initializeMapOperations()
}
fun initializeMapOperations() {
lockUnlockNearby(false)
updateMap(LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED)
}
fun loadAttractionsFromLocation(
currentLatLng: LatLng,
searchLatLng: LatLng?,
checkingAroundCurrent: Boolean
): Observable<ExplorePlacesInfo> {
return Observable.fromCallable {
exploreMapController?.loadAttractionsFromLocation(
currentLatLng, searchLatLng, checkingAroundCurrent
)
}
}
/**
@ -155,47 +142,45 @@ public class ExploreMapPresenter
*
* @param explorePlacesInfo This variable has placeToCenter list information and distances.
*/
public void updateMapMarkers(
MapController.ExplorePlacesInfo explorePlacesInfo) {
fun updateMapMarkers(explorePlacesInfo: MapController.ExplorePlacesInfo) {
if (explorePlacesInfo.mediaList != null) {
prepareNearbyBaseMarkers(explorePlacesInfo);
prepareNearbyBaseMarkers(explorePlacesInfo)
} else {
lockUnlockNearby(false); // So that new location updates wont come
exploreMapFragmentView.setProgressBarVisibility(false);
lockUnlockNearby(false) // So that new location updates won't come
exploreMapFragmentView.setProgressBarVisibility(false)
}
}
void prepareNearbyBaseMarkers(MapController.ExplorePlacesInfo explorePlacesInfo) {
exploreMapController
.loadAttractionsFromLocationToBaseMarkerOptions(explorePlacesInfo.currentLatLng,
// Curlatlang will be used to calculate distances
explorePlacesInfo.explorePlaceList,
exploreMapFragmentView.getContext(),
this,
explorePlacesInfo);
private fun prepareNearbyBaseMarkers(explorePlacesInfo: MapController.ExplorePlacesInfo) {
ExploreMapController.loadAttractionsFromLocationToBaseMarkerOptions(
explorePlacesInfo.currentLatLng,
explorePlacesInfo.explorePlaceList,
exploreMapFragmentView.getContext(),
this,
explorePlacesInfo
)
}
@Override
public void onNearbyBaseMarkerThumbsReady(List<BaseMarker> baseMarkers,
ExplorePlacesInfo explorePlacesInfo) {
if (null != exploreMapFragmentView) {
exploreMapFragmentView.addMarkersToMap(baseMarkers);
lockUnlockNearby(false); // So that new location updates wont come
exploreMapFragmentView.setProgressBarVisibility(false);
}
override fun onNearbyBaseMarkerThumbsReady(
baseMarkers: List<BaseMarker>,
explorePlacesInfo: ExplorePlacesInfo
) {
exploreMapFragmentView.addMarkersToMap(baseMarkers)
lockUnlockNearby(false) // So that new location updates won't come
exploreMapFragmentView.setProgressBarVisibility(false)
}
public View.OnClickListener onSearchThisAreaClicked() {
return v -> {
fun onSearchThisAreaClicked(): View.OnClickListener {
return View.OnClickListener {
// Lock map operations during search this area operation
exploreMapFragmentView.setSearchThisAreaButtonVisibility(false);
exploreMapFragmentView.setSearchThisAreaButtonVisibility(false)
if (searchCloseToCurrentLocation()) {
updateMap(LOCATION_SIGNIFICANTLY_CHANGED);
updateMap(LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED)
} else {
updateMap(SEARCH_CUSTOM_AREA);
updateMap(LocationChangeType.SEARCH_CUSTOM_AREA)
}
};
}
}
/**
@ -204,24 +189,19 @@ public class ExploreMapPresenter
*
* @return Returns true if search this area button is used around our current location
*/
public boolean searchCloseToCurrentLocation() {
if (null == exploreMapFragmentView.getLastMapFocus()) {
return true;
fun searchCloseToCurrentLocation(): Boolean {
val lastMapFocus = exploreMapFragmentView.getLastMapFocus() ?: return true
val myLocation = Location("").apply {
latitude = lastMapFocus.latitude
longitude = lastMapFocus.longitude
}
Location mylocation = new Location("");
Location dest_location = new Location("");
dest_location.setLatitude(exploreMapFragmentView.getMapFocus().getLatitude());
dest_location.setLongitude(exploreMapFragmentView.getMapFocus().getLongitude());
mylocation.setLatitude(exploreMapFragmentView.getLastMapFocus().getLatitude());
mylocation.setLongitude(exploreMapFragmentView.getLastMapFocus().getLongitude());
Float distance = mylocation.distanceTo(dest_location);
if (distance > 2000.0 * 3 / 4) {
return false;
} else {
return true;
val destLocation = Location("").apply {
latitude = exploreMapFragmentView.getMapFocus().latitude
longitude = exploreMapFragmentView.getMapFocus().longitude
}
return myLocation.distanceTo(destLocation) <= 2000.0 * 3 / 4
}
}

View file

@ -2,11 +2,11 @@ package fr.free.nrw.commons.location
interface LocationUpdateListener {
// Will be used to update all nearby markers on the map
fun onLocationChangedSignificantly(latLng: LatLng)
fun onLocationChangedSignificantly(latLng: LatLng?)
// Will be used to track users motion
fun onLocationChangedSlightly(latLng: LatLng)
fun onLocationChangedSlightly(latLng: LatLng?)
// Will be used updating nearby card view notification
fun onLocationChangedMedium(latLng: LatLng)
fun onLocationChangedMedium(latLng: LatLng?)
}

View file

@ -465,17 +465,17 @@ class NearbyParentFragmentPresenter
updateMapAndList(LocationChangeType.MAP_UPDATED)
}
override fun onLocationChangedSignificantly(latLng: LatLng) {
override fun onLocationChangedSignificantly(latLng: LatLng?) {
Timber.d("Location significantly changed")
updateMapAndList(LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED)
}
override fun onLocationChangedSlightly(latLng: LatLng) {
override fun onLocationChangedSlightly(latLng: LatLng?) {
Timber.d("Location significantly changed")
updateMapAndList(LocationChangeType.LOCATION_SLIGHTLY_CHANGED)
}
override fun onLocationChangedMedium(latLng: LatLng) {
override fun onLocationChangedMedium(latLng: LatLng?) {
Timber.d("Location changed medium")
}