Fixes #545 - Add support for campaigns (#4423)

* Integrate WLM
- Show monuments in maps along with nearby

* BugFix in Monuments
1. Single preference for monuments and campaigns
2. Expand collapse chips container in nearby
3. Typo fix in Monuments card in Nearby
4. If a nearby place is a monument as well - do not show them separately, show it as a monument instead
5. Bug fix, monument radius, use the same one as that of nearby

* More bug fixes
1. Possible NPE in nearby
2. Added column location_address in BookmarkLocationDao
3. Bug Fix - Display Date in WLM card
4. WLM card on click takes to nearby

* Use lowercase country code in WLM uploads

* Bug-Fix, WLM Campaign Icon

* 1. Updated monuments query to use any of the following properties for monuments - [P1435, P2186, P1459, P1460, P1216, P709, P718, P5694] 2. Append WikiData QID to descriptions template

* Updated WLM Banner String, Handle NPE in contributions callback

* Added nearby-monuments query log lines

* Handle WLM Query exception : - if an exception is thrown in WLM query, continue showing the nearby items if that succeeds

* Fix BookmarkLocationDaoTest

* Added Column Address in BookmarkLocationDaoTest

* Use fallback description as usual nearby pins even for WLM pins, instead of relying on P6375

* Test fix in BookmarkLocationDao

* Updated template for WLM, removed redundant feilds

* Fixed WLM template

* Removed categories from WLM template

* Fixed BookmarkControllerTest

* Fixed BookmarkLocationFragmentUnitTest

* fix ModelFunctions

* Fixed BookmarksDaoLocationTest

* Fixed WLM template
This commit is contained in:
Ashish 2021-08-18 13:57:26 +05:30 committed by GitHub
parent 67f5b6c271
commit 6588a6fd0e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 2906 additions and 185 deletions

View file

@ -17,6 +17,8 @@ import androidx.browser.customtabs.CustomTabColorSchemeParams;
import androidx.browser.customtabs.CustomTabsIntent;
import androidx.core.content.ContextCompat;
import fr.free.nrw.commons.kvstore.JsonKvStore;
import java.util.Date;
import org.wikipedia.dataclient.WikiSite;
import org.wikipedia.page.PageTitle;
@ -29,6 +31,7 @@ import fr.free.nrw.commons.utils.ViewUtil;
import timber.log.Timber;
import static android.widget.Toast.LENGTH_SHORT;
import static fr.free.nrw.commons.campaigns.CampaignView.CAMPAIGNS_DEFAULT_PREFERENCE;
public class Utils {
@ -210,4 +213,35 @@ public class Utils {
textView.setText(content);
}
/**
* For now we are enabling the monuments only when the date lies between 1 Sept & 31 OCt
* @param date
* @return
*/
public static boolean isMonumentsEnabled(final Date date, final JsonKvStore store){
if(date.getDay()>=1 && date.getMonth()>=9 && date.getDay()<=31 && date.getMonth()<=10 ){
return true;
}
return store.getBoolean(CAMPAIGNS_DEFAULT_PREFERENCE) || true ;
}
/**
* Util function to get the start date of wlm monument
* For this release we are hardcoding it to be 1st September
* @return
*/
public static String getWLMStartDate() {
return "1 Sep";
}
/***
* Util function to get the end date of wlm monument
* For this release we are hardcoding it to be 31st October
* @return
*/
public static String getWLMEndDate() {
return "31 Oct";
}
}

View file

@ -147,25 +147,25 @@ public class BookmarkLocationsDao {
}
@NonNull
Place fromCursor(Cursor cursor) {
LatLng location = new LatLng(cursor.getDouble(cursor.getColumnIndex(Table.COLUMN_LAT)),
Place fromCursor(final Cursor cursor) {
final LatLng location = new LatLng(cursor.getDouble(cursor.getColumnIndex(Table.COLUMN_LAT)),
cursor.getDouble(cursor.getColumnIndex(Table.COLUMN_LONG)), 1F);
Sitelinks.Builder builder = new Sitelinks.Builder();
final Sitelinks.Builder builder = new Sitelinks.Builder();
builder.setWikipediaLink(cursor.getString(cursor.getColumnIndex(Table.COLUMN_WIKIPEDIA_LINK)));
builder.setWikidataLink(cursor.getString(cursor.getColumnIndex(Table.COLUMN_WIKIDATA_LINK)));
builder.setCommonsLink(cursor.getString(cursor.getColumnIndex(Table.COLUMN_COMMONS_LINK)));
return new Place(
cursor.getString(cursor.getColumnIndex(Table.COLUMN_LANGUAGE)),
cursor.getString(cursor.getColumnIndex(Table.COLUMN_NAME)),
Label.fromText((cursor.getString(cursor.getColumnIndex(Table.COLUMN_LABEL_TEXT)))),
cursor.getString(cursor.getColumnIndex(Table.COLUMN_DESCRIPTION)),
location,
cursor.getString(cursor.getColumnIndex(Table.COLUMN_CATEGORY)),
builder.build(),
cursor.getString(cursor.getColumnIndex(Table.COLUMN_PIC)),
Boolean.parseBoolean(cursor.getString(cursor.getColumnIndex(Table.COLUMN_EXISTS)))
cursor.getString(cursor.getColumnIndex(Table.COLUMN_LANGUAGE)),
cursor.getString(cursor.getColumnIndex(Table.COLUMN_NAME)),
Label.fromText((cursor.getString(cursor.getColumnIndex(Table.COLUMN_LABEL_TEXT)))),
cursor.getString(cursor.getColumnIndex(Table.COLUMN_DESCRIPTION)),
location,
cursor.getString(cursor.getColumnIndex(Table.COLUMN_CATEGORY)),
builder.build(),
cursor.getString(cursor.getColumnIndex(Table.COLUMN_PIC)),
Boolean.parseBoolean(cursor.getString(cursor.getColumnIndex(Table.COLUMN_EXISTS)))
);
}
@ -220,7 +220,7 @@ public class BookmarkLocationsDao {
COLUMN_WIKIDATA_LINK,
COLUMN_COMMONS_LINK,
COLUMN_PIC,
COLUMN_EXISTS
COLUMN_EXISTS,
};
static final String DROP_TABLE_STATEMENT = "DROP TABLE IF EXISTS " + TABLE_NAME;
@ -251,7 +251,7 @@ public class BookmarkLocationsDao {
onCreate(db);
}
public static void onUpdate(SQLiteDatabase db, int from, int to) {
public static void onUpdate(final SQLiteDatabase db, int from, final int to) {
Timber.d("bookmarksLocations db is updated from:"+from+", to:"+to);
if (from == to) {
return;

View file

@ -7,4 +7,5 @@ data class Campaign(var title: String? = null,
var description: String? = null,
var startDate: String? = null,
var endDate: String? = null,
var link: String? = null)
var link: String? = null,
var isWLMCampaign: Boolean = false)

View file

@ -4,11 +4,13 @@ import android.content.Context;
import android.net.Uri;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import fr.free.nrw.commons.theme.BaseActivity;
import org.wikipedia.util.DateUtil;
import java.text.ParseException;
@ -27,9 +29,14 @@ import fr.free.nrw.commons.utils.ViewUtil;
* A view which represents a single campaign
*/
public class CampaignView extends SwipableCardView {
Campaign campaign = null;
Campaign campaign;
private ViewHolder viewHolder;
public static final String CAMPAIGNS_DEFAULT_PREFERENCE = "displayCampaignsCardView";
public static final String WLM_CARD_PREFERENCE = "displayWLMCardView";
private String campaignPreference = CAMPAIGNS_DEFAULT_PREFERENCE;
public CampaignView(@NonNull Context context) {
super(context);
init();
@ -45,37 +52,46 @@ public class CampaignView extends SwipableCardView {
init();
}
public void setCampaign(Campaign campaign) {
public void setCampaign(final Campaign campaign) {
this.campaign = campaign;
if (campaign != null) {
this.setVisibility(View.VISIBLE);
if (campaign.isWLMCampaign()) {
campaignPreference = WLM_CARD_PREFERENCE;
}
setVisibility(View.VISIBLE);
viewHolder.init();
} else {
this.setVisibility(View.GONE);
}
}
@Override public boolean onSwipe(View view) {
@Override public boolean onSwipe(final View view) {
view.setVisibility(View.GONE);
((MainActivity) getContext()).defaultKvStore
.putBoolean("displayCampaignsCardView", false);
((BaseActivity) getContext()).defaultKvStore
.putBoolean(campaignPreference, false);
ViewUtil.showLongToast(getContext(),
getResources().getString(R.string.nearby_campaign_dismiss_message));
return true;
}
private void init() {
View rootView = inflate(getContext(), R.layout.layout_campagin, this);
final View rootView = inflate(getContext(), R.layout.layout_campagin, this);
viewHolder = new ViewHolder(rootView);
setOnClickListener(view -> {
if (campaign != null) {
Utils.handleWebUrl(getContext(), Uri.parse(campaign.getLink()));
if (campaign.isWLMCampaign()) {
((MainActivity)(getContext())).showNearby();
} else {
Utils.handleWebUrl(getContext(), Uri.parse(campaign.getLink()));
}
}
});
}
public class ViewHolder {
@BindView(R.id.iv_campaign)
ImageView ivCampaign;
@BindView(R.id.tv_title) TextView tvTitle;
@BindView(R.id.tv_description) TextView tvDescription;
@BindView(R.id.tv_dates) TextView tvDates;
@ -86,14 +102,26 @@ public class CampaignView extends SwipableCardView {
public void init() {
if (campaign != null) {
ivCampaign.setImageDrawable(
getResources().getDrawable(R.drawable.ic_campaign));
tvTitle.setText(campaign.getTitle());
tvDescription.setText(campaign.getDescription());
try {
Date startDate = CommonsDateUtil.getIso8601DateFormatShort().parse(campaign.getStartDate());
Date endDate = CommonsDateUtil.getIso8601DateFormatShort().parse(campaign.getEndDate());
tvDates.setText(String.format("%1s - %2s", DateUtil.getExtraShortDateString(startDate),
DateUtil.getExtraShortDateString(endDate)));
} catch (ParseException e) {
if (campaign.isWLMCampaign()) {
tvDates.setText(
String.format("%1s - %2s", campaign.getStartDate(),
campaign.getEndDate()));
} else {
final Date startDate = CommonsDateUtil.getIso8601DateFormatShort()
.parse(campaign.getStartDate());
final Date endDate = CommonsDateUtil.getIso8601DateFormatShort()
.parse(campaign.getEndDate());
tvDates.setText(
String.format("%1s - %2s", startDate,
endDate));
}
} catch (final ParseException e) {
e.printStackTrace();
}
}

View file

@ -2,14 +2,13 @@ package fr.free.nrw.commons.contributions;
import static fr.free.nrw.commons.contributions.Contribution.STATE_FAILED;
import static fr.free.nrw.commons.contributions.Contribution.STATE_PAUSED;
import static fr.free.nrw.commons.nearby.fragments.NearbyParentFragment.WLM_URL;
import static fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@ -27,21 +26,21 @@ import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager.OnBackStackChangedListener;
import androidx.fragment.app.FragmentTransaction;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.notification.Notification;
import fr.free.nrw.commons.notification.NotificationController;
import fr.free.nrw.commons.theme.BaseActivity;
import java.text.ParseException;
import java.util.Date;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Named;
import androidx.work.WorkInfo;
import androidx.work.WorkManager;
import butterknife.BindView;
import butterknife.ButterKnife;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.campaigns.Campaign;
import fr.free.nrw.commons.campaigns.CampaignView;
import fr.free.nrw.commons.campaigns.CampaignsPresenter;
@ -59,10 +58,7 @@ import fr.free.nrw.commons.mwapi.OkHttpJsonApiClient;
import fr.free.nrw.commons.nearby.NearbyController;
import fr.free.nrw.commons.nearby.NearbyNotificationCardView;
import fr.free.nrw.commons.nearby.Place;
import fr.free.nrw.commons.notification.Notification;
import fr.free.nrw.commons.notification.NotificationActivity;
import fr.free.nrw.commons.notification.NotificationController;
import fr.free.nrw.commons.theme.BaseActivity;
import fr.free.nrw.commons.upload.worker.UploadWorker;
import fr.free.nrw.commons.utils.ConfigUtils;
import fr.free.nrw.commons.utils.DialogUtil;
@ -73,9 +69,6 @@ import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Named;
import timber.log.Timber;
public class ContributionsFragment
@ -118,6 +111,8 @@ public class ContributionsFragment
public TextView notificationCount;
private Campaign wlmCampaign;
@NonNull
public static ContributionsFragment newInstance() {
ContributionsFragment fragment = new ContributionsFragment();
@ -137,6 +132,7 @@ public class ContributionsFragment
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_contributions, container, false);
ButterKnife.bind(this, view);
initWLMCampaign();
presenter.onAttachView(this);
contributionsPresenter.onAttachView(this);
campaignView.setVisibility(View.GONE);
@ -177,6 +173,15 @@ public class ContributionsFragment
return view;
}
/**
* Initialise the campaign object for WML
*/
private void initWLMCampaign() {
wlmCampaign = new Campaign(getString(R.string.wlm_campaign_title),
getString(R.string.wlm_campaign_description), Utils.getWLMStartDate().toString(),
Utils.getWLMEndDate().toString(), WLM_URL, true);
}
@Override
public void onCreateOptionsMenu(@NonNull final Menu menu, @NonNull final MenuInflater inflater) {
inflater.inflate(R.menu.contribution_activity_notification_menu, menu);
@ -518,13 +523,17 @@ public class ContributionsFragment
}
/**
* ask the presenter to fetch the campaigns only if user has not manually disabled it
* As the home screen has limited space, we have choosen to show either campaigns or WLM card.
* The WLM Card gets the priority over monuments, so if the WLM is going on we show that instead
* of campaigns on the campaigns card
*/
private void fetchCampaigns() {
if (store.getBoolean("displayCampaignsCardView", true)) {
if (Utils.isMonumentsEnabled(new Date(), store)) {
campaignView.setCampaign(wlmCampaign);
campaignView.setVisibility(View.VISIBLE);
} else if (store.getBoolean(CampaignView.CAMPAIGNS_DEFAULT_PREFERENCE, true)) {
presenter.getCampaigns();
}
else{
} else {
campaignView.setVisibility(View.GONE);
}
}

View file

@ -90,7 +90,7 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
private ContributionsListAdapter adapter;
private Callback callback;
@Nullable private Callback callback;
private final int SPAN_COUNT_LANDSCAPE = 3;
private final int SPAN_COUNT_PORTRAIT = 1;
@ -150,7 +150,9 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
contributionsListPresenter.contributionList.observe(this.getViewLifecycleOwner(), list -> {
contributionsSize = list.size();
adapter.submitList(list);
callback.notifyDataSetChanged();
if (callback != null) {
callback.notifyDataSetChanged();
}
});
rvContributionsList.setAdapter(adapter);
adapter.registerAdapterDataObserver(new AdapterDataObserver() {
@ -172,7 +174,9 @@ public class ContributionsListFragment extends CommonsDaggerSupportFragment impl
@Override
public void onItemRangeChanged(final int positionStart, final int itemCount) {
super.onItemRangeChanged(positionStart, itemCount);
callback.viewPagerNotifyDataSetChanged();
if (callback != null) {
callback.viewPagerNotifyDataSetChanged();
}
}
});

View file

@ -373,6 +373,13 @@ public class MainActivity extends BaseActivity
super.onDestroy();
}
/**
* Public method to show nearby from the reference of this.
*/
public void showNearby() {
tabLayout.setSelectedItemId(NavTab.NEARBY.code());
}
public enum ActiveFragment {
CONTRIBUTIONS,
NEARBY,

View file

@ -13,7 +13,7 @@ import fr.free.nrw.commons.explore.recentsearches.RecentSearchesDao;
public class DBOpenHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "commons.db";
private static final int DATABASE_VERSION = 15;
private static final int DATABASE_VERSION = 17;
public static final String CONTRIBUTIONS_TABLE = "contributions";
private final String DROP_TABLE_STATEMENT="DROP TABLE IF EXISTS %s";

View file

@ -265,7 +265,9 @@ public class OkHttpJsonApiClient {
}
public Observable<List<Place>> getNearbyPlaces(LatLng cur, String language, double radius)
throws IOException {
throws Exception {
Timber.d("Fetching nearby items at radius %s", radius);
String wikidataQuery = FileUtils.readFromResource("/queries/nearby_query.rq");
String query = wikidataQuery
.replace("${RAD}", String.format(Locale.ROOT, "%.2f", radius))
@ -302,6 +304,67 @@ public class OkHttpJsonApiClient {
});
}
/**
* Wikidata query to fetch monuments
*
* @param cur : The current location coordinates
* @param language : The language
* @param radius : The radius around the current location within which we expect the results
* @return
* @throws IOException
*/
public Observable<List<Place>> getNearbyMonuments(LatLng cur, String language, final double radius){
Timber.d("Fetching monuments at radius %s", radius);
final String wikidataQuery;
try {
wikidataQuery = FileUtils.readFromResource("/queries/monuments_query.rq");
if (TextUtils.isEmpty(language)) {
language = "en";
}
String query = wikidataQuery
.replace("${RAD}", String.format(Locale.ROOT, "%.2f", radius))
.replace("${LAT}", String.format(Locale.ROOT, "%.4f", cur.getLatitude()))
.replace("${LONG}", String.format(Locale.ROOT, "%.4f", cur.getLongitude()))
.replace("${LANG}", language);
HttpUrl.Builder urlBuilder = HttpUrl
.parse(sparqlQueryUrl)
.newBuilder()
.addQueryParameter("query", query)
.addQueryParameter("format", "json");
Request request = new Request.Builder()
.url(urlBuilder.build())
.build();
Timber.d("Monuments URL: %s", request.url().toString());
return Observable.fromCallable(() -> {
final Response response = okHttpClient.newCall(request).execute();
if (response != null && response.body() != null && response.isSuccessful()) {
final String json = response.body().string();
if (json == null) {
return new ArrayList<>();
}
final NearbyResponse nearbyResponse = gson.fromJson(json, NearbyResponse.class);
final List<NearbyResultItem> bindings = nearbyResponse.getResults().getBindings();
final List<Place> places = new ArrayList<>();
for (final NearbyResultItem item : bindings) {
final Place place = Place.from(item);
place.setMonument(true);
places.add(place);
}
return places;
}
return new ArrayList<>();
});
} catch (final IOException e) {
e.printStackTrace();
return Observable.error(e);
}
}
/**
* Get the QIDs of all Wikidata items that are subclasses of the given Wikidata item. Example:
* bridge -> suspended bridge, aqueduct, etc

View file

@ -8,14 +8,17 @@ import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions;
import com.mapbox.mapboxsdk.annotations.Icon;
import com.mapbox.mapboxsdk.annotations.IconFactory;
import com.mapbox.mapboxsdk.geometry.LatLng;
import java.util.Objects;
public class NearbyBaseMarker extends BaseMarkerOptions<NearbyMarker, NearbyBaseMarker> {
public static final Parcelable.Creator<NearbyBaseMarker> CREATOR = new Parcelable.Creator<NearbyBaseMarker>() {
@Override
public NearbyBaseMarker createFromParcel(Parcel in) {
return new NearbyBaseMarker(in);
}
@Override
public NearbyBaseMarker[] newArray(int size) {
return new NearbyBaseMarker[size];
}
@ -70,4 +73,21 @@ public class NearbyBaseMarker extends BaseMarkerOptions<NearbyMarker, NearbyBase
dest.writeString(title);
dest.writeParcelable(place, 0);
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
final NearbyBaseMarker that = (NearbyBaseMarker) o;
return Objects.equals(place.location, that.place.location);
}
@Override
public int hashCode() {
return Objects.hash(place);
}
}

View file

@ -10,6 +10,7 @@ import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
import com.mapbox.mapboxsdk.annotations.IconFactory;
import com.mapbox.mapboxsdk.annotations.Marker;
import io.reactivex.Observable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
@ -127,6 +128,11 @@ public class NearbyController {
}
}
public Observable<List<Place>> queryWikiDataForMonuments(
final LatLng latLng, final String language) {
return nearbyPlaces.queryWikiDataForMonuments(latLng, language);
}
/**
* Loads attractions from location for list view, we need to return Place data type.
*
@ -168,6 +174,7 @@ public class NearbyController {
VectorDrawableCompat vectorDrawable = null;
VectorDrawableCompat vectorDrawableGreen = null;
VectorDrawableCompat vectorDrawableGrey = null;
VectorDrawableCompat vectorDrawableMonuments = null;
vectorDrawable = null;
try {
vectorDrawable = VectorDrawableCompat.create(
@ -176,6 +183,9 @@ public class NearbyController {
context.getResources(), R.drawable.ic_custom_map_marker_green, context.getTheme());
vectorDrawableGrey = VectorDrawableCompat.create(
context.getResources(), R.drawable.ic_custom_map_marker_grey, context.getTheme());
vectorDrawableMonuments = VectorDrawableCompat
.create(context.getResources(), R.drawable.ic_custom_map_marker_monuments,
context.getTheme());
} catch (Resources.NotFoundException e) {
// ignore when running tests.
}
@ -183,34 +193,39 @@ public class NearbyController {
Bitmap icon = UiUtils.getBitmap(vectorDrawable);
Bitmap iconGreen = UiUtils.getBitmap(vectorDrawableGreen);
Bitmap iconGrey = UiUtils.getBitmap(vectorDrawableGrey);
Bitmap iconMonuments = UiUtils.getBitmap(vectorDrawableMonuments);
for (Place place : placeList) {
NearbyBaseMarker nearbyBaseMarker = new NearbyBaseMarker();
String distance = formatDistanceBetween(curLatLng, place.location);
place.setDistance(distance);
NearbyBaseMarker nearbyBaseMarker = new NearbyBaseMarker();
nearbyBaseMarker.title(place.name);
nearbyBaseMarker.position(
new com.mapbox.mapboxsdk.geometry.LatLng(
place.location.getLatitude(),
place.location.getLongitude()));
new com.mapbox.mapboxsdk.geometry.LatLng(
place.location.getLatitude(),
place.location.getLongitude()));
nearbyBaseMarker.place(place);
// Check if string is only spaces or empty, if so place doesn't have any picture
if (!place.pic.trim().isEmpty()) {
if (place.isMonument()) {
nearbyBaseMarker.icon(IconFactory.getInstance(context)
.fromBitmap(iconMonuments));
}
else if (!place.pic.trim().isEmpty()) {
if (iconGreen != null) {
nearbyBaseMarker.icon(IconFactory.getInstance(context)
.fromBitmap(iconGreen));
.fromBitmap(iconGreen));
}
} else if (!place.exists) { // Means that the topic of the Wikidata item does not exist in the real world anymore, for instance it is a past event, or a place that was destroyed
if (iconGrey != null) {
nearbyBaseMarker.icon(IconFactory.getInstance(context)
.fromBitmap(iconGrey));
.fromBitmap(iconGrey));
}
} else {
nearbyBaseMarker.icon(IconFactory.getInstance(context)
.fromBitmap(icon));
.fromBitmap(icon));
}
baseMarkerOptions.add(nearbyBaseMarker);
}
}

View file

@ -5,6 +5,7 @@ import java.util.ArrayList;
public class NearbyFilterState {
private boolean existsSelected;
private boolean needPhotoSelected;
private boolean wlmSelected;
private int checkBoxTriState;
private ArrayList<Label> selectedLabels;
@ -16,6 +17,7 @@ public class NearbyFilterState {
private NearbyFilterState() {
existsSelected = false;
needPhotoSelected = true;
wlmSelected = true;
checkBoxTriState = -1; // Unknown
selectedLabels = new ArrayList<>(); // Initially empty
}
@ -39,6 +41,14 @@ public class NearbyFilterState {
getInstance().needPhotoSelected = needPhotoSelected;
}
public static void setWlmSelected(final boolean wlmSelected) {
getInstance().wlmSelected = wlmSelected;
}
public boolean isWlmSelected() {
return wlmSelected;
}
public boolean isExistsSelected() {
return existsSelected;
}

View file

@ -1,5 +1,6 @@
package fr.free.nrw.commons.nearby;
import io.reactivex.Observable;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.Collections;
@ -65,9 +66,9 @@ public class NearbyPlaces {
while (radius <= maxRadius) {
try {
places = getFromWikidataQuery(curLatLng, lang, radius);
} catch (InterruptedIOException e) {
Timber.e(e, "exception in fetching nearby places");
return places;
} catch (final Exception e) {
Timber.e(e, "Exception in fetching nearby places");
break;
}
Timber.d("%d results at radius: %f", places.size(), radius);
if (places.size() >= minResults) {
@ -91,7 +92,13 @@ public class NearbyPlaces {
* @return list of places obtained
* @throws IOException if query fails
*/
public List<Place> getFromWikidataQuery(LatLng cur, String lang, double radius) throws IOException {
public List<Place> getFromWikidataQuery(LatLng cur, String lang, double radius) throws Exception {
return okHttpJsonApiClient.getNearbyPlaces(cur, lang, radius).blockingSingle();
}
public Observable<List<Place>> queryWikiDataForMonuments(
LatLng latLng, String language) {
return okHttpJsonApiClient
.getNearbyMonuments(latLng, language, radius);
}
}

View file

@ -4,8 +4,10 @@ import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import fr.free.nrw.commons.nearby.NearbyController.NearbyPlacesInfo;
import org.apache.commons.lang3.StringUtils;
import fr.free.nrw.commons.location.LatLng;
@ -31,6 +33,7 @@ public class Place implements Parcelable {
public String distance;
public final Sitelinks siteLinks;
private boolean isMonument;
public Place(String language,String name, Label label, String longDescription, LatLng location, String category, Sitelinks siteLinks, String pic, Boolean exists) {
@ -56,6 +59,7 @@ public class Place implements Parcelable {
this.pic = (picString == null) ? "":picString;
String existString = in.readString();
this.exists = Boolean.parseBoolean(existString);
this.isMonument = in.readInt() == 1;
}
public static Place from(NearbyResultItem item) {
String itemClass = item.getClassName().getValue();
@ -80,20 +84,20 @@ public class Place implements Parcelable {
? " (" + description + ")" : "")
: description);
return new Place(
item.getLabel().getLanguage(),
item.getLabel().getValue(),
Label.fromText(classEntityId), // list
description, // description and label of Wikidata item
PlaceUtils.latLngFromPointString(item.getLocation().getValue()),
item.getCommonsCategory().getValue(),
new Sitelinks.Builder()
.setWikipediaLink(item.getWikipediaArticle().getValue())
.setCommonsLink(item.getCommonsArticle().getValue())
.setWikidataLink(item.getItem().getValue())
.build(),
item.getPic().getValue(),
// Checking if the place exists or not
(item.getDestroyed().getValue() == "") && (item.getEndTime().getValue() == ""));
item.getLabel().getLanguage(),
item.getLabel().getValue(),
Label.fromText(classEntityId), // list
description, // description and label of Wikidata item
PlaceUtils.latLngFromPointString(item.getLocation().getValue()),
item.getCommonsCategory().getValue(),
new Sitelinks.Builder()
.setWikipediaLink(item.getWikipediaArticle().getValue())
.setCommonsLink(item.getCommonsArticle().getValue())
.setWikidataLink(item.getItem().getValue())
.build(),
item.getPic().getValue(),
// Checking if the place exists or not
(item.getDestroyed().getValue() == "") && (item.getEndTime().getValue() == ""));
}
/**
@ -126,7 +130,9 @@ public class Place implements Parcelable {
* Gets the long description of the place
* @return long description
*/
public String getLongDescription() { return longDescription; }
public String getLongDescription() {
return longDescription;
}
/**
* Gets the Commons category of the place
@ -181,6 +187,22 @@ public class Place implements Parcelable {
return !(siteLinks == null || Uri.EMPTY.equals(siteLinks.getCommonsLink()));
}
/**
* Sets that this place in nearby is a WikiData monument
* @param monument
*/
public void setMonument(final boolean monument) {
isMonument = monument;
}
/**
* Returns if this place is a WikiData monument
* @return
*/
public boolean isMonument() {
return isMonument;
}
/**
* Check if we already have the exact same Place
* @param o Place being tested
@ -233,6 +255,7 @@ public class Place implements Parcelable {
dest.writeParcelable(siteLinks, 0);
dest.writeString(pic);
dest.writeString(exists.toString());
dest.writeInt(isMonument ? 1 : 0);
}
public static final Creator<Place> CREATOR = new Creator<Place>() {

View file

@ -3,7 +3,6 @@ package fr.free.nrw.commons.nearby.contract;
import android.content.Context;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.maps.MapboxMap;
import java.util.List;
@ -13,7 +12,6 @@ import fr.free.nrw.commons.location.LocationServiceManager;
import fr.free.nrw.commons.nearby.Label;
import fr.free.nrw.commons.nearby.NearbyBaseMarker;
import fr.free.nrw.commons.nearby.Place;
import fr.free.nrw.commons.nearby.presenter.NearbyParentFragmentPresenter;
public interface NearbyParentFragmentContract {
@ -60,7 +58,7 @@ public interface NearbyParentFragmentContract {
void displayAllMarkers();
void filterMarkersByLabels(List<Label> selectedLabels, boolean existsSelected, boolean needPhotoSelected, boolean filterForPlaceState, boolean filterForAllNoneType);
void filterMarkersByLabels(List<Label> selectedLabels, boolean existsSelected, boolean needPhotoSelected, boolean wlmSelected, boolean filterForPlaceState, boolean filterForAllNoneType);
LatLng getCameraTarget();

View file

@ -3,7 +3,6 @@ package fr.free.nrw.commons.nearby.fragments;
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SIGNIFICANTLY_CHANGED;
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.LOCATION_SLIGHTLY_CHANGED;
import static fr.free.nrw.commons.location.LocationServiceManager.LocationChangeType.MAP_UPDATED;
import static fr.free.nrw.commons.nearby.Label.TEXT_TO_DESCRIPTION;
import static fr.free.nrw.commons.utils.LengthUtils.formatDistanceBetween;
import static fr.free.nrw.commons.wikidata.WikidataConstants.PLACE_OBJECT;
@ -16,8 +15,8 @@ import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.drawable.VectorDrawable;
import android.location.LocationManager;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.text.Html;
@ -45,8 +44,8 @@ import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.appcompat.widget.SearchView;
import androidx.fragment.app.Fragment;
import androidx.appcompat.widget.AppCompatTextView;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
@ -54,6 +53,7 @@ import androidx.recyclerview.widget.RecyclerView;
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.chip.Chip;
import com.google.android.material.chip.ChipGroup;
@ -83,26 +83,24 @@ import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.auth.LoginActivity;
import fr.free.nrw.commons.bookmarks.locations.BookmarkLocationsDao;
import fr.free.nrw.commons.contributions.ContributionController;
import fr.free.nrw.commons.contributions.ContributionsFragment;
import fr.free.nrw.commons.contributions.MainActivity;
import fr.free.nrw.commons.contributions.MainActivity.ActiveFragment;
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.location.LocationServiceManager;
import fr.free.nrw.commons.location.LocationUpdateListener;
import fr.free.nrw.commons.navtab.NavTab;
import fr.free.nrw.commons.nearby.CheckBoxTriStates;
import fr.free.nrw.commons.nearby.Label;
import fr.free.nrw.commons.nearby.MarkerPlaceGroup;
import fr.free.nrw.commons.nearby.NearbyBaseMarker;
import fr.free.nrw.commons.nearby.NearbyController;
import fr.free.nrw.commons.nearby.NearbyController.NearbyPlacesInfo;
import fr.free.nrw.commons.nearby.NearbyFilterSearchRecyclerViewAdapter;
import fr.free.nrw.commons.nearby.NearbyFilterState;
import fr.free.nrw.commons.nearby.NearbyMarker;
import fr.free.nrw.commons.nearby.Place;
import fr.free.nrw.commons.nearby.contract.NearbyParentFragmentContract;
import fr.free.nrw.commons.nearby.presenter.NearbyParentFragmentPresenter;
import fr.free.nrw.commons.notification.NotificationActivity;
import fr.free.nrw.commons.utils.DialogUtil;
import fr.free.nrw.commons.utils.ExecutorUtils;
import fr.free.nrw.commons.utils.LayoutUtils;
@ -116,14 +114,18 @@ import fr.free.nrw.commons.utils.ViewUtil;
import fr.free.nrw.commons.wikidata.WikidataEditListener;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.inject.Named;
import kotlin.Unit;
import org.jetbrains.annotations.NotNull;
import timber.log.Timber;
@ -155,6 +157,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
@BindView(R.id.search_this_area_button) Button searchThisAreaButton;
@BindView(R.id.map_progress_bar) ProgressBar progressBar;
@BindView(R.id.choice_chip_exists) Chip chipExists;
@BindView(R.id.choice_chip_wlm) Chip chipWlm;
@BindView(R.id.choice_chip_needs_photo) Chip chipNeedsPhoto;
@BindView(R.id.choice_chip_group) ChipGroup choiceChipGroup;
@BindView(R.id.search_view) SearchView searchView;
@ -168,6 +171,14 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
@BindView(R.id.no_results_message) TextView noResultsView;
@BindView(R.id.tv_attribution)
AppCompatTextView tvAttribution;
@BindView(R.id.rl_container_wlm_month_message)
RelativeLayout rlContainerWLMMonthMessage;
@BindView(R.id.tv_learn_more)
AppCompatTextView tvLearnMore;
@BindView(R.id.iv_toggle_chips)
AppCompatImageView ivToggleChips;
@BindView(R.id.chip_view)
View llContainerChips;
@Inject LocationServiceManager locationManager;
@Inject NearbyController nearbyController;
@ -229,7 +240,12 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
/**
* Holds all the markers
*/
private List<NearbyBaseMarker> allMarkers;
private List<NearbyBaseMarker> allMarkers =new ArrayList<>();
/**
* WLM URL
*/
public static final String WLM_URL = "https://www.wikilovesmonuments.org/";
@NonNull
public static NearbyParentFragment newInstance() {
@ -268,6 +284,12 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
isDarkTheme = systemThemeUtils.isDeviceInNightMode();
if (Utils.isMonumentsEnabled(new Date(), applicationKvStore)) {
rlContainerWLMMonthMessage.setVisibility(View.VISIBLE);
} else {
rlContainerWLMMonthMessage.setVisibility(View.GONE);
}
cameraMoveListener= () -> presenter.onCameraMove(mapBox.getCameraPosition().target);
addCheckBoxCallback();
presenter.attachView(this);
@ -491,6 +513,9 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
setBottomSheetCallbacks();
decideButtonVisibilities();
addActionToTitle();
if(!Utils.isMonumentsEnabled(new Date(), applicationKvStore)){
chipWlm.setVisibility(View.GONE);
}
}
/**
@ -598,6 +623,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
Log.d("deneme5","setfilterState");
chipNeedsPhoto.setChecked(NearbyFilterState.getInstance().isNeedPhotoSelected());
chipExists.setChecked(NearbyFilterState.getInstance().isExistsSelected());
chipWlm.setChecked(NearbyFilterState.getInstance().isWlmSelected());
if (NearbyController.currentLocation != null) {
presenter.filterByMarkerType(nearbyFilterSearchRecyclerViewAdapter.selectedLabels, checkBoxTriStates.getState(), true, false);
}
@ -608,13 +634,8 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
chipNeedsPhoto.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (NearbyController.currentLocation != null) {
checkBoxTriStates.setState(CheckBoxTriStates.UNKNOWN);
if (isChecked) {
NearbyFilterState.setNeedPhotoSelected(true);
presenter.filterByMarkerType(nearbyFilterSearchRecyclerViewAdapter.selectedLabels, checkBoxTriStates.getState(), true, false);
} else {
NearbyFilterState.setNeedPhotoSelected(false);
presenter.filterByMarkerType(nearbyFilterSearchRecyclerViewAdapter.selectedLabels, checkBoxTriStates.getState(), true, false);
}
NearbyFilterState.setNeedPhotoSelected(isChecked);
presenter.filterByMarkerType(nearbyFilterSearchRecyclerViewAdapter.selectedLabels, checkBoxTriStates.getState(), true, false);
} else {
chipNeedsPhoto.setChecked(!isChecked);
}
@ -624,17 +645,23 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
chipExists.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (NearbyController.currentLocation != null) {
checkBoxTriStates.setState(CheckBoxTriStates.UNKNOWN);
if (isChecked) {
NearbyFilterState.setExistsSelected(true);
presenter.filterByMarkerType(nearbyFilterSearchRecyclerViewAdapter.selectedLabels, checkBoxTriStates.getState(), true, false);
} else {
NearbyFilterState.setExistsSelected(false);
presenter.filterByMarkerType(nearbyFilterSearchRecyclerViewAdapter.selectedLabels, checkBoxTriStates.getState(), true, false);
}
NearbyFilterState.setExistsSelected(isChecked);
presenter.filterByMarkerType(nearbyFilterSearchRecyclerViewAdapter.selectedLabels, checkBoxTriStates.getState(), true, false);
} else {
chipExists.setChecked(!isChecked);
}
});
chipWlm.setOnCheckedChangeListener((buttonView, isChecked) -> {
if(NearbyController.currentLocation!=null){
checkBoxTriStates.setState(CheckBoxTriStates.UNKNOWN);
NearbyFilterState.setWlmSelected(isChecked);
presenter.filterByMarkerType(nearbyFilterSearchRecyclerViewAdapter.selectedLabels, checkBoxTriStates.getState(), true, false);
}else{
chipWlm.setChecked(!isChecked);
}
});
}
/**
@ -852,40 +879,105 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
}
private void populatePlacesForCurrentLocation(final fr.free.nrw.commons.location.LatLng curlatLng,
final fr.free.nrw.commons.location.LatLng searchLatLng) {
compositeDisposable.add(Observable.fromCallable(() -> nearbyController
.loadAttractionsFromLocation(curlatLng, searchLatLng, false, true))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(nearbyPlacesInfo -> {
updateMapMarkers(nearbyPlacesInfo, true);
lastFocusLocation=searchLatLng;
},
throwable -> {
Timber.d(throwable);
showErrorMessage(getString(R.string.error_fetching_nearby_places)+throwable.getLocalizedMessage());
setProgressBarVisibility(false);
presenter.lockUnlockNearby(false);
setFilterState();
}));
final fr.free.nrw.commons.location.LatLng searchLatLng){
final Observable<NearbyPlacesInfo> nearbyPlacesInfoObservable = Observable
.fromCallable(() -> nearbyController
.loadAttractionsFromLocation(curlatLng, searchLatLng, false, true));
Observable<List<Place>> observableWikidataMonuments = Observable.empty();
if(Utils.isMonumentsEnabled(new Date(), applicationKvStore)){
observableWikidataMonuments =
nearbyController
.queryWikiDataForMonuments(searchLatLng, Locale.getDefault().getLanguage());
}
compositeDisposable.add(Observable.zip(nearbyPlacesInfoObservable
, observableWikidataMonuments.onErrorReturn(throwable -> {
showErrorMessage(getString(R.string.error_fetching_nearby_monuments) + throwable
.getLocalizedMessage());
return new ArrayList<>();
}),
(nearbyPlacesInfo, monuments) -> {
final List<Place> places = mergeNearbyPlacesAndMonuments(nearbyPlacesInfo.placeList,
monuments);
nearbyPlacesInfo.placeList.clear();
nearbyPlacesInfo.placeList.addAll(places);
return nearbyPlacesInfo;
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(nearbyPlacesInfo -> {
updateMapMarkers(nearbyPlacesInfo, true);
lastFocusLocation=searchLatLng;
},
throwable -> {
Timber.d(throwable);
showErrorMessage(getString(R.string.error_fetching_nearby_places)+throwable.getLocalizedMessage());
setProgressBarVisibility(false);
presenter.lockUnlockNearby(false);
setFilterState();
}));
}
private void populatePlacesForAnotherLocation(final fr.free.nrw.commons.location.LatLng curlatLng,
final fr.free.nrw.commons.location.LatLng searchLatLng) {
compositeDisposable.add(Observable.fromCallable(() -> nearbyController
.loadAttractionsFromLocation(curlatLng, searchLatLng, false, false))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(nearbyPlacesInfo -> {
updateMapMarkers(nearbyPlacesInfo, false);
lastFocusLocation=searchLatLng;
},
throwable -> {
Timber.d(throwable);
showErrorMessage(getString(R.string.error_fetching_nearby_places)+throwable.getLocalizedMessage());
setProgressBarVisibility(false);
presenter.lockUnlockNearby(false);
}));
final fr.free.nrw.commons.location.LatLng searchLatLng){
final Observable<NearbyPlacesInfo> nearbyPlacesInfoObservable = Observable
.fromCallable(() -> nearbyController
.loadAttractionsFromLocation(curlatLng, searchLatLng, false, false));
Observable<List<Place>> observableWikidataMonuments = Observable.empty();
if (Utils.isMonumentsEnabled(new Date(), applicationKvStore)) {
observableWikidataMonuments = nearbyController
.queryWikiDataForMonuments(searchLatLng, Locale.getDefault().getLanguage());
}
compositeDisposable.add(Observable.zip(nearbyPlacesInfoObservable
, observableWikidataMonuments.onErrorReturn(throwable -> {
showErrorMessage(getString(R.string.error_fetching_nearby_monuments) + throwable
.getLocalizedMessage());
return new ArrayList<>();
}),
(nearbyPlacesInfo, monuments) -> {
final List<Place> places = mergeNearbyPlacesAndMonuments(nearbyPlacesInfo.placeList,
monuments);
nearbyPlacesInfo.placeList.clear();
nearbyPlacesInfo.placeList.addAll(places);
return nearbyPlacesInfo;
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(nearbyPlacesInfo -> {
updateMapMarkers(nearbyPlacesInfo, false);
lastFocusLocation=searchLatLng;
},
throwable -> {
Timber.e(throwable);
showErrorMessage(getString(R.string.error_fetching_nearby_places)+throwable.getLocalizedMessage());
setProgressBarVisibility(false);
presenter.lockUnlockNearby(false);
setFilterState();
}));
}
/**
* If a nearby place happens to be a monument as well, don't make the Pin's overlap, instead
* show it as a monument
*
* @param nearbyPlaces
* @param monuments
* @return
*/
private List<Place> mergeNearbyPlacesAndMonuments(List<Place> nearbyPlaces, List<Place> monuments){
List<Place> allPlaces= new ArrayList<>();
allPlaces.addAll(monuments);
for (Place place : nearbyPlaces){
if(!allPlaces.contains(place)){
allPlaces.add(place);
}
}
return allPlaces;
}
/**
@ -1178,7 +1270,9 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
private void removeCurrentLocationMarker() {
if (currentLocationMarker != null && mapBox!=null) {
mapBox.removeMarker(currentLocationMarker);
mapBox.removePolygon(currentLocationPolygon);
if (currentLocationPolygon != null) {
mapBox.removePolygon(currentLocationPolygon);
}
}
}
@ -1244,6 +1338,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
public void filterMarkersByLabels(final List<Label> selectedLabels,
final boolean displayExists,
final boolean displayNeedsPhoto,
final boolean displayWlm,
final boolean filterForPlaceState,
final boolean filterForAllNoneType) {
@ -1263,23 +1358,36 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
continue;
}
if (displayExists && displayNeedsPhoto) {
if (!displayWlm && place.isMonument()) {
continue;
}
boolean shouldUpdateMarker=false;
if (displayWlm && place.isMonument()) {
shouldUpdateMarker=true;
}
else if (displayExists && displayNeedsPhoto) {
// Exists and needs photo
if (place.exists && place.pic.trim().isEmpty()) {
updateMarker(markerPlaceGroup.getIsBookmarked(), place, NearbyController.currentLocation);
shouldUpdateMarker=true;
}
} else if (displayExists && !displayNeedsPhoto) {
// Exists and all included needs and doesn't needs photo
if (place.exists) {
updateMarker(markerPlaceGroup.getIsBookmarked(), place, NearbyController.currentLocation);
shouldUpdateMarker=true;
}
} else if (!displayExists && displayNeedsPhoto) {
// All and only needs photo
if (place.pic.trim().isEmpty()) {
updateMarker(markerPlaceGroup.getIsBookmarked(), place, NearbyController.currentLocation);
shouldUpdateMarker=true;
}
} else if (!displayExists && !displayNeedsPhoto) {
// all
shouldUpdateMarker=true;
}
if(shouldUpdateMarker){
updateMarker(markerPlaceGroup.getIsBookmarked(), place, NearbyController.currentLocation);
}
}
@ -1337,7 +1445,10 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
}
private @DrawableRes int getIconFor(Place place, Boolean isBookmarked) {
if (!place.pic.trim().isEmpty()) {
if(place.isMonument()){
return R.drawable.ic_custom_map_marker_monuments;
}
else if (!place.pic.trim().isEmpty()) {
return (isBookmarked ?
R.drawable.ic_custom_map_marker_green_bookmarked :
R.drawable.ic_custom_map_marker_green);
@ -1397,7 +1508,7 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
}
@Override
public void recenterMap(final fr.free.nrw.commons.location.LatLng curLatLng) {
public void recenterMap(fr.free.nrw.commons.location.LatLng curLatLng) {
if (isPermissionDenied || curLatLng == null) {
recenterToUserLocation = true;
checkPermissionsAndPerformAction();
@ -1667,4 +1778,21 @@ public class NearbyParentFragment extends CommonsDaggerSupportFragment
rlBottomSheetLayoutParams.height = getActivity().getWindowManager().getDefaultDisplay().getHeight() / 16 * 9;
rlBottomSheet.setLayoutParams(rlBottomSheetLayoutParams);
}
@OnClick(R.id.tv_learn_more)
public void onLearnMoreClicked() {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(WLM_URL));
startActivity(intent);
}
@OnClick(R.id.iv_toggle_chips)
public void onToggleChipsClicked() {
if (llContainerChips.getVisibility() == View.VISIBLE) {
llContainerChips.setVisibility(View.GONE);
} else {
llContainerChips.setVisibility(View.VISIBLE);
}
ivToggleChips.setRotation(ivToggleChips.getRotation() + 180);
}
}

View file

@ -7,6 +7,7 @@ class NearbyResultItem(private val item: ResultTuple?,
private val commonsArticle: ResultTuple?,
private val location: ResultTuple?,
private val label: ResultTuple?,
@field:SerializedName("streetAddress") private val address: ResultTuple?,
private val icon: ResultTuple?, @field:SerializedName("class") private val className: ResultTuple?,
@field:SerializedName("classLabel") private val classLabel: ResultTuple?,
@field:SerializedName("commonsCategory") private val commonsCategory: ResultTuple?,
@ -66,4 +67,8 @@ class NearbyResultItem(private val item: ResultTuple?,
fun getEndTime(): ResultTuple {
return endTime ?: ResultTuple()
}
fun getAddress(): String {
return address?.value?:""
}
}

View file

@ -1,6 +1,5 @@
package fr.free.nrw.commons.nearby.presenter;
import android.util.Log;
import android.view.View;
import androidx.annotation.MainThread;
@ -297,6 +296,7 @@ public class NearbyParentFragmentPresenter
nearbyParentFragmentView.filterMarkersByLabels(selectedLabels,
NearbyFilterState.getInstance().isExistsSelected(),
NearbyFilterState.getInstance().isNeedPhotoSelected(),
NearbyFilterState.getInstance().isWlmSelected(),
filterForPlaceState, false);
nearbyParentFragmentView.setRecyclerViewAdapterAllSelected();
break;
@ -305,6 +305,7 @@ public class NearbyParentFragmentPresenter
nearbyParentFragmentView.filterMarkersByLabels(selectedLabels,
NearbyFilterState.getInstance().isExistsSelected(),
NearbyFilterState.getInstance().isNeedPhotoSelected(),
NearbyFilterState.getInstance().isWlmSelected(),
filterForPlaceState, false);
}
}

View file

@ -1,5 +1,6 @@
package fr.free.nrw.commons.repository;
import androidx.annotation.Nullable;
import fr.free.nrw.commons.category.CategoriesModel;
import fr.free.nrw.commons.category.CategoryItem;
import fr.free.nrw.commons.contributions.Contribution;
@ -26,6 +27,7 @@ import java.util.Locale;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;
import timber.log.Timber;
/**
* The repository class for UploadActivity
@ -280,6 +282,7 @@ public class UploadRepository {
* @param decLongitude
* @return
*/
@Nullable
public Place checkNearbyPlaces(double decLatitude, double decLongitude) {
try {
List<Place> fromWikidataQuery = nearbyPlaces.getFromWikidataQuery(new LatLng(
@ -287,7 +290,8 @@ public class UploadRepository {
Locale.getDefault().getLanguage(),
NEARBY_RADIUS_IN_KILO_METERS);
return fromWikidataQuery.size() > 0 ? fromWikidataQuery.get(0) : null;
} catch (IOException e) {
}catch (final Exception e) {
Timber.e("Error fetching nearby places: %s", e.getMessage());
return null;
}
}

View file

@ -8,11 +8,13 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import androidx.preference.ListPreference;
import androidx.preference.MultiSelectListPreference;
import androidx.preference.Preference;
import androidx.preference.Preference.OnPreferenceChangeListener;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceGroupAdapter;
import androidx.preference.PreferenceScreen;
@ -25,6 +27,7 @@ import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.maps.TelemetryDefinition;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.campaigns.CampaignView;
import fr.free.nrw.commons.contributions.MainActivity;
import fr.free.nrw.commons.di.ApplicationlessInjection;
import fr.free.nrw.commons.kvstore.JsonKvStore;
@ -104,7 +107,7 @@ public class SettingsFragment extends PreferenceFragmentCompat {
findPreference("displayNearbyCardView").setEnabled(false);
findPreference("descriptionDefaultLanguagePref").setEnabled(false);
findPreference("displayLocationPermissionForCardView").setEnabled(false);
findPreference("displayCampaignsCardView").setEnabled(false);
findPreference(CampaignView.CAMPAIGNS_DEFAULT_PREFERENCE).setEnabled(false);
}
findPreference("telemetryOptOut").setOnPreferenceChangeListener(
@ -127,7 +130,7 @@ public class SettingsFragment extends PreferenceFragmentCompat {
}
@Override
protected Adapter onCreateAdapter(PreferenceScreen preferenceScreen) {
protected Adapter onCreateAdapter(final PreferenceScreen preferenceScreen) {
return new PreferenceGroupAdapter(preferenceScreen) {
@Override
public void onBindViewHolder(PreferenceViewHolder holder, int position) {

View file

@ -13,6 +13,7 @@ import java.util.List;
import java.util.Locale;
import javax.inject.Inject;
import org.apache.commons.lang3.StringUtils;
import timber.log.Timber;
class PageContentsCreator {
@ -29,13 +30,15 @@ class PageContentsCreator {
this.context = context;
}
public String createFrom(Contribution contribution) {
public String createFrom(Contribution contribution, String countryCode) {
StringBuilder buffer = new StringBuilder();
final Media media = contribution.getMedia();
buffer
.append("== {{int:filedesc}} ==\n")
.append("{{Information\n")
.append("|description=").append(media.getFallbackDescription()).append("\n")
.append("|description=").append(media.getFallbackDescription())
.append("{{ on Wikidata|").append(contribution.getWikidataPlace().getId()).append("}}")
.append("\n")
.append("|source=").append("{{own}}\n")
.append("|author=[[User:").append(media.getAuthor()).append("|")
.append(media.getAuthor()).append("]]\n");
@ -48,6 +51,12 @@ class PageContentsCreator {
buffer.append("}}").append("\n");
if (contribution.getWikidataPlace()!=null && contribution.getWikidataPlace().isMonumentUpload()) {
buffer.append("{{Wiki Loves Monuments 2021|1= ")
.append(countryCode)
.append("}}").append("\n");
}
//Only add Location template (e.g. {{Location|37.51136|-77.602615}} ) if coords is not null
final String decimalCoords = contribution.getDecimalCoords();
if (decimalCoords != null) {
@ -66,6 +75,7 @@ class PageContentsCreator {
} else {
buffer.append("{{subst:unc}}");
}
Timber.d("Template: %s", buffer.toString());
return buffer.toString();
}

View file

@ -261,6 +261,11 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
return fragments.size();
}
@Override
public boolean isWLMUpload() {
return place!=null && place.isMonument();
}
@Override
public void showMessage(int messageResourceId) {
ViewUtil.showLongToast(this, messageResourceId);
@ -372,6 +377,11 @@ public class UploadActivity extends BaseActivity implements UploadContract.View,
public int getTotalNumberOfSteps() {
return fragments.size();
}
@Override
public boolean isWLMUpload() {
return place!=null && place.isMonument();
}
});
fragments.add(uploadMediaDetailFragment);
}

View file

@ -37,5 +37,6 @@ public class UploadBaseFragment extends CommonsDaggerSupportFragment {
int getTotalNumberOfSteps();
boolean isWLMUpload();
}
}

View file

@ -16,9 +16,7 @@ import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
@ -212,11 +210,11 @@ public class UploadClient {
public Observable<UploadResult> uploadFileFromStash(
final Contribution contribution,
final String uniqueFileName,
final String fileKey) {
final String fileKey, @Nullable String countryCode) {
try {
return uploadInterface
.uploadFileFromStash(csrfTokenClient.getTokenBlocking(),
pageContentsCreator.createFrom(contribution),
pageContentsCreator.createFrom(contribution, countryCode),
CommonsApplication.DEFAULT_EDIT_SUMMARY,
uniqueFileName,
fileKey).map(uploadResponse -> {

View file

@ -1,6 +1,7 @@
package fr.free.nrw.commons.upload
import android.os.Parcelable
import fr.free.nrw.commons.location.LatLng
import fr.free.nrw.commons.nearby.Place
import kotlinx.android.parcel.Parcelize
@ -9,14 +10,18 @@ data class WikidataPlace(
override val id: String,
override val name: String,
val imageValue: String?,
val wikipediaArticle: String?
val wikipediaArticle: String?,
val location: LatLng? = null,
val isMonumentUpload : Boolean =false
) :
WikidataItem, Parcelable {
constructor(place: Place) : this(
place.wikiDataEntityId!!,
place.name,
place.pic.takeIf { it.isNotBlank() },
place.siteLinks.wikipediaLink?.toString() ?: ""
place.siteLinks.wikipediaLink?.toString() ?: "",
place.location,
isMonumentUpload=place.isMonument
)
companion object {

View file

@ -16,6 +16,7 @@ import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import androidx.annotation.NonNull;
@ -48,6 +49,8 @@ public class MediaLicenseFragment extends UploadBaseFragment implements MediaLic
TextView tvShareLicenseSummary;
@BindView(R.id.tooltip)
ImageView tooltip;
@BindView(R.id.ll_info_monument_upload)
LinearLayout llInfoMonumentUpload;
@Inject
MediaLicenseContract.UserActionListener presenter;
@ -87,6 +90,16 @@ public class MediaLicenseFragment extends UploadBaseFragment implements MediaLic
initPresenter();
initLicenseSpinner();
presenter.getLicenses();
/**
* Show the wlm info message if the upload is a WLM upload
*/
if(callback.isWLMUpload()){
//TODO : Update the info message logo
llInfoMonumentUpload.setVisibility(View.VISIBLE);
}else{
llInfoMonumentUpload.setVisibility(View.GONE);
}
}
/**

View file

@ -3,12 +3,12 @@ package fr.free.nrw.commons.upload.worker
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.BitmapFactory
import android.location.Geocoder
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.work.CoroutineWorker
import androidx.work.Data
import androidx.work.WorkerParameters
import com.google.gson.Gson
import com.mapbox.mapboxsdk.plugins.localization.BuildConfig
import dagger.android.ContributesAndroidInjector
import fr.free.nrw.commons.CommonsApplication
@ -19,6 +19,7 @@ import fr.free.nrw.commons.contributions.ChunkInfo
import fr.free.nrw.commons.contributions.Contribution
import fr.free.nrw.commons.contributions.ContributionDao
import fr.free.nrw.commons.di.ApplicationlessInjection
import fr.free.nrw.commons.location.LatLng
import fr.free.nrw.commons.media.MediaClient
import fr.free.nrw.commons.upload.StashUploadState
import fr.free.nrw.commons.upload.UploadClient
@ -30,6 +31,7 @@ import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.withContext
import timber.log.Timber
import java.io.IOException
import java.util.*
import java.util.regex.Pattern
import javax.inject.Inject
@ -275,8 +277,16 @@ class UploadWorker(var appContext: Context, workerParams: WorkerParameters) :
try {
//Upload the file from stash
var countryCode: String? =null
with(contribution.wikidataPlace?.location){
if(contribution.wikidataPlace?.isMonumentUpload!!) {
countryCode =
reverseGeoCode(contribution.wikidataPlace?.location!!)?.toLowerCase()
}
}
val uploadResult = uploadClient.uploadFileFromStash(
contribution, uniqueFileName, stashUploadResult.fileKey
contribution, uniqueFileName, stashUploadResult.fileKey, countryCode
).blockingSingle()
if (uploadResult.isSuccessful()) {
@ -339,6 +349,26 @@ class UploadWorker(var appContext: Context, workerParams: WorkerParameters) :
}
}
private fun reverseGeoCode(latLng: LatLng): String? {
val geocoder = Geocoder(
CommonsApplication.getInstance().applicationContext, Locale
.getDefault()
)
try {
val addresses =
geocoder.getFromLocation(latLng.latitude, latLng.longitude, 1)
for (address in addresses) {
if (address != null && address.locale.isO3Country != null) {
return address.locale.country
}
}
} catch (e: IOException) {
Timber.e(e)
}
return null
}
private fun clearChunks(contribution: Contribution) {
contribution.chunkInfo=null
contributionDao.saveSynchronous(contribution)

File diff suppressed because it is too large Load diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

View file

@ -37,6 +37,14 @@
app:chipBackgroundColor="@color/bg_chip_state"
android:text="@string/place_state_needs_photo"/>
<com.google.android.material.chip.Chip
android:id="@+id/choice_chip_wlm"
style="@style/Widget.MaterialComponents.Chip.Filter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:chipBackgroundColor="@color/bg_chip_state"
android:text="@string/place_state_wlm"/>
</com.google.android.material.chip.ChipGroup>
</LinearLayout>

View file

@ -3,9 +3,9 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_marginBottom="@dimen/activity_margin_horizontal"
android:padding="@dimen/standard_gap"
>
android:padding="@dimen/standard_gap">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -67,8 +67,29 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:padding="10dp"
android:orientation="vertical">
<LinearLayout
android:id="@+id/ll_info_monument_upload"
android:visibility="gone"
tools:visibility="visible"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="96dp"
android:layout_height="96dp"
app:srcCompat="@drawable/ic_custom_map_marker_monuments"/>
<androidx.appcompat.widget.AppCompatTextView
android:layout_marginLeft="10dp"
android:layout_width="match_parent"
android:text="@string/wlm_upload_info"
android:layout_height="wrap_content"/>
</LinearLayout>
<fr.free.nrw.commons.ui.widget.HtmlTextView
android:id="@+id/tv_media_upload_policy"
android:layout_width="match_parent"

View file

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -15,6 +16,35 @@
layout="@layout/nearby_filter_all_items"
android:id="@+id/nearby_filter"/>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="12dp"
android:gravity="center"
android:id="@+id/rl_container_wlm_month_message"
android:background="@color/white"
tools:visibility="visible"
android:visibility="gone"
android:layout_below="@id/nearby_filter">
<androidx.appcompat.widget.AppCompatTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toStartOf="@id/tv_learn_more"
android:textStyle="bold"
android:textColor="@color/secondaryTextColor"
android:text="@string/wlm_month_message"/>
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tv_learn_more"
android:textColor="@color/status_bar_blue"
android:textStyle="bold"
android:layout_width="wrap_content"
android:layout_alignParentEnd="true"
android:text="@string/learn_more"
android:layout_height="wrap_content">
</androidx.appcompat.widget.AppCompatTextView>
</RelativeLayout>
<include layout="@layout/nearby_filter_list"
android:id="@+id/nearby_filter_list"
android:layout_below="@id/nearby_filter"
@ -28,7 +58,7 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/nearby_filter">
android:layout_below="@id/rl_container_wlm_month_message">
<com.mapbox.mapboxsdk.maps.MapView
android:id="@+id/map_view"
@ -69,7 +99,8 @@
android:textColor="@color/status_bar_blue"
android:visibility="gone"
app:elevation="@dimen/dimen_6"
android:layout_below="@id/nearby_filter"/>
android:layout_below="@id/rl_container_wlm_month_message"
/>
<View
android:id="@+id/transparentView"
@ -88,7 +119,7 @@
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentRight="true"
android:layout_below="@id/nearby_filter"
android:layout_below="@id/rl_container_wlm_month_message"
android:clickable="true"
android:visibility="visible"
app:backgroundTint="@color/main_background_light"

View file

@ -1,22 +1,35 @@
<LinearLayout android:layout_width="match_parent"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@color/status_bar_blue">
<include
android:layout_toStartOf="@+id/iv_toggle_chips"
android:id="@+id/chip_view"
layout="@layout/filter_chip_view"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
android:layout_width="match_parent"
android:background="@color/deleteRed" />
<include
android:id="@+id/chip_view"
layout="@layout/filter_chip_view"
android:background="@color/deleteRed"
/>
<include
android:layout_toStartOf="@+id/iv_toggle_chips"
android:id="@+id/search_view_layout"
layout="@layout/filter_search_view_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/chip_view" />
<include android:id="@+id/search_view_layout" layout="@layout/filter_search_view_layout" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/iv_toggle_chips"
android:layout_width="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:scaleType="centerCrop"
app:srcCompat="@drawable/ic_expand_less_black_24dp"
android:tint="@color/white"
android:layout_height="wrap_content"
android:padding="12dp"
android:layout_gravity="center" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/search_view_layout"
android:background="@color/status_bar_blue">
</RelativeLayout>
</LinearLayout>
</RelativeLayout>

View file

@ -323,6 +323,7 @@
<string name="share_app_title">Share App</string>
<string name="error_fetching_nearby_places">Error fetching nearby places.</string>
<string name="error_fetching_nearby_monuments">Error fetching nearby monuments.</string>
<string name="no_recent_searches">No recent searches</string>
<string name="delete_recent_searches_dialog">Are you sure you want to clear your search history?</string>
<string name="delete_search_dialog">Do you want to delete this search?</string>
@ -638,5 +639,12 @@ Upload your first media by tapping on the add button.</string>
The shadow of the image view of the location picker</string>
<string name="image_location">Image Location</string>
<string name="check_whether_location_is_correct">Check whether location is correct</string>
<string name="place_state_wlm">WLM</string>
<string name="wlm_upload_info">You are contributing to Wiki Loves Monuments Campaign. Related templates will be added accordingly.</string>
<string name="display_monuments">Display monuments</string>
<string name="wlm_month_message">It\'s Wiki Loves Monuments month!</string>
<string name="learn_more">LEARN MORE</string>
<string name="wlm_campaign_title">Wiki Loves Monuments</string>
<string name="wlm_campaign_description">Wiki Loves Monuments is an international photo contest for monuments organised by Wikimedia</string>
</resources>

View file

@ -70,7 +70,6 @@
app:singleLineTitle="false"
android:summary="@string/display_campaigns_explanation"
android:title="@string/display_campaigns" />
</PreferenceCategory>
<PreferenceCategory

View file

@ -0,0 +1,60 @@
SELECT
(SAMPLE(?location) as ?location)
?item
(SAMPLE(COALESCE(?itemLabelPreferredLanguage, ?itemLabelAnyLanguage)) as ?label)
(SAMPLE(COALESCE(?itemDescriptionPreferredLanguage, ?itemDescriptionAnyLanguage, "?")) as ?description)
(SAMPLE(?classId) as ?class)
(SAMPLE(COALESCE(?classLabelPreferredLanguage, ?classLabelAnyLanguage, "?")) as ?classLabel)
(SAMPLE(COALESCE(?icon0, ?icon1)) as ?icon)
?wikipediaArticle
?commonsArticle
(SAMPLE(?commonsCategory) as ?commonsCategory)
(SAMPLE(?pic) as ?pic)
WHERE {
# Around given location...
SERVICE wikibase:around {
?item wdt:P625 ?location.
bd:serviceParam wikibase:center "Point(${LONG} ${LAT})"^^geo:wktLiteral.
bd:serviceParam wikibase:radius "${RAD}" . # Radius in kilometers.
}
{ ?item p:P1435 ?monument } UNION { ?item p:P2186 ?monument } UNION { ?item p:P1459 ?monument } UNION { ?item p:P1460 ?monument } UNION { ?item p:P1216 ?monument } UNION { ?item p:P709 ?monument } UNION { ?item p:P718 ?monument } UNION { ?item p:P5694 ?monument }
# Get Commons category (P373)
OPTIONAL { ?item wdt:P373 ?commonsCategory. }
# Get (P18)
OPTIONAL { ?item wdt:P18 ?pic. }
# Get the label in the preferred language of the user, or any other language if no label is available in that language.
OPTIONAL {?item rdfs:label ?itemLabelPreferredLanguage. FILTER (lang(?itemLabelPreferredLanguage) = "${LANG}")}
OPTIONAL {?item rdfs:label ?itemLabelAnyLanguage}
# Get the description in the preferred language of the user, or any other language if no description is available in that language.
OPTIONAL {?item schema:description ?itemDescriptionPreferredLanguage. FILTER (lang(?itemDescriptionPreferredLanguage) = "${LANG}")}
OPTIONAL {?item schema:description ?itemDescriptionAnyLanguage }
# Get the class label in the preferred language of the user, or any other language if no label is available in that language.
OPTIONAL {
?item p:P31/ps:P31 ?classId.
OPTIONAL {?classId rdfs:label ?classLabelPreferredLanguage. FILTER (lang(?classLabelPreferredLanguage) = "")}
OPTIONAL {?classId rdfs:label ?classLabelAnyLanguage}
OPTIONAL {
?wikipediaArticle schema:about ?item ;
schema:isPartOf <https://.wikipedia.org/> .
}
OPTIONAL {
?wikipediaArticle schema:about ?item ;
schema:isPartOf <https://en.wikipedia.org/> .
SERVICE wikibase:label { bd:serviceParam wikibase:language "en" }
}
OPTIONAL {
?commonsArticle schema:about ?item ;
schema:isPartOf <https://commons.wikimedia.org/> .
SERVICE wikibase:label { bd:serviceParam wikibase:language "en" }
}
}
}
GROUP BY ?item ?wikipediaArticle ?commonsArticle

View file

@ -1,9 +1,6 @@
package fr.free.nrw.commons.bookmarks.locations
import android.net.Uri
import com.nhaarman.mockitokotlin2.whenever
import fr.free.nrw.commons.bookmarks.Bookmark
import fr.free.nrw.commons.bookmarks.pictures.BookmarkPicturesDao
import fr.free.nrw.commons.nearby.Place
import org.junit.Assert
import org.junit.Before
@ -33,8 +30,23 @@ class BookmarkLocationControllerTest {
private val mockBookmarkList: List<Place>
private get() {
val list = ArrayList<Place>()
list.add(Place("en","a place",null,"a description",null,"a cat",null,null,true))
list.add(Place("en","another place",null,"another description",null,"another cat",null,null,true))
list.add(
Place(
"en", "a place", null, "a description", null, "a cat", null, null, true)
)
list.add(
Place(
"en",
"another place",
null,
"another description",
null,
"another cat",
null,
null,
true
)
)
return list
}

View file

@ -77,7 +77,18 @@ class BookmarkLocationFragmentUnitTests {
private val mockBookmarkList: List<Place>
private get() {
val list = ArrayList<Place>()
list.add(Place("en","a place",null,"a description",null,"a cat",null,null,true))
list.add(
Place(
"en",
"a place",
null,
"a description",
null,
"a cat",
null,
null,
true)
)
return list
}

View file

@ -265,7 +265,14 @@ class NearbyParentFragmentPresenterTest {
fun testFilterByMarkerTypeMultiSelectCHECKED() {
val state = CheckBoxTriStates.CHECKED
nearbyPresenter.filterByMarkerType(selectedLabels, state, false,true)
verify(nearbyParentFragmentView).filterMarkersByLabels(ArgumentMatchers.anyList(),ArgumentMatchers.anyBoolean(),ArgumentMatchers.anyBoolean(),ArgumentMatchers.anyBoolean(),ArgumentMatchers.anyBoolean());
verify(nearbyParentFragmentView).filterMarkersByLabels(
ArgumentMatchers.anyList(),
ArgumentMatchers.anyBoolean(),
ArgumentMatchers.anyBoolean(),
ArgumentMatchers.anyBoolean(),
ArgumentMatchers.anyBoolean(),
ArgumentMatchers.anyBoolean()
);
verify(nearbyParentFragmentView).setRecyclerViewAdapterAllSelected()
verifyNoMoreInteractions(nearbyParentFragmentView)
}
@ -276,7 +283,14 @@ class NearbyParentFragmentPresenterTest {
@Test
fun testFilterByMarkerTypeSingleSelect() {
nearbyPresenter.filterByMarkerType(selectedLabels, 0, true,false)
verify(nearbyParentFragmentView).filterMarkersByLabels(any(), any(), any(), any(), any());
verify(nearbyParentFragmentView).filterMarkersByLabels(
any(),
any(),
any(),
any(),
any(),
any()
);
verifyNoMoreInteractions(nearbyParentFragmentView)
}