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 6de21aa3de
commit 21404f6fbd
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 // Will be called if location changed more than 1000 meter
updateClosestNearbyCardViewInfo() updateClosestNearbyCardViewInfo()
} }
override fun onLocationChangedSlightly(latLng: LatLng) { override fun onLocationChangedSlightly(latLng: LatLng?) {
/* Update closest nearby notification card onLocationChangedSlightly /* Update closest nearby notification card onLocationChangedSlightly
*/ */
try { 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 // Update closest nearby card view if location changed more than 500 meters
updateClosestNearbyCardViewInfo() updateClosestNearbyCardViewInfo()
} }

View file

@ -144,8 +144,8 @@ public class ExploreMapRootFragment extends CommonsDaggerSupportFragment impleme
*/ */
@Override @Override
public Media getMediaAtPosition(int i) { public Media getMediaAtPosition(int i) {
if (mapFragment != null && mapFragment.mediaList != null) { if (mapFragment != null && mapFragment.getMediaList() != null) {
return mapFragment.mediaList.get(i); return mapFragment.getMediaList().get(i);
} else { } else {
return null; return null;
} }
@ -159,8 +159,8 @@ public class ExploreMapRootFragment extends CommonsDaggerSupportFragment impleme
*/ */
@Override @Override
public int getTotalMediaCount() { public int getTotalMediaCount() {
if (mapFragment != null && mapFragment.mediaList != null) { if (mapFragment != null && mapFragment.getMediaList() != null) {
return mapFragment.mediaList.size(); return mapFragment.getMediaList().size();
} else { } else {
return 0; 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.Context
import android.content.Intent; import android.content.Intent
import android.net.Uri; import android.net.Uri
import android.os.Bundle; import android.os.Bundle
import android.view.Menu; import android.view.Menu
import android.view.MenuInflater; import android.view.MenuItem
import android.view.MenuItem; import android.view.View
import android.view.View; import androidx.fragment.app.Fragment
import android.widget.FrameLayout; import androidx.fragment.app.FragmentManager
import androidx.appcompat.widget.Toolbar; import com.google.android.material.snackbar.Snackbar
import androidx.fragment.app.Fragment; import fr.free.nrw.commons.Media
import androidx.fragment.app.FragmentManager; import fr.free.nrw.commons.R
import androidx.viewpager.widget.ViewPager; import fr.free.nrw.commons.Utils
import com.google.android.material.snackbar.Snackbar; import fr.free.nrw.commons.ViewPagerAdapter
import com.google.android.material.tabs.TabLayout; import fr.free.nrw.commons.bookmarks.items.BookmarkItemsDao
import fr.free.nrw.commons.Media; import fr.free.nrw.commons.category.CategoryImagesCallback
import fr.free.nrw.commons.R; import fr.free.nrw.commons.databinding.ActivityWikidataItemDetailsBinding
import fr.free.nrw.commons.Utils; import fr.free.nrw.commons.explore.depictions.child.ChildDepictionsFragment
import fr.free.nrw.commons.ViewPagerAdapter; import fr.free.nrw.commons.explore.depictions.media.DepictedImagesFragment
import fr.free.nrw.commons.bookmarks.items.BookmarkItemsDao; import fr.free.nrw.commons.explore.depictions.parent.ParentDepictionsFragment
import fr.free.nrw.commons.category.CategoryImagesCallback; import fr.free.nrw.commons.media.MediaDetailPagerFragment
import fr.free.nrw.commons.databinding.ActivityWikidataItemDetailsBinding; import fr.free.nrw.commons.theme.BaseActivity
import fr.free.nrw.commons.explore.depictions.child.ChildDepictionsFragment; import fr.free.nrw.commons.upload.structure.depictions.DepictModel
import fr.free.nrw.commons.explore.depictions.media.DepictedImagesFragment; import fr.free.nrw.commons.upload.structure.depictions.DepictedItem
import fr.free.nrw.commons.explore.depictions.parent.ParentDepictionsFragment; import fr.free.nrw.commons.wikidata.WikidataConstants
import fr.free.nrw.commons.media.MediaDetailPagerFragment; import io.reactivex.android.schedulers.AndroidSchedulers
import fr.free.nrw.commons.theme.BaseActivity; import io.reactivex.schedulers.Schedulers
import fr.free.nrw.commons.upload.structure.depictions.DepictModel; import javax.inject.Inject
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;
/** /**
* Activity to show depiction media, parent classes and child classes of depicted items in Explore * Activity to show depiction media, parent classes and child classes of depicted items in Explore
*/ */
public class WikidataItemDetailsActivity extends BaseActivity implements MediaDetailPagerFragment.MediaDetailProvider, class WikidataItemDetailsActivity : BaseActivity(),
CategoryImagesCallback { MediaDetailPagerFragment.MediaDetailProvider, CategoryImagesCallback {
private FragmentManager supportFragmentManager;
private DepictedImagesFragment depictionImagesListFragment; private lateinit var supportFragmentManager: FragmentManager
private MediaDetailPagerFragment mediaDetailPagerFragment; private lateinit var depictionImagesListFragment: DepictedImagesFragment
private var mediaDetailPagerFragment: MediaDetailPagerFragment? = null
/** /**
* Name of the depicted item * Name of the depicted item
* Ex: Rabbit * Ex: Rabbit
*/ */
@Inject BookmarkItemsDao bookmarkItemsDao;
private CompositeDisposable compositeDisposable;
@Inject @Inject
DepictModel depictModel; lateinit var bookmarkItemsDao: BookmarkItemsDao
private String wikidataItemName;
private ActivityWikidataItemDetailsBinding binding;
ViewPagerAdapter viewPagerAdapter; @Inject
private DepictedItem wikidataItem; lateinit var depictModel: DepictModel
private var wikidataItemName: String? = null
private lateinit var binding: ActivityWikidataItemDetailsBinding
@Override private lateinit var viewPagerAdapter: ViewPagerAdapter
protected void onCreate(Bundle savedInstanceState) { private var wikidataItem: DepictedItem? = null
super.onCreate(savedInstanceState);
binding = ActivityWikidataItemDetailsBinding.inflate(getLayoutInflater()); override fun onCreate(savedInstanceState: Bundle?) {
setContentView(binding.getRoot()); super.onCreate(savedInstanceState)
compositeDisposable = new CompositeDisposable();
supportFragmentManager = getSupportFragmentManager();
viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());
binding.viewPager.setAdapter(viewPagerAdapter);
binding.viewPager.setOffscreenPageLimit(2);
binding.tabLayout.setupWithViewPager(binding.viewPager);
final DepictedItem depictedItem = getIntent().getParcelableExtra( binding = ActivityWikidataItemDetailsBinding.inflate(layoutInflater)
WikidataConstants.BOOKMARKS_ITEMS); setContentView(binding.root)
wikidataItem = depictedItem;
setSupportActionBar(binding.toolbarBinding.toolbar); supportFragmentManager = getSupportFragmentManager()
getSupportActionBar().setDisplayHomeAsUpEnabled(true); viewPagerAdapter = ViewPagerAdapter(supportFragmentManager)
setTabs(); binding.viewPager.adapter = viewPagerAdapter
setPageTitle(); 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() { private fun setPageTitle() {
if (getIntent() != null && getIntent().getStringExtra("wikidataItemName") != null) { intent.getStringExtra("wikidataItemName")?.let {
setTitle(getIntent().getStringExtra("wikidataItemName")); title = it
} }
} }
/** /**
* This method is called on success of API call for featured Images. * This method is called on success of API call for featured images.
* The viewpager will notified that number of items have changed. * The ViewPager will be notified that the number of items has changed.
*/ */
@Override override fun viewPagerNotifyDataSetChanged() {
public void viewPagerNotifyDataSetChanged() { mediaDetailPagerFragment?.notifyDataSetChanged()
if (mediaDetailPagerFragment !=null){
mediaDetailPagerFragment.notifyDataSetChanged();
}
} }
/** /**
* This activity contains 3 tabs and a viewpager. This method is used to set the titles of tab, * This activity contains 3 tabs and a ViewPager.
* Set the fragments according to the tab selected in the viewPager. * This method is used to set the titles of tabs and the fragments according to the selected tab
*/ */
private void setTabs() { private fun setTabs() {
List<Fragment> fragmentList = new ArrayList<>(); val fragmentList = mutableListOf<Fragment>()
List<String> titleList = new ArrayList<>(); val titleList = mutableListOf<String>()
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);
}
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();
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.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 * Shows media detail fragment when user clicks on any image in the list
*/ */
@Override override fun onMediaClicked(position: Int) {
public void onMediaClicked(int position) { binding.apply {
binding.tabLayout.setVisibility(View.GONE); tabLayout.visibility = View.GONE
binding.viewPager.setVisibility(View.GONE); viewPager.visibility = View.GONE
binding.mediaContainer.setVisibility(View.VISIBLE); mediaContainer.visibility = 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();
} }
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. * current index of viewPager.
* @return Media Object * @return Media Object
*/ */
@Override override fun getMediaAtPosition(i: Int): Media? {
public Media getMediaAtPosition(int i) { return depictionImagesListFragment.getMediaAtPosition(i)
return depictionImagesListFragment.getMediaAtPosition(i);
} }
/** /**
* This method is called on backPressed of anyFragment in the activity. * This method is called on backPressed of anyFragment in the activity.
* If condition is called when mediaDetailFragment is opened. * If condition is called when mediaDetailFragment is opened.
*/ */
@Override override fun onBackPressed() {
public void onBackPressed() { if (supportFragmentManager.backStackEntryCount == 1) {
if (supportFragmentManager.getBackStackEntryCount() == 1){ binding.apply {
binding.tabLayout.setVisibility(View.VISIBLE); tabLayout.visibility = View.VISIBLE
binding.viewPager.setVisibility(View.VISIBLE); viewPager.visibility = View.VISIBLE
binding.mediaContainer.setVisibility(View.GONE); 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. * The viewpager will contain same number of media items as that of media elements in adapter.
* @return Total Media count in the adapter * @return Total Media count in the adapter
*/ */
@Override override fun getTotalMediaCount(): Int {
public int getTotalMediaCount() { return depictionImagesListFragment.getTotalMediaCount()
return depictionImagesListFragment.getTotalMediaCount();
} }
@Override override fun getContributionStateAt(position: Int): Int? {
public Integer getContributionStateAt(int position) { return null
return null;
} }
/** /**
@ -203,107 +199,105 @@ public class WikidataItemDetailsActivity extends BaseActivity implements MediaDe
* *
* @param index item position that has been nominated * @param index item position that has been nominated
*/ */
@Override override fun refreshNominatedMedia(index: Int) {
public void refreshNominatedMedia(int index) { if (supportFragmentManager.backStackEntryCount == 1) {
if (getSupportFragmentManager().getBackStackEntryCount() == 1) { onBackPressed()
onBackPressed(); onMediaClicked(index)
onMediaClicked(index);
} }
} }
companion object {
/** /**
* Consumers should be simply using this method to use this activity. * Consumers should be simply using this method to use this activity.
* *
* @param context A Context of the application package implementing this class. * @param context a Context of the application package implementing this class.
* @param depictedItem Name of the depicts for displaying its details * @param depictedItem Name of the depicts for displaying its details
*/ */
public static void startYourself(Context context, DepictedItem depictedItem) { fun startYourself(context: Context, depictedItem: DepictedItem) {
Intent intent = new Intent(context, WikidataItemDetailsActivity.class); val intent = Intent(context, WikidataItemDetailsActivity::class.java).apply {
intent.putExtra("wikidataItemName", depictedItem.getName()); putExtra("wikidataItemName", depictedItem.name)
intent.putExtra("entityId", depictedItem.getId()); putExtra("entityId", depictedItem.id)
intent.putExtra(WikidataConstants.BOOKMARKS_ITEMS, depictedItem); putExtra(WikidataConstants.BOOKMARKS_ITEMS, depictedItem)
context.startActivity(intent); }
context.startActivity(intent)
}
} }
/** /**
* This function inflates the menu * Inflates the menu
*/ */
@Override override fun onCreateOptionsMenu(menu: Menu): Boolean {
public boolean onCreateOptionsMenu(Menu menu) { menuInflater.inflate(R.menu.menu_wikidata_item, menu)
MenuInflater menuInflater=getMenuInflater(); updateBookmarkState(menu.findItem(R.id.menu_bookmark_current_item))
menuInflater.inflate(R.menu.menu_wikidata_item,menu); return super.onCreateOptionsMenu(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 * 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 * Currently only 1 choice is available to open Wikidata item details page in browser
*/ */
@Override override fun onOptionsItemSelected(item: MenuItem): Boolean {
public boolean onOptionsItemSelected(MenuItem item) { 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")
switch (item.getItemId()){ if (intent.getStringExtra("fragment") != null) {
case R.id.browser_actions_menu_items: compositeDisposable.add(
String entityId=getIntent().getStringExtra("entityId"); depictModel.getDepictions(entityId!!)
Uri uri = Uri.parse("https://www.wikidata.org/wiki/" + entityId); .subscribeOn(Schedulers.io())
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()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(depictedItems -> { .subscribe { depictedItems ->
final boolean bookmarkExists = bookmarkItemsDao.updateBookmarkItem( val bookmarkExists = bookmarkItemsDao
depictedItems.get(0)); .updateBookmarkItem(depictedItems[0])
final Snackbar snackbar val snackbarText = if (bookmarkExists)
= bookmarkExists ? Snackbar.make(findViewById(R.id.toolbar_layout), R.string.add_bookmark
R.string.add_bookmark, Snackbar.LENGTH_LONG) else
: Snackbar.make(findViewById(R.id.toolbar_layout), R.string.remove_bookmark
R.string.remove_bookmark, Snackbar.make(
Snackbar.LENGTH_LONG); findViewById(R.id.toolbar_layout),
snackbarText,
snackbar.show(); Snackbar.LENGTH_LONG
updateBookmarkState(item); ).show()
})); updateBookmarkState(item)
}
)
} else { } else {
final boolean bookmarkExists val bookmarkExists = bookmarkItemsDao.updateBookmarkItem(wikidataItem!!)
= bookmarkItemsDao.updateBookmarkItem(wikidataItem); val snackbarText = if (bookmarkExists)
final Snackbar snackbar R.string.add_bookmark
= bookmarkExists ? Snackbar.make(findViewById(R.id.toolbar_layout), else
R.string.add_bookmark, Snackbar.LENGTH_LONG) R.string.remove_bookmark
: Snackbar.make(findViewById(R.id.toolbar_layout), R.string.remove_bookmark, Snackbar.make(
Snackbar.LENGTH_LONG); findViewById(R.id.toolbar_layout),
snackbarText,
snackbar.show(); Snackbar.LENGTH_LONG
updateBookmarkState(item); ).show()
updateBookmarkState(item)
} }
return true; return true
case android.R.id.home: }
onBackPressed(); android.R.id.home -> {
return true; onBackPressed()
default: return true
return super.onOptionsItemSelected(item); }
else -> return super.onOptionsItemSelected(item)
} }
} }
private void updateBookmarkState(final MenuItem item) { private fun updateBookmarkState(item: MenuItem) {
final boolean isBookmarked; val isBookmarked = bookmarkItemsDao.findBookmarkItem(
if(getIntent().getStringExtra("fragment") != null) { intent.getStringExtra("entityId") ?: wikidataItem?.id
isBookmarked )
= bookmarkItemsDao.findBookmarkItem(getIntent().getStringExtra("entityId")); val icon = if (isBookmarked)
} else { R.drawable.menu_ic_round_star_filled_24px
isBookmarked = bookmarkItemsDao.findBookmarkItem(wikidataItem.getId()); else
} R.drawable.menu_ic_round_star_border_24px
final int icon item.setIcon(icon)
= isBookmarked ? R.drawable.menu_ic_round_star_filled_24px
: 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.Media
import fr.free.nrw.commons.location.LatLng; import fr.free.nrw.commons.location.LatLng
import fr.free.nrw.commons.media.MediaClient; import fr.free.nrw.commons.media.MediaClient
import java.util.List; import javax.inject.Inject
import javax.inject.Inject; import javax.inject.Singleton
import javax.inject.Singleton;
@Singleton @Singleton
public class ExploreMapCalls { class ExploreMapCalls @Inject constructor() {
@Inject @Inject
MediaClient mediaClient; lateinit var mediaClient: MediaClient
@Inject
public ExploreMapCalls() {
}
/** /**
* Calls method to query Commons for uploads around a location * Calls method to query Commons for uploads around a location
@ -23,9 +18,8 @@ public class ExploreMapCalls {
* @param currentLatLng coordinates of search location * @param currentLatLng coordinates of search location
* @return list of places obtained * @return list of places obtained
*/ */
List<Media> callCommonsQuery(final LatLng currentLatLng) { fun callCommonsQuery(currentLatLng: LatLng): List<Media> {
String coordinates = currentLatLng.getLatitude() + "|" + currentLatLng.getLongitude(); val coordinates = "${currentLatLng.latitude}|${currentLatLng.longitude}"
return mediaClient.getMediaListFromGeoSearch(coordinates).blockingGet(); 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 android.content.Context
import fr.free.nrw.commons.BaseMarker; import fr.free.nrw.commons.BaseMarker
import fr.free.nrw.commons.kvstore.JsonKvStore; import fr.free.nrw.commons.kvstore.JsonKvStore
import fr.free.nrw.commons.location.LatLng; import fr.free.nrw.commons.location.LatLng
import fr.free.nrw.commons.location.LocationServiceManager; import fr.free.nrw.commons.location.LocationServiceManager
import java.util.List;
public class ExploreMapContract { interface ExploreMapContract {
interface View { interface View {
boolean isNetworkConnectionEstablished(); fun isNetworkConnectionEstablished(): Boolean
void populatePlaces(LatLng curlatLng); fun populatePlaces(curLatLng: LatLng?)
void askForLocationPermission(); fun askForLocationPermission()
void recenterMap(LatLng curLatLng); fun recenterMap(curLatLng: LatLng?)
void hideBottomDetailsSheet(); fun hideBottomDetailsSheet()
LatLng getMapCenter(); fun getMapCenter(): LatLng
LatLng getMapFocus(); fun getMapFocus(): LatLng
LatLng getLastMapFocus(); fun getLastMapFocus(): LatLng
void addMarkersToMap(final List<BaseMarker> nearbyBaseMarkers); fun addMarkersToMap(nearbyBaseMarkers: List<BaseMarker>)
void clearAllMarkers(); fun clearAllMarkers()
void addSearchThisAreaButtonAction(); fun addSearchThisAreaButtonAction()
void setSearchThisAreaButtonVisibility(boolean isVisible); fun setSearchThisAreaButtonVisibility(isVisible: Boolean)
void setProgressBarVisibility(boolean isVisible); fun setProgressBarVisibility(isVisible: Boolean)
boolean isDetailsBottomSheetVisible(); fun isDetailsBottomSheetVisible(): Boolean
boolean isSearchThisAreaButtonVisible(); fun isSearchThisAreaButtonVisible(): Boolean
Context getContext(); fun getContext(): Context
LatLng getLastLocation(); fun getLastLocation(): LatLng
void disableFABRecenter(); fun disableFABRecenter()
void enableFABRecenter(); fun enableFABRecenter()
void setFABRecenterAction(android.view.View.OnClickListener onClickListener); fun setFABRecenterAction(onClickListener: android.view.View.OnClickListener)
boolean backButtonClicked(); fun backButtonClicked(): Boolean
} }
interface UserActions { interface UserActions {
void updateMap(LocationServiceManager.LocationChangeType locationChangeType); fun updateMap(locationChangeType: LocationServiceManager.LocationChangeType)
void lockUnlockNearby(boolean isNearbyLocked); fun lockUnlockNearby(isNearbyLocked: Boolean)
void attachView(View view); fun attachView(view: View)
void detachView(); fun detachView()
void setActionListeners(JsonKvStore applicationKvStore); fun setActionListeners(applicationKvStore: JsonKvStore)
boolean backButtonClicked(); fun backButtonClicked(): Boolean
} }
} }

View file

@ -1,52 +1,42 @@
package fr.free.nrw.commons.explore.map; package fr.free.nrw.commons.explore.map
import static fr.free.nrw.commons.utils.LengthUtils.computeDistanceBetween; import android.content.Context
import static fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween; 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; class ExploreMapController @Inject constructor(
import android.content.res.Resources; private val exploreMapCalls: ExploreMapCalls
import android.graphics.Bitmap; ) : MapController() {
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;
public class ExploreMapController extends MapController { var latestSearchLocation: LatLng? = null // Can be current and camera target when search this
// area button is used
private final ExploreMapCalls exploreMapCalls; var currentLocation: LatLng? = null // Current location of user
public LatLng latestSearchLocation; // Can be current and camera target on search this area button is used var latestSearchRadius: Double = 0.0 // Any last search radius
public LatLng currentLocation; // current location of user var currentLocationSearchRadius: Double = 0.0 // Search radius of only searches around current
public double latestSearchRadius = 0; // Any last search radius // location
public double currentLocationSearchRadius = 0; // Search radius of only searches around current location
@Inject
public ExploreMapController(ExploreMapCalls explorePlaces) {
this.exploreMapCalls = explorePlaces;
}
/** /**
* Takes location as parameter and returns ExplorePlaces info that holds currentLatLng, mediaList, * Takes location as parameter and returns ExplorePlaces info that holds currentLatLng,
* explorePlaceList and boundaryCoordinates * mediaList, explorePlaceList and boundaryCoordinates
* *
* @param currentLatLng is current geolocation * @param currentLatLng is current geolocation
* @param searchLatLng is the location that we want to search around * @param searchLatLng is the location that we want to search around
@ -55,72 +45,76 @@ public class ExploreMapController extends MapController {
* @return explorePlacesInfo info that holds currentLatLng, mediaList, explorePlaceList and * @return explorePlacesInfo info that holds currentLatLng, mediaList, explorePlaceList and
* boundaryCoordinates * boundaryCoordinates
*/ */
public ExplorePlacesInfo loadAttractionsFromLocation(LatLng currentLatLng, LatLng searchLatLng, fun loadAttractionsFromLocation(
boolean checkingAroundCurrentLocation) { currentLatLng: LatLng,
searchLatLng: LatLng?,
checkingAroundCurrentLocation: Boolean
): ExplorePlacesInfo? {
if (searchLatLng == null) { if (searchLatLng == null) {
Timber.d("Loading attractions explore map, but search is null"); Timber.d("Loading attractions explore map, but search is null")
return null; return null
} }
ExplorePlacesInfo explorePlacesInfo = new ExplorePlacesInfo(); val explorePlacesInfo = ExplorePlacesInfo()
try { try {
explorePlacesInfo.currentLatLng = currentLatLng; explorePlacesInfo.currentLatLng = currentLatLng
latestSearchLocation = searchLatLng; latestSearchLocation = searchLatLng
List<Media> mediaList = exploreMapCalls.callCommonsQuery(searchLatLng); val mediaList = exploreMapCalls.callCommonsQuery(searchLatLng)
LatLng[] boundaryCoordinates = {mediaList.get(0).getCoordinates(), // south val boundaryCoordinates = arrayOf(
mediaList.get(0).getCoordinates(), // north mediaList[0].coordinates, // south
mediaList.get(0).getCoordinates(), // west mediaList[0].coordinates, // north
mediaList.get(0).getCoordinates()};// east, init with a random location mediaList[0].coordinates, // west
mediaList[0].coordinates // east, init with a random location
)
Timber.d("Sorting places by distance...")
val distances = mutableMapOf<Media, Double>()
for (media in mediaList) {
distances[media] = computeDistanceBetween(media.coordinates!!, searchLatLng)
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 // Find boundaries with basic find max approach
if (media.getCoordinates().getLatitude() if (media.coordinates!!.latitude < boundaryCoordinates[0]?.latitude!!) {
< boundaryCoordinates[0].getLatitude()) { boundaryCoordinates[0] = media.coordinates
boundaryCoordinates[0] = media.getCoordinates();
} }
if (media.getCoordinates().getLatitude() if (media.coordinates!!.latitude > boundaryCoordinates[1]?.latitude!!) {
> boundaryCoordinates[1].getLatitude()) { boundaryCoordinates[1] = media.coordinates
boundaryCoordinates[1] = media.getCoordinates();
} }
if (media.getCoordinates().getLongitude() if (media.coordinates!!.longitude < boundaryCoordinates[2]?.longitude!!) {
< boundaryCoordinates[2].getLongitude()) { boundaryCoordinates[2] = media.coordinates
boundaryCoordinates[2] = media.getCoordinates();
} }
if (media.getCoordinates().getLongitude() if (media.coordinates!!.longitude > boundaryCoordinates[3]?.longitude!!) {
> boundaryCoordinates[3].getLongitude()) { boundaryCoordinates[3] = media.coordinates
boundaryCoordinates[3] = media.getCoordinates();
} }
} }
}
explorePlacesInfo.mediaList = mediaList; explorePlacesInfo.mediaList = mediaList
explorePlacesInfo.explorePlaceList = PlaceUtils.mediaToExplorePlace(mediaList); explorePlacesInfo.explorePlaceList = PlaceUtils.mediaToExplorePlace(mediaList)
explorePlacesInfo.boundaryCoordinates = boundaryCoordinates; explorePlacesInfo.boundaryCoordinates = boundaryCoordinates
// Sets latestSearchRadius to maximum distance among boundaries and search location // Sets latestSearchRadius to maximum distance among boundaries and search location
for (LatLng bound : boundaryCoordinates) { for (bound in boundaryCoordinates) {
double distance = LocationUtils.calculateDistance(bound.getLatitude(), val distance = LocationUtils.calculateDistance(
bound.getLongitude(), searchLatLng.getLatitude(), searchLatLng.getLongitude()); bound?.latitude!!, bound.longitude,
searchLatLng.latitude, searchLatLng.longitude
)
if (distance > latestSearchRadius) { 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) { if (checkingAroundCurrentLocation) {
currentLocationSearchRadius = latestSearchRadius; currentLocationSearchRadius = latestSearchRadius
currentLocation = currentLatLng; currentLocation = currentLatLng
} }
} catch (Exception e) { } catch (e: Exception) {
e.printStackTrace(); 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 * @return baseMarkerOptions list that holds nearby places with their icons
*/ */
public static List<BaseMarker> loadAttractionsFromLocationToBaseMarkerOptions( companion object {
LatLng currentLatLng, fun loadAttractionsFromLocationToBaseMarkerOptions(
final List<Place> placeList, currentLatLng: LatLng,
Context context, placeList: List<Place>?,
NearbyBaseMarkerThumbCallback callback, context: Context,
ExplorePlacesInfo explorePlacesInfo) { callback: NearbyBaseMarkerThumbCallback,
List<BaseMarker> baseMarkerList = new ArrayList<>(); explorePlacesInfo: ExplorePlacesInfo
): List<BaseMarker> {
val baseMarkerList = mutableListOf<BaseMarker>()
if (placeList == null) { if (placeList == null) {
return baseMarkerList; return baseMarkerList
} }
VectorDrawableCompat vectorDrawable = null; var vectorDrawable: VectorDrawableCompat? = null
try { try {
vectorDrawable = VectorDrawableCompat.create( vectorDrawable = VectorDrawableCompat.create(
context.getResources(), R.drawable.ic_custom_map_marker_dark, context.getTheme()); context.resources, R.drawable.ic_custom_map_marker_dark, context.theme
)
} catch (Resources.NotFoundException e) { } catch (e: Resources.NotFoundException) {
// ignore when running tests. // 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( vectorDrawable?.let {
explorePlace.name.substring(5, explorePlace.name.lastIndexOf("."))); for (explorePlace in placeList) {
baseMarker.setPosition( val baseMarker = BaseMarker()
new fr.free.nrw.commons.location.LatLng( val distance = formatDistanceBetween(currentLatLng, explorePlace.location)
explorePlace.location.getLatitude(), explorePlace.distance = distance
explorePlace.location.getLongitude(), 0));
baseMarker.setPlace(explorePlace); 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) Glide.with(context)
.asBitmap() .asBitmap()
.load(explorePlace.getThumb()) .load(explorePlace.thumb)
.placeholder(R.drawable.image_placeholder_96) .placeholder(R.drawable.image_placeholder_96)
.apply(new RequestOptions().override(96, 96).centerCrop()) .apply(RequestOptions().override(96, 96).centerCrop())
.into(new CustomTarget<Bitmap>() { .into(object : CustomTarget<Bitmap>() {
// We add icons to markers when bitmaps are ready // We add icons to markers when bitmaps are ready
@Override override fun onResourceReady(
public void onResourceReady(@NonNull Bitmap resource, resource: Bitmap,
@Nullable Transition<? super Bitmap> transition) { transition: Transition<in Bitmap>?
baseMarker.setIcon( ) {
ImageUtils.addRedBorder(resource, 6, context)); baseMarker.icon = ImageUtils.addRedBorder(resource, 6, context)
baseMarkerList.add(baseMarker); baseMarkerList.add(baseMarker)
if (baseMarkerList.size() if (baseMarkerList.size == placeList.size) {
== placeList.size()) { // if true, we added all markers to list and can trigger thumbs ready callback // If true, we added all markers to list and can trigger thumbs
callback.onNearbyBaseMarkerThumbsReady(baseMarkerList, // ready callback
explorePlacesInfo); callback.onNearbyBaseMarkerThumbsReady(
baseMarkerList,
explorePlacesInfo
)
} }
} }
@Override override fun onLoadCleared(placeholder: Drawable?) {}
public void onLoadCleared(@Nullable Drawable placeholder) {
}
// We add thumbnail icon for images that couldn't be loaded // We add thumbnail icon for images that couldn't be loaded
@Override override fun onLoadFailed(errorDrawable: Drawable?) {
public void onLoadFailed(@Nullable final Drawable errorDrawable) { super.onLoadFailed(errorDrawable)
super.onLoadFailed(errorDrawable); baseMarker.fromResource(context, R.drawable.image_placeholder_96)
baseMarker.fromResource(context, R.drawable.image_placeholder_96); baseMarkerList.add(baseMarker)
baseMarkerList.add(baseMarker); if (baseMarkerList.size == placeList.size) {
if (baseMarkerList.size() // If true, we added all markers to list and can trigger thumbs
== placeList.size()) { // if true, we added all markers to list and can trigger thumbs ready callback // ready callback
callback.onNearbyBaseMarkerThumbsReady(baseMarkerList, callback.onNearbyBaseMarkerThumbsReady(
explorePlacesInfo); baseMarkerList,
explorePlacesInfo
)
} }
} }
}); })
} }
} }
return baseMarkerList; return baseMarkerList
}
} }
interface NearbyBaseMarkerThumbCallback { interface NearbyBaseMarkerThumbCallback {
// Callback to notify thumbnails of explore markers are added as icons and ready // Callback to notify thumbnails of explore markers are added as icons and ready
void onNearbyBaseMarkerThumbsReady(List<BaseMarker> baseMarkers, fun onNearbyBaseMarkerThumbsReady(
ExplorePlacesInfo explorePlacesInfo); 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 android.location.Location
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.SEARCH_CUSTOM_AREA; 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; private var isNearbyLocked: Boolean = false
import android.view.View; private var currentLatLng: LatLng? = null
import fr.free.nrw.commons.BaseMarker; private var exploreMapController: ExploreMapController? = null
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;
public class ExploreMapPresenter companion object {
implements ExploreMapContract.UserActions, private val DUMMY: ExploreMapContract.View = Proxy.newProxyInstance(
NearbyBaseMarkerThumbCallback { ExploreMapContract.View::class.java.classLoader,
arrayOf(ExploreMapContract.View::class.java)
BookmarkLocationsDao bookmarkLocationDao; ) { _, method, _ ->
private boolean isNearbyLocked; when (method.returnType) {
private LatLng currentLatLng; String::class.java -> ""
private ExploreMapController exploreMapController; Integer::class.java -> 0
Int::class.java -> 0
private static final ExploreMapContract.View DUMMY = (ExploreMapContract.View) Proxy Boolean::class.java -> false
.newProxyInstance( Boolean::class.javaPrimitiveType -> false
ExploreMapContract.View.class.getClassLoader(), else -> null
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;
} }
} } as ExploreMapContract.View
);
private ExploreMapContract.View exploreMapFragmentView = DUMMY;
public ExploreMapPresenter(BookmarkLocationsDao bookmarkLocationDao) {
this.bookmarkLocationDao = bookmarkLocationDao;
} }
@Override private var exploreMapFragmentView: ExploreMapContract.View = DUMMY
public void updateMap(LocationChangeType locationChangeType) {
Timber.d("Presenter updates map and list" + locationChangeType.toString()); override fun updateMap(locationChangeType: LocationChangeType) {
Timber.d("Presenter updates map and list $locationChangeType")
if (isNearbyLocked) { if (isNearbyLocked) {
Timber.d("Nearby is locked, so updateMapAndList returns"); Timber.d("Nearby is locked, so updateMapAndList returns")
return; return
} }
if (!exploreMapFragmentView.isNetworkConnectionEstablished()) { if (!exploreMapFragmentView.isNetworkConnectionEstablished()) {
Timber.d("Network connection is not established"); Timber.d("Network connection is not established")
return; return
} }
/** /**
* Significant changed - Markers and current location will be updated together * Significant changed - Markers and current location will be updated together
* Slightly changed - Only current position marker will be updated * Slightly changed - Only current position marker will be updated
*/ */
if (locationChangeType.equals(LOCATION_SIGNIFICANTLY_CHANGED)) { when (locationChangeType) {
Timber.d("LOCATION_SIGNIFICANTLY_CHANGED"); LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED -> {
lockUnlockNearby(true); Timber.d("LOCATION_SIGNIFICANTLY_CHANGED")
exploreMapFragmentView.setProgressBarVisibility(true); lockUnlockNearby(true)
exploreMapFragmentView.populatePlaces(exploreMapFragmentView.getMapCenter()); exploreMapFragmentView.setProgressBarVisibility(true)
} else if (locationChangeType.equals(SEARCH_CUSTOM_AREA)) { exploreMapFragmentView.populatePlaces(exploreMapFragmentView.getMapCenter())
Timber.d("SEARCH_CUSTOM_AREA"); }
lockUnlockNearby(true);
exploreMapFragmentView.setProgressBarVisibility(true); LocationChangeType.SEARCH_CUSTOM_AREA -> {
exploreMapFragmentView.populatePlaces(exploreMapFragmentView.getMapFocus()); Timber.d("SEARCH_CUSTOM_AREA")
} else { // Means location changed slightly, ie user is walking or driving. lockUnlockNearby(true)
Timber.d("Means location changed slightly"); 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 * Nearby updates take time since they are network operations. During update time, we don't
* want to get any other calls from user. So locking nearby. * want to get any other calls from the user. So locking nearby.
* *
* @param isNearbyLocked true means lock, false means unlock * @param isNearbyLocked true means lock, false means unlock
*/ */
@Override override fun lockUnlockNearby(isNearbyLocked: Boolean) {
public void lockUnlockNearby(boolean isNearbyLocked) { this.isNearbyLocked = isNearbyLocked
this.isNearbyLocked = isNearbyLocked;
if (isNearbyLocked) { if (isNearbyLocked) {
exploreMapFragmentView.disableFABRecenter(); exploreMapFragmentView.disableFABRecenter()
} else { } else {
exploreMapFragmentView.enableFABRecenter(); exploreMapFragmentView.enableFABRecenter()
} }
} }
@Override override fun attachView(view: ExploreMapContract.View) {
public void attachView(ExploreMapContract.View view) { exploreMapFragmentView = view
exploreMapFragmentView = view;
} }
@Override override fun detachView() {
public void detachView() { exploreMapFragmentView = DUMMY
exploreMapFragmentView = DUMMY;
} }
/** /**
* Sets click listener of FAB * Sets click listener of FAB
*/ */
@Override override fun setActionListeners(applicationKvStore: JsonKvStore) {
public void setActionListeners(JsonKvStore applicationKvStore) { exploreMapFragmentView.setFABRecenterAction {
exploreMapFragmentView.setFABRecenterAction(v -> { currentLatLng?.let { it1 -> exploreMapFragmentView.recenterMap(it1) }
exploreMapFragmentView.recenterMap(currentLatLng);
});
}
@Override
public boolean backButtonClicked() {
return exploreMapFragmentView.backButtonClicked();
}
public void onMapReady(ExploreMapController exploreMapController) {
this.exploreMapController = exploreMapController;
if (null != exploreMapFragmentView) {
exploreMapFragmentView.addSearchThisAreaButtonAction();
initializeMapOperations();
} }
} }
public void initializeMapOperations() { override fun backButtonClicked(): Boolean {
lockUnlockNearby(false); return exploreMapFragmentView.backButtonClicked()
updateMap(LOCATION_SIGNIFICANTLY_CHANGED);
} }
public Observable<ExplorePlacesInfo> loadAttractionsFromLocation(LatLng currentLatLng, fun onMapReady(exploreMapController: ExploreMapController) {
LatLng searchLatLng, boolean checkingAroundCurrent) { this.exploreMapController = exploreMapController
return Observable exploreMapFragmentView.addSearchThisAreaButtonAction()
.fromCallable(() -> exploreMapController initializeMapOperations()
.loadAttractionsFromLocation(currentLatLng, searchLatLng, checkingAroundCurrent)); }
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. * @param explorePlacesInfo This variable has placeToCenter list information and distances.
*/ */
public void updateMapMarkers( fun updateMapMarkers(explorePlacesInfo: MapController.ExplorePlacesInfo) {
MapController.ExplorePlacesInfo explorePlacesInfo) {
if (explorePlacesInfo.mediaList != null) { if (explorePlacesInfo.mediaList != null) {
prepareNearbyBaseMarkers(explorePlacesInfo); prepareNearbyBaseMarkers(explorePlacesInfo)
} else { } else {
lockUnlockNearby(false); // So that new location updates wont come lockUnlockNearby(false) // So that new location updates won't come
exploreMapFragmentView.setProgressBarVisibility(false); exploreMapFragmentView.setProgressBarVisibility(false)
} }
} }
void prepareNearbyBaseMarkers(MapController.ExplorePlacesInfo explorePlacesInfo) { private fun prepareNearbyBaseMarkers(explorePlacesInfo: MapController.ExplorePlacesInfo) {
exploreMapController ExploreMapController.loadAttractionsFromLocationToBaseMarkerOptions(
.loadAttractionsFromLocationToBaseMarkerOptions(explorePlacesInfo.currentLatLng, explorePlacesInfo.currentLatLng,
// Curlatlang will be used to calculate distances
explorePlacesInfo.explorePlaceList, explorePlacesInfo.explorePlaceList,
exploreMapFragmentView.getContext(), exploreMapFragmentView.getContext(),
this, this,
explorePlacesInfo); explorePlacesInfo
)
} }
@Override override fun onNearbyBaseMarkerThumbsReady(
public void onNearbyBaseMarkerThumbsReady(List<BaseMarker> baseMarkers, baseMarkers: List<BaseMarker>,
ExplorePlacesInfo explorePlacesInfo) { explorePlacesInfo: ExplorePlacesInfo
if (null != exploreMapFragmentView) { ) {
exploreMapFragmentView.addMarkersToMap(baseMarkers); exploreMapFragmentView.addMarkersToMap(baseMarkers)
lockUnlockNearby(false); // So that new location updates wont come lockUnlockNearby(false) // So that new location updates won't come
exploreMapFragmentView.setProgressBarVisibility(false); exploreMapFragmentView.setProgressBarVisibility(false)
}
} }
public View.OnClickListener onSearchThisAreaClicked() { fun onSearchThisAreaClicked(): View.OnClickListener {
return v -> { return View.OnClickListener {
// Lock map operations during search this area operation // Lock map operations during search this area operation
exploreMapFragmentView.setSearchThisAreaButtonVisibility(false); exploreMapFragmentView.setSearchThisAreaButtonVisibility(false)
if (searchCloseToCurrentLocation()) { if (searchCloseToCurrentLocation()) {
updateMap(LOCATION_SIGNIFICANTLY_CHANGED); updateMap(LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED)
} else { } 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 * @return Returns true if search this area button is used around our current location
*/ */
public boolean searchCloseToCurrentLocation() { fun searchCloseToCurrentLocation(): Boolean {
if (null == exploreMapFragmentView.getLastMapFocus()) { val lastMapFocus = exploreMapFragmentView.getLastMapFocus() ?: return true
return true;
val myLocation = Location("").apply {
latitude = lastMapFocus.latitude
longitude = lastMapFocus.longitude
} }
Location mylocation = new Location(""); val destLocation = Location("").apply {
Location dest_location = new Location(""); latitude = exploreMapFragmentView.getMapFocus().latitude
dest_location.setLatitude(exploreMapFragmentView.getMapFocus().getLatitude()); longitude = exploreMapFragmentView.getMapFocus().longitude
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;
}
} }
return myLocation.distanceTo(destLocation) <= 2000.0 * 3 / 4
}
} }

View file

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

View file

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