Refactoring travel helpers
This commit is contained in:
parent
a5f0622dcd
commit
6236da3a02
20 changed files with 639 additions and 295 deletions
|
@ -1727,13 +1727,12 @@ public class BinaryMapIndexReader {
|
|||
double half16t = MapUtils.getDistance(lat, MapUtils.getLongitudeFromTile(16, ((int) dx) + 0.5),
|
||||
lat, MapUtils.getLongitudeFromTile(16, (int) dx));
|
||||
double cf31 = ((double) radiusMeters / (half16t * 2)) * (1 << 15);
|
||||
int y31 = MapUtils.get31TileNumberY(lat);
|
||||
int x31 = MapUtils.get31TileNumberX(lon);
|
||||
left = (int) (x31 - cf31);
|
||||
right = (int) (x31 + cf31);
|
||||
top = (int) (y31 - cf31);
|
||||
bottom = (int) (y31 + cf31);
|
||||
|
||||
y = MapUtils.get31TileNumberY(lat);
|
||||
x = MapUtils.get31TileNumberX(lon);
|
||||
left = (int) (x - cf31);
|
||||
right = (int) (x + cf31);
|
||||
top = (int) (y - cf31);
|
||||
bottom = (int) (y + cf31);
|
||||
}
|
||||
|
||||
public boolean publish(T obj) {
|
||||
|
|
|
@ -44,6 +44,7 @@ public class Amenity extends MapObject {
|
|||
public static final String IS_AGGR_PART = "is_aggr_part";
|
||||
public static final String CONTENT_JSON = "content_json";
|
||||
public static final String ROUTE_ID = "route_id";
|
||||
public static final String ROUTE_SOURCE = "route_source";
|
||||
|
||||
|
||||
private String subType;
|
||||
|
|
|
@ -16,11 +16,13 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
|
||||
|
||||
|
|
|
@ -78,6 +78,10 @@ public class Algorithms {
|
|||
return map == null || map.size() == 0;
|
||||
}
|
||||
|
||||
public static String emptyIfNull(String s) {
|
||||
return s == null ? "" : s;
|
||||
}
|
||||
|
||||
public static boolean isEmpty(CharSequence s) {
|
||||
return s == null || s.length() == 0;
|
||||
}
|
||||
|
@ -86,6 +90,10 @@ public class Algorithms {
|
|||
return s == null || s.trim().length() == 0;
|
||||
}
|
||||
|
||||
public static int hash(Object... values) {
|
||||
return Arrays.hashCode(values);
|
||||
}
|
||||
|
||||
public static boolean stringsEqual(String s1, String s2) {
|
||||
if (s1 == null && s2 == null) {
|
||||
return true;
|
||||
|
|
|
@ -427,7 +427,7 @@ public class MapMarkersGroupsAdapter extends RecyclerView.Adapter<RecyclerView.V
|
|||
@Override
|
||||
public void onClick(View v) {
|
||||
if (mapActivity.getSupportFragmentManager() != null) {
|
||||
WikivoyageArticleDialogFragment.showInstanceByTitle(app, mapActivity.getSupportFragmentManager(), article.getTitle(), article.getLang());
|
||||
WikivoyageArticleDialogFragment.showInstance(app, mapActivity.getSupportFragmentManager(), article.generateIdentifier(), article.getLang());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -39,6 +39,7 @@ import com.squareup.picasso.RequestCreator;
|
|||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.GPXUtilities;
|
||||
import net.osmand.GPXUtilities.GPXFile;
|
||||
import net.osmand.GPXUtilities.Metadata;
|
||||
import net.osmand.GPXUtilities.WptPt;
|
||||
import net.osmand.PicassoUtils;
|
||||
import net.osmand.data.PointDescription;
|
||||
|
@ -422,7 +423,7 @@ public class TrackActivityFragmentAdapter implements TrackBitmapDrawerListener {
|
|||
return null;
|
||||
}
|
||||
|
||||
TravelArticle article = getTravelArticle(gpx.metadata);
|
||||
TravelArticle article = getTravelArticle(gpx);
|
||||
if (article != null) {
|
||||
return createTravelArticleCard(context, article);
|
||||
}
|
||||
|
@ -448,7 +449,7 @@ public class TrackActivityFragmentAdapter implements TrackBitmapDrawerListener {
|
|||
}
|
||||
|
||||
@Nullable
|
||||
private String getMetadataDescription(@NonNull GPXUtilities.Metadata metadata) {
|
||||
private String getMetadataDescription(@NonNull Metadata metadata) {
|
||||
String descHtml = metadata.desc;
|
||||
if (TextUtils.isEmpty(descHtml)) {
|
||||
Map<String, String> extensions = metadata.getExtensionsToRead();
|
||||
|
@ -466,7 +467,7 @@ public class TrackActivityFragmentAdapter implements TrackBitmapDrawerListener {
|
|||
}
|
||||
|
||||
@Nullable
|
||||
private String getMetadataImageLink(@NonNull GPXUtilities.Metadata metadata) {
|
||||
private String getMetadataImageLink(@NonNull Metadata metadata) {
|
||||
String link = metadata.link;
|
||||
if (!TextUtils.isEmpty(link)) {
|
||||
String lowerCaseLink = link.toLowerCase();
|
||||
|
@ -482,11 +483,12 @@ public class TrackActivityFragmentAdapter implements TrackBitmapDrawerListener {
|
|||
}
|
||||
|
||||
@Nullable
|
||||
private TravelArticle getTravelArticle(@NonNull GPXUtilities.Metadata metadata) {
|
||||
private TravelArticle getTravelArticle(@NonNull GPXFile gpx) {
|
||||
Metadata metadata = gpx.metadata;
|
||||
String title = metadata.getArticleTitle();
|
||||
String lang = metadata.getArticleLang();
|
||||
if (!TextUtils.isEmpty(title) && !TextUtils.isEmpty(lang)) {
|
||||
return app.getTravelHelper().getArticleByTitle(title, lang);
|
||||
return app.getTravelHelper().getArticleByTitle(title, gpx.getRect(), lang);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -506,8 +508,8 @@ public class TrackActivityFragmentAdapter implements TrackBitmapDrawerListener {
|
|||
public void onClick(View v) {
|
||||
TrackActivity activity = getTrackActivity();
|
||||
if (activity != null) {
|
||||
WikivoyageArticleDialogFragment.showInstance(app,
|
||||
activity.getSupportFragmentManager(), article.getRouteId(), article.getLang());
|
||||
WikivoyageArticleDialogFragment.showInstance(app, activity.getSupportFragmentManager(),
|
||||
article.generateIdentifier(), article.getLang());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -14,6 +14,7 @@ import androidx.fragment.app.FragmentManager;
|
|||
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.GPXUtilities;
|
||||
import net.osmand.GPXUtilities.WptPt;
|
||||
import net.osmand.data.LatLon;
|
||||
import net.osmand.data.PointDescription;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
|
@ -22,6 +23,7 @@ import net.osmand.plus.settings.backend.OsmandSettings;
|
|||
import net.osmand.plus.wikipedia.WikiArticleHelper;
|
||||
import net.osmand.plus.wikivoyage.article.WikivoyageArticleDialogFragment;
|
||||
import net.osmand.plus.wikivoyage.data.TravelArticle;
|
||||
import net.osmand.plus.wikivoyage.data.TravelArticle.TravelArticleIdentifier;
|
||||
import net.osmand.plus.wikivoyage.explore.WikivoyageExploreActivity;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -67,8 +69,8 @@ public class WikivoyageWebViewClient extends WebViewClient {
|
|||
if (url.contains(WIKIVOYAGE_DOMAIN) && isWebPage) {
|
||||
String lang = WikiArticleHelper.getLang(url);
|
||||
String articleName = WikiArticleHelper.getArticleNameFromUrl(url, lang);
|
||||
String articleId = app.getTravelHelper().getArticleId(articleName, lang);
|
||||
if (!articleId.isEmpty()) {
|
||||
TravelArticleIdentifier articleId = app.getTravelHelper().getArticleId(articleName, lang);
|
||||
if (articleId != null) {
|
||||
WikivoyageArticleDialogFragment.showInstance(app, fragmentManager, articleId, lang);
|
||||
} else {
|
||||
WikiArticleHelper.warnAboutExternalLoad(url, activity, nightMode);
|
||||
|
@ -83,8 +85,8 @@ public class WikivoyageWebViewClient extends WebViewClient {
|
|||
WikiArticleHelper.warnAboutExternalLoad(url, activity, nightMode);
|
||||
} else if (url.startsWith(PREFIX_GEO)) {
|
||||
if (article != null) {
|
||||
List<GPXUtilities.WptPt> points = article.getGpxFile().getPoints();
|
||||
GPXUtilities.WptPt gpxPoint = null;
|
||||
List<WptPt> points = article.getGpxFile().getPoints();
|
||||
WptPt gpxPoint = null;
|
||||
String coordinates = url.replace(PREFIX_GEO, "");
|
||||
double lat;
|
||||
double lon;
|
||||
|
@ -96,7 +98,7 @@ public class WikivoyageWebViewClient extends WebViewClient {
|
|||
Log.w(TAG, e.getMessage(), e);
|
||||
return true;
|
||||
}
|
||||
for (GPXUtilities.WptPt point : points) {
|
||||
for (WptPt point : points) {
|
||||
if (point.getLatitude() == lat && point.getLongitude() == lon) {
|
||||
gpxPoint = point;
|
||||
break;
|
||||
|
|
|
@ -30,17 +30,18 @@ import net.osmand.AndroidUtils;
|
|||
import net.osmand.IndexConstants;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.OsmandPlugin;
|
||||
import net.osmand.plus.UiUtilities;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.UiUtilities;
|
||||
import net.osmand.plus.activities.TrackActivity;
|
||||
import net.osmand.plus.development.OsmandDevelopmentPlugin;
|
||||
import net.osmand.plus.helpers.FileNameTranslationHelper;
|
||||
import net.osmand.plus.settings.backend.OsmandSettings;
|
||||
import net.osmand.plus.wikipedia.WikiArticleBaseDialogFragment;
|
||||
import net.osmand.plus.wikipedia.WikiArticleHelper;
|
||||
import net.osmand.plus.wikivoyage.WikivoyageShowPicturesDialogFragment;
|
||||
import net.osmand.plus.wikivoyage.WikivoyageWebViewClient;
|
||||
import net.osmand.plus.wikivoyage.data.TravelArticle;
|
||||
import net.osmand.plus.wikivoyage.data.TravelArticle.TravelArticleIdentifier;
|
||||
import net.osmand.plus.wikivoyage.data.TravelHelper;
|
||||
import net.osmand.plus.wikivoyage.data.TravelLocalDataHelper;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
@ -58,15 +59,15 @@ public class WikivoyageArticleDialogFragment extends WikiArticleBaseDialogFragme
|
|||
public static final String TAG = "WikivoyageArticleDialogFragment";
|
||||
|
||||
|
||||
private static final String ROUTE_ID_KEY = "route_id_key";
|
||||
private static final String LANGS_KEY = "langs_key";
|
||||
private static final String SELECTED_LANG_KEY = "selected_lang_key";
|
||||
private static final String ARTICLE_ID_KEY = "article_id";
|
||||
private static final String LANGS_KEY = "langs";
|
||||
private static final String SELECTED_LANG_KEY = "selected_lang";
|
||||
|
||||
private static final String EMPTY_URL = "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d4//";
|
||||
|
||||
private static final int MENU_ITEM_SHARE = 0;
|
||||
|
||||
private String routeId = "";
|
||||
private TravelArticleIdentifier articleId;
|
||||
private ArrayList<String> langs;
|
||||
private String selectedLang;
|
||||
private TravelArticle article;
|
||||
|
@ -192,15 +193,17 @@ public class WikivoyageArticleDialogFragment extends WikiArticleBaseDialogFragme
|
|||
if (requestCode == WikivoyageArticleContentsFragment.SHOW_CONTENT_ITEM_REQUEST_CODE) {
|
||||
String link = data.getStringExtra(WikivoyageArticleContentsFragment.CONTENT_ITEM_LINK_KEY);
|
||||
String title = data.getStringExtra(WikivoyageArticleContentsFragment.CONTENT_ITEM_TITLE_KEY);
|
||||
moveToAnchor(link, title);
|
||||
if (title != null) {
|
||||
moveToAnchor(link, title);
|
||||
}
|
||||
} else if (requestCode == WikivoyageShowPicturesDialogFragment.SHOW_PICTURES_CHANGED_REQUEST_CODE) {
|
||||
updateWebSettings();
|
||||
populateArticle();
|
||||
} else if (requestCode == WikivoyageArticleNavigationFragment.OPEN_ARTICLE_REQUEST_CODE) {
|
||||
String tripId = data.getStringExtra(WikivoyageArticleNavigationFragment.ROUTE_ID_KEY);
|
||||
TravelArticleIdentifier articleId = data.getParcelableExtra(WikivoyageArticleNavigationFragment.ARTICLE_ID_KEY);
|
||||
String selectedLang = data.getStringExtra(WikivoyageArticleNavigationFragment.SELECTED_LANG_KEY);
|
||||
if (!Algorithms.isEmpty(tripId) && !TextUtils.isEmpty(selectedLang)) {
|
||||
this.routeId = tripId;
|
||||
if (articleId != null && !TextUtils.isEmpty(selectedLang)) {
|
||||
this.articleId = articleId;
|
||||
this.selectedLang = selectedLang;
|
||||
populateArticle();
|
||||
}
|
||||
|
@ -286,21 +289,21 @@ public class WikivoyageArticleDialogFragment extends WikiArticleBaseDialogFragme
|
|||
|
||||
@Override
|
||||
protected void populateArticle() {
|
||||
if (Algorithms.isEmpty(routeId) || langs == null) {
|
||||
if (articleId == null || langs == null) {
|
||||
Bundle args = getArguments();
|
||||
if (args != null) {
|
||||
routeId = args.getString(ROUTE_ID_KEY);
|
||||
articleId = args.getParcelable(ARTICLE_ID_KEY);
|
||||
langs = args.getStringArrayList(LANGS_KEY);
|
||||
}
|
||||
}
|
||||
if (Algorithms.isEmpty(routeId) || langs == null || langs.isEmpty()) {
|
||||
if (articleId == null || langs == null || langs.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (selectedLang == null) {
|
||||
selectedLang = langs.get(0);
|
||||
}
|
||||
articleToolbarText.setText("");
|
||||
article = getMyApplication().getTravelHelper().getArticleById(routeId, selectedLang);
|
||||
article = getMyApplication().getTravelHelper().getArticleById(articleId, selectedLang);
|
||||
if (article == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -366,34 +369,34 @@ public class WikivoyageArticleDialogFragment extends WikiArticleBaseDialogFragme
|
|||
}
|
||||
|
||||
public static boolean showInstanceByTitle(@NonNull OsmandApplication app,
|
||||
@NonNull FragmentManager fm,
|
||||
@NonNull String title,
|
||||
@NonNull String lang) {
|
||||
String articleId = app.getTravelHelper().getArticleId(title, lang);
|
||||
@NonNull FragmentManager fm,
|
||||
@NonNull String title,
|
||||
@NonNull String lang) {
|
||||
TravelArticleIdentifier articleId = app.getTravelHelper().getArticleId(title, lang);
|
||||
return showInstance(app, fm, articleId, lang);
|
||||
}
|
||||
|
||||
public static boolean showInstance(@NonNull OsmandApplication app,
|
||||
@NonNull FragmentManager fm,
|
||||
@NonNull String routeId,
|
||||
@NonNull TravelArticleIdentifier articleId,
|
||||
@Nullable String selectedLang) {
|
||||
ArrayList<String> langs = app.getTravelHelper().getArticleLangs(routeId);
|
||||
return showInstance(fm, routeId, langs, selectedLang);
|
||||
ArrayList<String> langs = app.getTravelHelper().getArticleLangs(articleId);
|
||||
return showInstance(fm, articleId, langs, selectedLang);
|
||||
}
|
||||
|
||||
public static boolean showInstance(@NonNull FragmentManager fm,
|
||||
String routeId,
|
||||
@NonNull TravelArticleIdentifier articleId,
|
||||
@NonNull ArrayList<String> langs) {
|
||||
return showInstance(fm, routeId, langs, null);
|
||||
return showInstance(fm, articleId, langs, null);
|
||||
}
|
||||
|
||||
public static boolean showInstance(@NonNull FragmentManager fm,
|
||||
String routeId,
|
||||
@NonNull ArrayList<String> langs,
|
||||
@Nullable String selectedLang) {
|
||||
private static boolean showInstance(@NonNull FragmentManager fm,
|
||||
@NonNull TravelArticleIdentifier articleId,
|
||||
@NonNull ArrayList<String> langs,
|
||||
@Nullable String selectedLang) {
|
||||
try {
|
||||
Bundle args = new Bundle();
|
||||
args.putString(ROUTE_ID_KEY, routeId);
|
||||
args.putParcelable(ARTICLE_ID_KEY, articleId);
|
||||
args.putStringArrayList(LANGS_KEY, langs);
|
||||
if (langs.contains(selectedLang)) {
|
||||
args.putString(SELECTED_LANG_KEY, selectedLang);
|
||||
|
@ -416,7 +419,7 @@ public class WikivoyageArticleDialogFragment extends WikiArticleBaseDialogFragme
|
|||
return;
|
||||
}
|
||||
WikivoyageArticleNavigationFragment.showInstance(fm,
|
||||
WikivoyageArticleDialogFragment.this, routeId, selectedLang);
|
||||
WikivoyageArticleDialogFragment.this, articleId, selectedLang);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import net.osmand.plus.base.MenuBottomSheetDialogFragment;
|
|||
import net.osmand.plus.base.bottomsheetmenu.SimpleBottomSheetItem;
|
||||
import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem;
|
||||
import net.osmand.plus.wikivoyage.data.TravelArticle;
|
||||
import net.osmand.plus.wikivoyage.data.TravelArticle.TravelArticleIdentifier;
|
||||
import net.osmand.plus.wikivoyage.data.WikivoyageSearchResult;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
|
@ -38,14 +39,14 @@ public class WikivoyageArticleNavigationFragment extends MenuBottomSheetDialogFr
|
|||
|
||||
public static final String TAG = WikivoyageArticleNavigationFragment.class.getSimpleName();
|
||||
|
||||
public static final String ROUTE_ID_KEY = "route_id_key";
|
||||
public static final String SELECTED_LANG_KEY = "selected_lang_key";
|
||||
public static final String ARTICLE_ID_KEY = "article_id";
|
||||
public static final String SELECTED_LANG_KEY = "selected_lang";
|
||||
|
||||
public static final int OPEN_ARTICLE_REQUEST_CODE = 2;
|
||||
|
||||
private static final long UNDEFINED = -1;
|
||||
|
||||
private String routeId = "";
|
||||
private TravelArticleIdentifier articleId;
|
||||
private String selectedLang;
|
||||
private TravelArticle article;
|
||||
private List<String> parentsList;
|
||||
|
@ -61,26 +62,27 @@ public class WikivoyageArticleNavigationFragment extends MenuBottomSheetDialogFr
|
|||
|
||||
if (savedInstanceState != null) {
|
||||
selectedLang = savedInstanceState.getString(SELECTED_LANG_KEY);
|
||||
routeId = savedInstanceState.getString(ROUTE_ID_KEY);
|
||||
articleId = savedInstanceState.getParcelable(ARTICLE_ID_KEY);
|
||||
} else {
|
||||
Bundle args = getArguments();
|
||||
if (args != null) {
|
||||
selectedLang = args.getString(SELECTED_LANG_KEY);
|
||||
routeId = args.getString(ROUTE_ID_KEY);
|
||||
articleId = args.getParcelable(ARTICLE_ID_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
if (Algorithms.isEmpty(routeId) || TextUtils.isEmpty(selectedLang)) {
|
||||
if (articleId == null || TextUtils.isEmpty(selectedLang)) {
|
||||
return;
|
||||
}
|
||||
|
||||
article = getMyApplication().getTravelHelper().getArticleById(routeId, selectedLang);
|
||||
article = getMyApplication().getTravelHelper().getArticleById(articleId, selectedLang);
|
||||
if (article == null) {
|
||||
return;
|
||||
}
|
||||
parentsList = new ArrayList<>(Arrays.asList(article.getAggregatedPartOf().split(",")));
|
||||
|
||||
Map<WikivoyageSearchResult, List<WikivoyageSearchResult>> navigationMap = getMyApplication().getTravelHelper().getNavigationMap(article);
|
||||
Map<WikivoyageSearchResult, List<WikivoyageSearchResult>> navigationMap
|
||||
= getMyApplication().getTravelHelper().getNavigationMap(article);
|
||||
|
||||
items.add(new TitleItem(getString(R.string.shared_string_navigation)));
|
||||
|
||||
|
@ -102,7 +104,7 @@ public class WikivoyageArticleNavigationFragment extends MenuBottomSheetDialogFr
|
|||
public boolean onChildClick(ExpandableListView parent, View v,
|
||||
int groupPosition, int childPosition, long id) {
|
||||
WikivoyageSearchResult articleItem = listAdapter.getArticleItem(groupPosition, childPosition);
|
||||
sendResults(articleItem.getRouteId());
|
||||
sendResults(articleItem.getArticleId());
|
||||
dismiss();
|
||||
return true;
|
||||
}
|
||||
|
@ -111,10 +113,10 @@ public class WikivoyageArticleNavigationFragment extends MenuBottomSheetDialogFr
|
|||
@Override
|
||||
public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
|
||||
WikivoyageSearchResult articleItem = (WikivoyageSearchResult) listAdapter.getGroup(groupPosition);
|
||||
if (Algorithms.isEmpty(articleItem.getRouteId())) {
|
||||
if (Algorithms.isEmpty(articleItem.getArticleRouteId())) {
|
||||
Toast.makeText(getContext(), R.string.wiki_article_not_found, Toast.LENGTH_LONG).show();
|
||||
} else {
|
||||
sendResults(articleItem.getRouteId());
|
||||
sendResults(articleItem.getArticleId());
|
||||
dismiss();
|
||||
}
|
||||
return true;
|
||||
|
@ -134,7 +136,7 @@ public class WikivoyageArticleNavigationFragment extends MenuBottomSheetDialogFr
|
|||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putString(ROUTE_ID_KEY, routeId);
|
||||
outState.putParcelable(ARTICLE_ID_KEY, articleId);
|
||||
outState.putString(SELECTED_LANG_KEY, selectedLang);
|
||||
}
|
||||
|
||||
|
@ -148,17 +150,17 @@ public class WikivoyageArticleNavigationFragment extends MenuBottomSheetDialogFr
|
|||
return nightMode ? R.color.wikivoyage_bottom_bar_bg_dark : R.color.list_background_color_light;
|
||||
}
|
||||
|
||||
private void sendResults(String routeId) {
|
||||
WikivoyageArticleDialogFragment.showInstance(getMyApplication(), getFragmentManager(), routeId, selectedLang);
|
||||
private void sendResults(TravelArticleIdentifier articleId) {
|
||||
WikivoyageArticleDialogFragment.showInstance(getMyApplication(), getFragmentManager(), articleId, selectedLang);
|
||||
}
|
||||
|
||||
public static boolean showInstance(@NonNull FragmentManager fm,
|
||||
@Nullable Fragment targetFragment,
|
||||
String routeId,
|
||||
@NonNull TravelArticleIdentifier articleId,
|
||||
@NonNull String selectedLang) {
|
||||
try {
|
||||
Bundle args = new Bundle();
|
||||
args.putString(ROUTE_ID_KEY, routeId);
|
||||
args.putParcelable(ARTICLE_ID_KEY, articleId);
|
||||
args.putString(SELECTED_LANG_KEY, selectedLang);
|
||||
WikivoyageArticleNavigationFragment fragment = new WikivoyageArticleNavigationFragment();
|
||||
if (targetFragment != null) {
|
||||
|
@ -204,7 +206,7 @@ public class WikivoyageArticleNavigationFragment extends MenuBottomSheetDialogFr
|
|||
|
||||
@Override
|
||||
public Object getChild(int groupPosition, int childPosititon) {
|
||||
return getArticleItem(groupPosition, childPosititon).getArticleTitles().get(0);
|
||||
return getArticleItem(groupPosition, childPosititon).getArticleTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -236,8 +238,8 @@ public class WikivoyageArticleNavigationFragment extends MenuBottomSheetDialogFr
|
|||
public View getChildView(int groupPosition, final int childPosition,
|
||||
boolean isLastChild, View convertView, ViewGroup parent) {
|
||||
WikivoyageSearchResult articleItem = getArticleItem(groupPosition, childPosition);
|
||||
String childTitle = articleItem.getArticleTitles().get(0);
|
||||
boolean selected = Algorithms.stringsEqual(routeId, articleItem.getRouteId()) || parentsList.contains(childTitle);
|
||||
String childTitle = articleItem.getArticleTitle();
|
||||
boolean selected = articleItem.getArticleId().equals(articleId) || parentsList.contains(childTitle);
|
||||
|
||||
if (convertView == null) {
|
||||
convertView = LayoutInflater.from(context)
|
||||
|
@ -263,7 +265,7 @@ public class WikivoyageArticleNavigationFragment extends MenuBottomSheetDialogFr
|
|||
@Override
|
||||
public View getGroupView(final int groupPosition, final boolean isExpanded,
|
||||
View convertView, ViewGroup parent) {
|
||||
String groupTitle = ((WikivoyageSearchResult) getGroup(groupPosition)).getArticleTitles().get(0);
|
||||
String groupTitle = ((WikivoyageSearchResult) getGroup(groupPosition)).getArticleTitle();
|
||||
boolean selected = parentsList.contains(groupTitle) || article.getTitle().equals(groupTitle);
|
||||
if (convertView == null) {
|
||||
convertView = LayoutInflater.from(context)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package net.osmand.plus.wikivoyage.data;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
@ -7,13 +9,21 @@ import androidx.annotation.Nullable;
|
|||
import androidx.annotation.Size;
|
||||
|
||||
import net.osmand.GPXUtilities.GPXFile;
|
||||
import net.osmand.Location;
|
||||
import net.osmand.aidl.search.SearchResult;
|
||||
import net.osmand.data.LatLon;
|
||||
import net.osmand.util.Algorithms;
|
||||
import net.osmand.util.MapUtils;
|
||||
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
public class TravelArticle {
|
||||
|
||||
|
@ -21,19 +31,29 @@ public class TravelArticle {
|
|||
private static final String THUMB_PREFIX = "320px-";
|
||||
private static final String REGULAR_PREFIX = "1280px-";//1280, 1024, 800
|
||||
|
||||
File file;
|
||||
String title;
|
||||
String content;
|
||||
String isPartOf;
|
||||
double lat;
|
||||
double lon;
|
||||
double lat = Double.NaN;
|
||||
double lon = Double.NaN;
|
||||
String imageTitle;
|
||||
GPXFile gpxFile;
|
||||
String routeId;
|
||||
String routeSource;
|
||||
long originalId;
|
||||
String lang;
|
||||
String contentsJson;
|
||||
String aggregatedPartOf;
|
||||
|
||||
@NonNull
|
||||
public TravelArticleIdentifier generateIdentifier() {
|
||||
return new TravelArticleIdentifier(this);
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
|
@ -67,6 +87,10 @@ public class TravelArticle {
|
|||
return routeId;
|
||||
}
|
||||
|
||||
public String getRouteSource() {
|
||||
return routeSource;
|
||||
}
|
||||
|
||||
public long getOriginalId() {
|
||||
return originalId;
|
||||
}
|
||||
|
@ -126,4 +150,92 @@ public class TravelArticle {
|
|||
String md5 = new String(Hex.encodeHex(DigestUtils.md5(s)));
|
||||
return new String[]{md5.substring(0, 1), md5.substring(0, 2)};
|
||||
}
|
||||
|
||||
public static class TravelArticleIdentifier implements Parcelable {
|
||||
@Nullable File file;
|
||||
double lat;
|
||||
double lon;
|
||||
@Nullable String title;
|
||||
@Nullable String routeId;
|
||||
@Nullable String routeSource;
|
||||
|
||||
public static final Creator<TravelArticleIdentifier> CREATOR = new Creator<TravelArticleIdentifier>() {
|
||||
@Override
|
||||
public TravelArticleIdentifier createFromParcel(Parcel in) {
|
||||
return new TravelArticleIdentifier(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TravelArticleIdentifier[] newArray(int size) {
|
||||
return new TravelArticleIdentifier[size];
|
||||
}
|
||||
};
|
||||
|
||||
private TravelArticleIdentifier(@NonNull Parcel in) {
|
||||
readFromParcel(in);
|
||||
}
|
||||
|
||||
private TravelArticleIdentifier(@NonNull TravelArticle article) {
|
||||
file = article.file;
|
||||
lat = article.lat;
|
||||
lon = article.lon;
|
||||
title = article.title;
|
||||
routeId = article.routeId;
|
||||
routeSource = article.routeSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeDouble(lat);
|
||||
out.writeDouble(lon);
|
||||
out.writeString(title);
|
||||
out.writeString(routeId);
|
||||
out.writeString(routeSource);
|
||||
out.writeString(file != null ? file.getAbsolutePath() : null);
|
||||
}
|
||||
|
||||
private void readFromParcel(Parcel in) {
|
||||
lat = in.readDouble();
|
||||
lon = in.readDouble();
|
||||
title = in.readString();
|
||||
routeId = in.readString();
|
||||
routeSource = in.readString();
|
||||
String filePath = in.readString();
|
||||
if (!Algorithms.isEmpty(filePath)) {
|
||||
file = new File(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
TravelArticleIdentifier that = (TravelArticleIdentifier) o;
|
||||
return areLatLonEqual(that.lat, that.lon, lat, lon) &&
|
||||
Algorithms.objectEquals(file, that.file) &&
|
||||
Algorithms.stringsEqual(title, that.title) &&
|
||||
Algorithms.stringsEqual(routeId, that.routeId) &&
|
||||
Algorithms.stringsEqual(routeSource, that.routeSource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Algorithms.hash(file, lat, lon, title, routeId, routeSource);
|
||||
}
|
||||
|
||||
private static boolean areLatLonEqual(double lat1, double lon1, double lat2, double lon2) {
|
||||
boolean latEqual = (Double.isNaN(lat1) && Double.isNaN(lat2)) || Math.abs(lat1 - lat2) < 0.00001;
|
||||
boolean lonEqual = (Double.isNaN(lon1) && Double.isNaN(lon2)) || Math.abs(lon1 - lon2) < 0.00001;
|
||||
return latEqual && lonEqual;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,10 +16,12 @@ import net.osmand.OsmAndCollator;
|
|||
import net.osmand.PlatformUtil;
|
||||
import net.osmand.data.Amenity;
|
||||
import net.osmand.data.LatLon;
|
||||
import net.osmand.data.QuadRect;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.api.SQLiteAPI.SQLiteConnection;
|
||||
import net.osmand.plus.api.SQLiteAPI.SQLiteCursor;
|
||||
import net.osmand.plus.wikivoyage.data.TravelArticle.TravelArticleIdentifier;
|
||||
import net.osmand.util.Algorithms;
|
||||
import net.osmand.util.MapUtils;
|
||||
|
||||
|
@ -245,12 +247,15 @@ public class TravelDbHelper implements TravelHelper {
|
|||
if (cursor != null) {
|
||||
if (cursor.moveToFirst()) {
|
||||
do {
|
||||
WikivoyageSearchResult rs = new WikivoyageSearchResult();
|
||||
rs.routeId = cursor.getLong(0) + "";
|
||||
rs.articleTitles.add(cursor.getString(1));
|
||||
rs.langs.add(cursor.getString(2));
|
||||
rs.isPartOf.add(cursor.getString(3));
|
||||
rs.imageTitle = cursor.getString(4);
|
||||
String routeId = cursor.getLong(0) + "";
|
||||
String articleTitle = cursor.getString(1);
|
||||
String lang = cursor.getString(2);
|
||||
String isPartOf = cursor.getString(3);
|
||||
String imageTitle = cursor.getString(4);
|
||||
List<String> langs = new ArrayList<>();
|
||||
langs.add(lang);
|
||||
WikivoyageSearchResult rs = new WikivoyageSearchResult(routeId, articleTitle,
|
||||
isPartOf, imageTitle, langs);
|
||||
res.add(rs);
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
|
@ -386,12 +391,12 @@ public class TravelDbHelper implements TravelHelper {
|
|||
Collections.sort(list, new Comparator<WikivoyageSearchResult>() {
|
||||
@Override
|
||||
public int compare(WikivoyageSearchResult o1, WikivoyageSearchResult o2) {
|
||||
boolean c1 = CollatorStringMatcher.cmatches(collator, searchQuery, o1.articleTitles.get(0),
|
||||
boolean c1 = CollatorStringMatcher.cmatches(collator, searchQuery, o1.getArticleTitle(),
|
||||
StringMatcherMode.CHECK_ONLY_STARTS_WITH);
|
||||
boolean c2 = CollatorStringMatcher.cmatches(collator, searchQuery, o2.articleTitles.get(0),
|
||||
boolean c2 = CollatorStringMatcher.cmatches(collator, searchQuery, o2.getArticleTitle(),
|
||||
StringMatcherMode.CHECK_ONLY_STARTS_WITH);
|
||||
if (c1 == c2) {
|
||||
return collator.compare(o1.articleTitles.get(0), o2.articleTitles.get(0));
|
||||
return collator.compare(o1.getArticleTitle(), o2.getArticleTitle());
|
||||
} else if (c1) {
|
||||
return -1;
|
||||
} else if (c2) {
|
||||
|
@ -422,28 +427,27 @@ public class TravelDbHelper implements TravelHelper {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private Collection<WikivoyageSearchResult> groupSearchResultsByRouteId(List<WikivoyageSearchResult> res) {
|
||||
String baseLng = application.getLanguage();
|
||||
Map<String, WikivoyageSearchResult> wikivoyage = new HashMap<>();
|
||||
for (WikivoyageSearchResult rs : res) {
|
||||
WikivoyageSearchResult prev = wikivoyage.get(rs.routeId);
|
||||
WikivoyageSearchResult prev = wikivoyage.get(rs.getArticleRouteId());
|
||||
if (prev != null) {
|
||||
int insInd = prev.langs.size();
|
||||
boolean matchLang = false;
|
||||
if (rs.langs.get(0).equals(baseLng)) {
|
||||
insInd = 0;
|
||||
matchLang = true;
|
||||
} else if (rs.langs.get(0).equals("en")) {
|
||||
if (!prev.langs.get(0).equals(baseLng)) {
|
||||
insInd = 0;
|
||||
} else {
|
||||
insInd = 1;
|
||||
matchLang = true;
|
||||
}
|
||||
}
|
||||
prev.articleTitles.add(insInd, rs.articleTitles.get(0));
|
||||
prev.langs.add(insInd, rs.langs.get(0));
|
||||
prev.isPartOf.add(insInd, rs.isPartOf.get(0));
|
||||
if (matchLang) {
|
||||
prev.articleId.title = rs.getArticleTitle();
|
||||
prev.isPartOf = rs.getIsPartOf();
|
||||
}
|
||||
prev.langs.add(matchLang ? 0 : 1, rs.langs.get(0));
|
||||
} else {
|
||||
wikivoyage.put(rs.routeId, rs);
|
||||
wikivoyage.put(rs.getArticleRouteId(), rs);
|
||||
}
|
||||
}
|
||||
return wikivoyage.values();
|
||||
|
@ -451,12 +455,11 @@ public class TravelDbHelper implements TravelHelper {
|
|||
|
||||
@NonNull
|
||||
@Override
|
||||
public LinkedHashMap<WikivoyageSearchResult, List<WikivoyageSearchResult>> getNavigationMap(
|
||||
@NonNull final TravelArticle article) {
|
||||
public Map<WikivoyageSearchResult, List<WikivoyageSearchResult>> getNavigationMap(@NonNull final TravelArticle article) {
|
||||
String lang = article.getLang();
|
||||
String title = article.getTitle();
|
||||
if (TextUtils.isEmpty(lang) || TextUtils.isEmpty(title)) {
|
||||
return new LinkedHashMap<>();
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
String[] parts = null;
|
||||
if (!TextUtils.isEmpty(article.getAggregatedPartOf())) {
|
||||
|
@ -498,20 +501,20 @@ public class TravelDbHelper implements TravelHelper {
|
|||
SQLiteCursor cursor = conn.rawQuery(query.toString(), params.toArray(new String[0]));
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
do {
|
||||
WikivoyageSearchResult rs = new WikivoyageSearchResult();
|
||||
rs.routeId = cursor.getLong(0) + "";
|
||||
rs.articleTitles.add(cursor.getString(1));
|
||||
rs.langs.add(cursor.getString(2));
|
||||
rs.isPartOf.add(cursor.getString(3));
|
||||
List<WikivoyageSearchResult> l = navMap.get(rs.isPartOf.get(0));
|
||||
String routeId = cursor.getLong(0) + "";
|
||||
String articleTitle = cursor.getString(1);
|
||||
String articleLang = cursor.getString(2);
|
||||
String isPartOf = cursor.getString(3);
|
||||
WikivoyageSearchResult rs = new WikivoyageSearchResult(routeId, articleTitle,
|
||||
isPartOf, null, Collections.singletonList(articleLang));
|
||||
List<WikivoyageSearchResult> l = navMap.get(rs.isPartOf);
|
||||
if (l == null) {
|
||||
l = new ArrayList<>();
|
||||
navMap.put(rs.isPartOf.get(0), l);
|
||||
navMap.put(rs.isPartOf, l);
|
||||
}
|
||||
l.add(rs);
|
||||
String key = rs.getArticleTitles().get(0);
|
||||
if (headers != null && headers.contains(key)) {
|
||||
headerObjs.put(key, rs);
|
||||
if (headers != null && headers.contains(articleTitle)) {
|
||||
headerObjs.put(articleTitle, rs);
|
||||
}
|
||||
} while (cursor.moveToNext());
|
||||
}
|
||||
|
@ -527,12 +530,10 @@ public class TravelDbHelper implements TravelHelper {
|
|||
Collections.sort(results, new Comparator<WikivoyageSearchResult>() {
|
||||
@Override
|
||||
public int compare(WikivoyageSearchResult o1, WikivoyageSearchResult o2) {
|
||||
return collator.compare(o1.articleTitles.get(0), o2.articleTitles.get(0));
|
||||
return collator.compare(o1.getArticleTitle(), o2.getArticleTitle());
|
||||
}
|
||||
});
|
||||
WikivoyageSearchResult emptyResult = new WikivoyageSearchResult();
|
||||
emptyResult.articleTitles.add(header);
|
||||
emptyResult.routeId = "";
|
||||
WikivoyageSearchResult emptyResult = new WikivoyageSearchResult("", header, null, null, null);
|
||||
searchResult = searchResult != null ? searchResult : emptyResult;
|
||||
res.put(searchResult, results);
|
||||
}
|
||||
|
@ -542,9 +543,10 @@ public class TravelDbHelper implements TravelHelper {
|
|||
|
||||
@Override
|
||||
@Nullable
|
||||
public TravelArticle getArticleById(@NonNull String routeId, @NonNull String lang) {
|
||||
public TravelArticle getArticleById(@NonNull TravelArticleIdentifier articleId, @NonNull String lang) {
|
||||
TravelArticle res = null;
|
||||
SQLiteConnection conn = openConnection();
|
||||
String routeId = articleId.routeId;
|
||||
if (conn != null && !Algorithms.isEmpty(routeId)) {
|
||||
SQLiteCursor cursor = conn.rawQuery(ARTICLES_TABLE_SELECT + " WHERE " + ARTICLES_COL_TRIP_ID + " = ? AND "
|
||||
+ ARTICLES_COL_LANG + " = ?", new String[] { routeId, lang });
|
||||
|
@ -558,9 +560,21 @@ public class TravelDbHelper implements TravelHelper {
|
|||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public TravelArticle getArticleByTitle(@NonNull String title, @NonNull String lang) {
|
||||
@Override
|
||||
public TravelArticle getArticleByTitle(@NonNull final String title, @NonNull final String lang) {
|
||||
return getArticleByTitle(title, new QuadRect(), lang);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TravelArticle getArticleByTitle(@NonNull final String title, @NonNull LatLon latLon, @NonNull final String lang) {
|
||||
return getArticleByTitle(title, new QuadRect(), lang);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TravelArticle getArticleByTitle(@NonNull final String title, @NonNull QuadRect rect, @NonNull final String lang) {
|
||||
TravelArticle res = null;
|
||||
SQLiteConnection conn = openConnection();
|
||||
if (conn != null) {
|
||||
|
@ -576,33 +590,32 @@ public class TravelDbHelper implements TravelHelper {
|
|||
return res;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Nullable
|
||||
@Override
|
||||
public String getArticleId(@NonNull String title, @NonNull String lang) {
|
||||
String res = "";
|
||||
public TravelArticleIdentifier getArticleId(@NonNull String title, @NonNull String lang) {
|
||||
TravelArticle article = null;
|
||||
SQLiteConnection conn = openConnection();
|
||||
if (conn != null) {
|
||||
SQLiteCursor cursor = conn.rawQuery("SELECT " + ARTICLES_COL_TRIP_ID + " FROM "
|
||||
+ ARTICLES_TABLE_NAME + " WHERE " + ARTICLES_COL_TITLE + " = ? AND "
|
||||
SQLiteCursor cursor = conn.rawQuery(ARTICLES_TABLE_SELECT + " WHERE " + ARTICLES_COL_TITLE + " = ? AND "
|
||||
+ ARTICLES_COL_LANG + " = ?", new String[]{title, lang});
|
||||
if (cursor != null) {
|
||||
if (cursor.moveToFirst()) {
|
||||
res = cursor.getLong(0) + "";
|
||||
article = readArticle(cursor);
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
return res;
|
||||
return article != null ? article.generateIdentifier() : null;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ArrayList<String> getArticleLangs(@NonNull String routeId) {
|
||||
public ArrayList<String> getArticleLangs(@NonNull TravelArticleIdentifier articleId) {
|
||||
ArrayList<String> res = new ArrayList<>();
|
||||
SQLiteConnection conn = openConnection();
|
||||
if (conn != null) {
|
||||
SQLiteCursor cursor = conn.rawQuery("SELECT " + ARTICLES_COL_LANG + " FROM " + ARTICLES_TABLE_NAME
|
||||
+ " WHERE " + ARTICLES_COL_TRIP_ID + " = ?", new String[]{routeId});
|
||||
+ " WHERE " + ARTICLES_COL_TRIP_ID + " = ?", new String[]{articleId.routeId});
|
||||
if (cursor != null) {
|
||||
if (cursor.moveToFirst()) {
|
||||
String baseLang = application.getLanguage();
|
||||
|
|
|
@ -3,6 +3,10 @@ package net.osmand.plus.wikivoyage.data;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.osmand.data.LatLon;
|
||||
import net.osmand.data.QuadRect;
|
||||
import net.osmand.plus.wikivoyage.data.TravelArticle.TravelArticleIdentifier;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -28,16 +32,22 @@ public interface TravelHelper {
|
|||
Map<WikivoyageSearchResult, List<WikivoyageSearchResult>> getNavigationMap(@NonNull final TravelArticle article);
|
||||
|
||||
@Nullable
|
||||
TravelArticle getArticleById(@NonNull String routeId, @NonNull String lang);
|
||||
TravelArticle getArticleById(@NonNull TravelArticleIdentifier articleId, @NonNull String lang);
|
||||
|
||||
@Nullable
|
||||
TravelArticle getArticleByTitle(@NonNull String title, @NonNull String lang);
|
||||
public TravelArticle getArticleByTitle(@NonNull final String title, @NonNull final String lang);
|
||||
|
||||
@Nullable
|
||||
public TravelArticle getArticleByTitle(@NonNull final String title, @NonNull LatLon latLon, @NonNull final String lang);
|
||||
|
||||
@Nullable
|
||||
TravelArticle getArticleByTitle(@NonNull String title, @NonNull QuadRect rect, @NonNull String lang);
|
||||
|
||||
@Nullable
|
||||
TravelArticleIdentifier getArticleId(@NonNull String title, @NonNull String lang);
|
||||
|
||||
@NonNull
|
||||
String getArticleId(@NonNull String title, @NonNull String lang);
|
||||
|
||||
@NonNull
|
||||
ArrayList<String> getArticleLangs(@NonNull String routeId);
|
||||
ArrayList<String> getArticleLangs(@NonNull TravelArticleIdentifier articleId);
|
||||
|
||||
@NonNull
|
||||
String getGPXName(@NonNull final TravelArticle article);
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
package net.osmand.plus.wikivoyage.data;
|
||||
|
||||
import android.text.TextUtils;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.osmand.Collator;
|
||||
import net.osmand.CollatorStringMatcher;
|
||||
import net.osmand.GPXUtilities;
|
||||
import net.osmand.GPXUtilities.GPXFile;
|
||||
import net.osmand.IndexConstants;
|
||||
|
@ -13,10 +14,13 @@ import net.osmand.PlatformUtil;
|
|||
import net.osmand.ResultMatcher;
|
||||
import net.osmand.binary.BinaryMapIndexReader;
|
||||
import net.osmand.binary.BinaryMapIndexReader.SearchPoiTypeFilter;
|
||||
import net.osmand.binary.BinaryMapIndexReader.SearchRequest;
|
||||
import net.osmand.data.Amenity;
|
||||
import net.osmand.data.LatLon;
|
||||
import net.osmand.data.QuadRect;
|
||||
import net.osmand.osm.PoiCategory;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.wikivoyage.data.TravelArticle.TravelArticleIdentifier;
|
||||
import net.osmand.util.Algorithms;
|
||||
import net.osmand.util.MapUtils;
|
||||
|
||||
|
@ -25,33 +29,39 @@ import org.apache.commons.logging.Log;
|
|||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static net.osmand.CollatorStringMatcher.StringMatcherMode.CHECK_EQUALS_FROM_SPACE;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class TravelObfHelper implements TravelHelper {
|
||||
|
||||
private static final Log LOG = PlatformUtil.getLog(TravelObfHelper.class);
|
||||
public static final String ROUTE_ARTICLE = "route_article";
|
||||
public static final int SEARCH_RADIUS = 100000;
|
||||
public static final int POPULAR_ARTICLES_SEARCH_RADIUS = 100000;
|
||||
public static final int ARTICLE_SEARCH_RADIUS = 50000;
|
||||
public static final int MAX_POPULAR_ARTICLES_COUNT = 100;
|
||||
|
||||
private final OsmandApplication app;
|
||||
private final Collator collator;
|
||||
|
||||
private List<TravelArticle> popularArticles = new ArrayList<>();
|
||||
private final Map<String, TravelArticle> cachedArticles;
|
||||
private Map<TravelArticleIdentifier, Map<String, TravelArticle>> cachedArticles = new ConcurrentHashMap<>();
|
||||
private final TravelLocalDataHelper localDataHelper;
|
||||
|
||||
public TravelObfHelper(OsmandApplication app) {
|
||||
this.app = app;
|
||||
collator = OsmAndCollator.primaryCollator();
|
||||
localDataHelper = new TravelLocalDataHelper(app);
|
||||
cachedArticles = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -71,22 +81,23 @@ public class TravelObfHelper implements TravelHelper {
|
|||
|
||||
@NonNull
|
||||
public List<TravelArticle> loadPopularArticles() {
|
||||
String language = app.getLanguage();
|
||||
String lang = app.getLanguage();
|
||||
List<TravelArticle> popularArticles = new ArrayList<>();
|
||||
for (BinaryMapIndexReader travelBookReader : getTravelBookReaders()) {
|
||||
for (BinaryMapIndexReader reader : getReaders()) {
|
||||
try {
|
||||
final LatLon location = app.getMapViewTrackingUtilities().getMapLocation();
|
||||
BinaryMapIndexReader.SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest(
|
||||
location, SEARCH_RADIUS, -1, getSearchRouteArticleFilter(), null);
|
||||
List<Amenity> amenities = travelBookReader.searchPoi(req);
|
||||
SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest(
|
||||
location, POPULAR_ARTICLES_SEARCH_RADIUS, -1, getSearchRouteArticleFilter(), null);
|
||||
List<Amenity> amenities = reader.searchPoi(req);
|
||||
if (amenities.size() > 0) {
|
||||
for (Amenity a : amenities) {
|
||||
if (!Algorithms.isEmpty(a.getName(language))) {
|
||||
TravelArticle article = readArticle(a, language);
|
||||
popularArticles.add(article);
|
||||
cachedArticles.put(article.routeId, article);
|
||||
if (popularArticles.size() >= 100) {
|
||||
break;
|
||||
for (Amenity amenity : amenities) {
|
||||
if (!Algorithms.isEmpty(amenity.getName(lang))) {
|
||||
TravelArticle article = cacheTravelArticles(reader.getFile(), amenity, lang);
|
||||
if (article != null) {
|
||||
popularArticles.add(article);
|
||||
if (popularArticles.size() >= MAX_POPULAR_ARTICLES_COUNT) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -102,13 +113,25 @@ public class TravelObfHelper implements TravelHelper {
|
|||
});
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error(e.getMessage());
|
||||
LOG.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
this.popularArticles = popularArticles;
|
||||
return popularArticles;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private TravelArticle cacheTravelArticles(File file, Amenity amenity, String lang) {
|
||||
TravelArticle article = null;
|
||||
Map<String, TravelArticle> articles = readArticles(file, amenity);
|
||||
if (!Algorithms.isEmpty(articles)) {
|
||||
TravelArticleIdentifier newArticleId = articles.values().iterator().next().generateIdentifier();
|
||||
cachedArticles.put(newArticleId, articles);
|
||||
article = getCachedArticle(newArticleId, lang);
|
||||
}
|
||||
return article;
|
||||
}
|
||||
|
||||
SearchPoiTypeFilter getSearchRouteArticleFilter() {
|
||||
return new SearchPoiTypeFilter() {
|
||||
@Override
|
||||
|
@ -123,23 +146,29 @@ public class TravelObfHelper implements TravelHelper {
|
|||
};
|
||||
}
|
||||
|
||||
private TravelArticle readArticle(@NonNull Amenity amenity, @Nullable String lang) {
|
||||
TravelArticle res = new TravelArticle();
|
||||
String title = Algorithms.isEmpty(amenity.getName(lang)) ? amenity.getName() : amenity.getName(lang);
|
||||
if (Algorithms.isEmpty(title)) {
|
||||
Map<String, String> namesMap = amenity.getNamesMap(true);
|
||||
if (!namesMap.isEmpty()) {
|
||||
lang = namesMap.keySet().iterator().next();
|
||||
title = amenity.getName(lang);
|
||||
}
|
||||
@NonNull
|
||||
private Map<String, TravelArticle> readArticles(@NonNull File file, @NonNull Amenity amenity) {
|
||||
Map<String, TravelArticle> articles = new HashMap<>();
|
||||
Set<String> langs = getLanguages(amenity);
|
||||
for (String lang : langs) {
|
||||
articles.put(lang, readArticle(file, amenity, lang));
|
||||
}
|
||||
res.title = title;
|
||||
return articles;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private TravelArticle readArticle(@NonNull File file, @NonNull Amenity amenity, @Nullable String lang) {
|
||||
TravelArticle res = new TravelArticle();
|
||||
res.file = file;
|
||||
String title = amenity.getName(lang);
|
||||
res.title = Algorithms.isEmpty(title) ? amenity.getName() : title;
|
||||
res.content = amenity.getDescription(lang);
|
||||
res.isPartOf = emptyIfNull(amenity.getTagContent(Amenity.IS_PART, lang));
|
||||
res.lat = amenity.getLocation().getLatitude();
|
||||
res.lon = amenity.getLocation().getLongitude();
|
||||
res.imageTitle = emptyIfNull(amenity.getTagContent(Amenity.IMAGE_TITLE, lang));
|
||||
res.routeId = getRouteId(amenity);
|
||||
res.imageTitle = emptyIfNull(amenity.getTagContent(Amenity.IMAGE_TITLE, null));
|
||||
res.routeId = emptyIfNull(amenity.getTagContent(Amenity.ROUTE_ID, null));
|
||||
res.routeSource = emptyIfNull(amenity.getTagContent(Amenity.ROUTE_SOURCE, null));
|
||||
res.originalId = 0;
|
||||
res.lang = lang;
|
||||
res.contentsJson = emptyIfNull(amenity.getTagContent(Amenity.CONTENT_JSON, lang));
|
||||
|
@ -151,85 +180,72 @@ public class TravelObfHelper implements TravelHelper {
|
|||
return text == null ? "" : text;
|
||||
}
|
||||
|
||||
private String getRouteId(Amenity amenity) {
|
||||
return amenity.getTagContent(Amenity.ROUTE_ID, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAnyTravelBookPresent() {
|
||||
return !Algorithms.isEmpty(getTravelBookReaders());
|
||||
return !Algorithms.isEmpty(getReaders());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public List<WikivoyageSearchResult> search(@NonNull String searchQuery) {
|
||||
List<WikivoyageSearchResult> res = new ArrayList<>();
|
||||
List<Amenity> searchObjects = null;
|
||||
for (BinaryMapIndexReader reader : app.getResourceManager().getTravelRepositories()) {
|
||||
Map<File, List<Amenity>> amenityMap = new HashMap<>();
|
||||
for (BinaryMapIndexReader reader : getReaders()) {
|
||||
try {
|
||||
BinaryMapIndexReader.SearchRequest<Amenity> searchRequest = BinaryMapIndexReader.
|
||||
buildSearchPoiRequest(0, 0, searchQuery,
|
||||
SearchRequest<Amenity> searchRequest = BinaryMapIndexReader.buildSearchPoiRequest(0, 0, searchQuery,
|
||||
0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE, getSearchRouteArticleFilter(), null, null);
|
||||
|
||||
searchObjects = reader.searchPoiByName(searchRequest);
|
||||
List<Amenity> amenities = reader.searchPoiByName(searchRequest);
|
||||
if (!Algorithms.isEmpty(amenities)) {
|
||||
amenityMap.put(reader.getFile(), amenities);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.error(e);
|
||||
LOG.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
if (!Algorithms.isEmpty(searchObjects)) {
|
||||
String baseLng = app.getLanguage();
|
||||
for (Amenity obj : searchObjects) {
|
||||
WikivoyageSearchResult r = new WikivoyageSearchResult();
|
||||
TravelArticle article = readArticle(obj, baseLng);
|
||||
r.articleTitles = new ArrayList<>(Collections.singletonList(article.title));
|
||||
r.imageTitle = article.imageTitle;
|
||||
r.routeId = article.routeId;
|
||||
r.isPartOf = new ArrayList<>(Collections.singletonList(article.isPartOf));
|
||||
r.langs = new ArrayList<>(Collections.singletonList(baseLng));
|
||||
res.add(r);
|
||||
cachedArticles.put(article.routeId, article);
|
||||
if (!Algorithms.isEmpty(amenityMap)) {
|
||||
String appLang = app.getLanguage();
|
||||
for (Entry<File, List<Amenity>> entry : amenityMap.entrySet()) {
|
||||
File file = entry.getKey();
|
||||
for (Amenity amenity : entry.getValue()) {
|
||||
Set<String> nameLangs = getLanguages(amenity);
|
||||
if (nameLangs.contains(appLang)) {
|
||||
TravelArticle article = readArticle(file, amenity, appLang);
|
||||
WikivoyageSearchResult r = new WikivoyageSearchResult(article, new ArrayList<>(nameLangs));
|
||||
res.add(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
res = new ArrayList<>(groupSearchResultsByRouteId(res));
|
||||
sortSearchResults(res);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private void sortSearchResults(@NonNull List<WikivoyageSearchResult> list) {
|
||||
Collections.sort(list, new Comparator<WikivoyageSearchResult>() {
|
||||
|
||||
@Override
|
||||
public int compare(WikivoyageSearchResult res1, WikivoyageSearchResult res2) {
|
||||
return collator.compare(res1.articleTitles.get(0), res2.articleTitles.get(0));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Collection<WikivoyageSearchResult> groupSearchResultsByRouteId(@NonNull List<WikivoyageSearchResult> res) {
|
||||
String baseLng = app.getLanguage();
|
||||
Map<String, WikivoyageSearchResult> wikivoyage = new HashMap<>();
|
||||
for (WikivoyageSearchResult rs : res) {
|
||||
WikivoyageSearchResult prev = wikivoyage.get(rs.routeId);
|
||||
if (prev != null) {
|
||||
int insInd = prev.langs.size();
|
||||
if (rs.langs.get(0).equals(baseLng)) {
|
||||
insInd = 0;
|
||||
} else if (rs.langs.get(0).equals("en")) {
|
||||
if (!prev.langs.get(0).equals(baseLng)) {
|
||||
insInd = 0;
|
||||
} else {
|
||||
insInd = 1;
|
||||
}
|
||||
private Set<String> getLanguages(@NonNull Amenity amenity) {
|
||||
Set<String> langs = new HashSet<>();
|
||||
String descrStart = Amenity.DESCRIPTION + ":";
|
||||
String partStart = Amenity.IS_PART + ":";
|
||||
for (String infoTag : amenity.getAdditionalInfoKeys()) {
|
||||
if (infoTag.startsWith(descrStart)) {
|
||||
if (infoTag.length() > descrStart.length()) {
|
||||
langs.add(infoTag.substring(descrStart.length()));
|
||||
}
|
||||
} else if (infoTag.startsWith(partStart)) {
|
||||
if (infoTag.length() > partStart.length()) {
|
||||
langs.add(infoTag.substring(partStart.length()));
|
||||
}
|
||||
prev.articleTitles.add(insInd, rs.articleTitles.get(0));
|
||||
prev.langs.add(insInd, rs.langs.get(0));
|
||||
prev.isPartOf.add(insInd, rs.isPartOf.get(0));
|
||||
} else {
|
||||
wikivoyage.put(rs.routeId, rs);
|
||||
}
|
||||
}
|
||||
return wikivoyage.values();
|
||||
return langs;
|
||||
}
|
||||
|
||||
private void sortSearchResults(@NonNull List<WikivoyageSearchResult> list) {
|
||||
Collections.sort(list, new Comparator<WikivoyageSearchResult>() {
|
||||
@Override
|
||||
public int compare(WikivoyageSearchResult res1, WikivoyageSearchResult res2) {
|
||||
return collator.compare(res1.articleId.title, res2.articleId.title);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
@ -241,71 +257,153 @@ public class TravelObfHelper implements TravelHelper {
|
|||
@NonNull
|
||||
@Override
|
||||
public Map<WikivoyageSearchResult, List<WikivoyageSearchResult>> getNavigationMap(@NonNull final TravelArticle article) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TravelArticle getArticleById(@NonNull String routeId, @NonNull String lang) {
|
||||
TravelArticle article = cachedArticles.get(routeId);
|
||||
if (article != null) {
|
||||
return article;
|
||||
} else {
|
||||
return getArticleByIdFromTravelBooks(routeId, lang);
|
||||
final String lang = article.getLang();
|
||||
final String title = article.getTitle();
|
||||
if (TextUtils.isEmpty(lang) || TextUtils.isEmpty(title)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
|
||||
private TravelArticle getArticleByIdFromTravelBooks(final String routeId, final String lang) {
|
||||
TravelArticle article = null;
|
||||
final List<Amenity> amenities = new ArrayList<>();
|
||||
for (BinaryMapIndexReader travelBookReader : getTravelBookReaders()) {
|
||||
final String[] parts;
|
||||
if (!TextUtils.isEmpty(article.getAggregatedPartOf())) {
|
||||
String[] originalParts = article.getAggregatedPartOf().split(",");
|
||||
if (originalParts.length > 1) {
|
||||
parts = new String[originalParts.length];
|
||||
for (int i = 0; i < originalParts.length; i++) {
|
||||
parts[i] = originalParts[originalParts.length - i - 1];
|
||||
}
|
||||
} else {
|
||||
parts = originalParts;
|
||||
}
|
||||
} else {
|
||||
parts = null;
|
||||
}
|
||||
Map<String, List<WikivoyageSearchResult>> navMap = new HashMap<>();
|
||||
Set<String> headers = new LinkedHashSet<String>();
|
||||
Map<String, WikivoyageSearchResult> headerObjs = new HashMap<>();
|
||||
Map<File, List<Amenity>> amenityMap = new HashMap<>();
|
||||
for (BinaryMapIndexReader reader : getReaders()) {
|
||||
try {
|
||||
BinaryMapIndexReader.SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest(
|
||||
0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE, -1, getSearchRouteArticleFilter(),
|
||||
new ResultMatcher<Amenity>() {
|
||||
boolean done = false;
|
||||
SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest(0,
|
||||
Integer.MAX_VALUE, 0, Integer.MAX_VALUE, -1, getSearchRouteArticleFilter(), new ResultMatcher<Amenity>() {
|
||||
|
||||
@Override
|
||||
public boolean publish(Amenity amenity) {
|
||||
if (getRouteId(amenity).equals(routeId)) {
|
||||
amenities.add(amenity);
|
||||
done = true;
|
||||
String isPartOf = amenity.getTagContent(Amenity.IS_PART, lang);
|
||||
if (Algorithms.stringsEqual(title, isPartOf)) {
|
||||
return true;
|
||||
} else if (parts != null && parts.length > 0) {
|
||||
String title = amenity.getName(lang);
|
||||
title = Algorithms.isEmpty(title) ? amenity.getName() : title;
|
||||
for (int i = 0; i < parts.length; i++) {
|
||||
String part = parts[i];
|
||||
if (i == 0 && Algorithms.stringsEqual(part, title) || Algorithms.stringsEqual(part, isPartOf)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCancelled() {
|
||||
return done;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
travelBookReader.searchPoi(req);
|
||||
} catch (IOException e) {
|
||||
LOG.error(e.getMessage());
|
||||
}
|
||||
if (!amenities.isEmpty()) {
|
||||
article = readArticle(amenities.get(0), lang);
|
||||
cachedArticles.put(article.routeId, article);
|
||||
List<Amenity> amenities = reader.searchPoi(req);
|
||||
if (!Algorithms.isEmpty(amenities)) {
|
||||
amenityMap.put(reader.getFile(), amenities);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
return article;
|
||||
if (parts != null && parts.length > 0) {
|
||||
headers.addAll(Arrays.asList(parts));
|
||||
headers.add(title);
|
||||
}
|
||||
if (!Algorithms.isEmpty(amenityMap)) {
|
||||
for (Entry<File, List<Amenity>> entry : amenityMap.entrySet()) {
|
||||
File file = entry.getKey();
|
||||
for (Amenity amenity : entry.getValue()) {
|
||||
Set<String> nameLangs = getLanguages(amenity);
|
||||
if (nameLangs.contains(lang)) {
|
||||
TravelArticle a = readArticle(file, amenity, lang);
|
||||
WikivoyageSearchResult rs = new WikivoyageSearchResult(a, new ArrayList<>(nameLangs));
|
||||
List<WikivoyageSearchResult> l = navMap.get(rs.isPartOf);
|
||||
if (l == null) {
|
||||
l = new ArrayList<>();
|
||||
navMap.put(rs.isPartOf, l);
|
||||
}
|
||||
l.add(rs);
|
||||
if (headers != null && headers.contains(a.getTitle())) {
|
||||
headerObjs.put(a.getTitle(), rs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LinkedHashMap<WikivoyageSearchResult, List<WikivoyageSearchResult>> res = new LinkedHashMap<>();
|
||||
for (String header : headers) {
|
||||
WikivoyageSearchResult searchResult = headerObjs.get(header);
|
||||
List<WikivoyageSearchResult> results = navMap.get(header);
|
||||
if (results != null) {
|
||||
Collections.sort(results, new Comparator<WikivoyageSearchResult>() {
|
||||
@Override
|
||||
public int compare(WikivoyageSearchResult o1, WikivoyageSearchResult o2) {
|
||||
return collator.compare(o1.getArticleTitle(), o2.getArticleTitle());
|
||||
}
|
||||
});
|
||||
WikivoyageSearchResult emptyResult = new WikivoyageSearchResult("", header, null, null, null);
|
||||
searchResult = searchResult != null ? searchResult : emptyResult;
|
||||
res.put(searchResult, results);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TravelArticle getArticleById(@NonNull TravelArticleIdentifier articleId, @NonNull String lang) {
|
||||
TravelArticle article = getCachedArticle(articleId, lang);
|
||||
return article == null ? findArticleById(articleId, lang) : article;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TravelArticle getArticleByTitle(@NonNull final String title, @NonNull final String lang) {
|
||||
private TravelArticle getCachedArticle(@NonNull TravelArticleIdentifier articleId, @NonNull String lang) {
|
||||
TravelArticle article = null;
|
||||
Map<String, TravelArticle> articles = cachedArticles.get(articleId);
|
||||
if (articles != null) {
|
||||
if (Algorithms.isEmpty(lang)) {
|
||||
Collection<TravelArticle> ac = articles.values();
|
||||
if (!ac.isEmpty()) {
|
||||
article = ac.iterator().next();
|
||||
}
|
||||
} else {
|
||||
article = articles.get(lang);
|
||||
if (article == null) {
|
||||
article = articles.get("");
|
||||
}
|
||||
}
|
||||
}
|
||||
return article == null ? findArticleById(articleId, lang) : article;
|
||||
}
|
||||
|
||||
private TravelArticle findArticleById(@NonNull final TravelArticleIdentifier articleId, final String lang) {
|
||||
TravelArticle article = null;
|
||||
final List<Amenity> amenities = new ArrayList<>();
|
||||
for (BinaryMapIndexReader travelBookReader : getTravelBookReaders()) {
|
||||
for (BinaryMapIndexReader reader : getReaders()) {
|
||||
try {
|
||||
BinaryMapIndexReader.SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest(
|
||||
0, 0, title, 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE, getSearchRouteArticleFilter(),
|
||||
new ResultMatcher<Amenity>() {
|
||||
if (articleId.file != null && !articleId.file.equals(reader.getFile())) {
|
||||
continue;
|
||||
}
|
||||
SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest(0, 0,
|
||||
Algorithms.emptyIfNull(articleId.title), 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE,
|
||||
getSearchRouteArticleFilter(), new ResultMatcher<Amenity>() {
|
||||
boolean done = false;
|
||||
|
||||
@Override
|
||||
public boolean publish(Amenity amenity) {
|
||||
if (CollatorStringMatcher.cmatches(collator, title, amenity.getName(lang), CHECK_EQUALS_FROM_SPACE)) {
|
||||
if (Algorithms.stringsEqual(articleId.routeId, Algorithms.emptyIfNull(amenity.getTagContent(Amenity.ROUTE_ID, null)))
|
||||
&& Algorithms.stringsEqual(articleId.routeSource, Algorithms.emptyIfNull(amenity.getTagContent(Amenity.ROUTE_SOURCE, null)))) {
|
||||
amenities.add(amenity);
|
||||
done = true;
|
||||
}
|
||||
|
@ -318,19 +416,74 @@ public class TravelObfHelper implements TravelHelper {
|
|||
}
|
||||
}, null);
|
||||
|
||||
travelBookReader.searchPoiByName(req);
|
||||
if (!Double.isNaN(articleId.lat)) {
|
||||
req.setBBoxRadius(articleId.lat, articleId.lon, ARTICLE_SEARCH_RADIUS);
|
||||
if (!Algorithms.isEmpty(articleId.title)) {
|
||||
reader.searchPoiByName(req);
|
||||
} else {
|
||||
reader.searchPoi(req);
|
||||
}
|
||||
} else {
|
||||
reader.searchPoi(req);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.error(e.getMessage());
|
||||
}
|
||||
if (!amenities.isEmpty()) {
|
||||
article = readArticle(amenities.get(0), lang);
|
||||
cachedArticles.put(article.routeId, article);
|
||||
article = cacheTravelArticles(reader.getFile(), amenities.get(0), lang);
|
||||
}
|
||||
}
|
||||
return article;
|
||||
}
|
||||
|
||||
private List<BinaryMapIndexReader> getTravelBookReaders() {
|
||||
@Nullable
|
||||
@Override
|
||||
public TravelArticle getArticleByTitle(@NonNull final String title, @NonNull final String lang) {
|
||||
return getArticleByTitle(title, new QuadRect(), lang);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TravelArticle getArticleByTitle(@NonNull final String title, @NonNull LatLon latLon, @NonNull final String lang) {
|
||||
QuadRect rect = latLon != null ? MapUtils.calculateLatLonBbox(latLon.getLatitude(), latLon.getLongitude(), ARTICLE_SEARCH_RADIUS) : new QuadRect();
|
||||
return getArticleByTitle(title, rect, lang);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public TravelArticle getArticleByTitle(@NonNull final String title, @NonNull QuadRect rect, @NonNull final String lang) {
|
||||
TravelArticle article = null;
|
||||
List<Amenity> amenities = null;
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int left = 0;
|
||||
int right = Integer.MAX_VALUE;
|
||||
int top = 0;
|
||||
int bottom = Integer.MAX_VALUE;
|
||||
if (rect.height() > 0 && rect.width() > 0) {
|
||||
x = (int) rect.centerX();
|
||||
y = (int) rect.centerY();
|
||||
left = (int) rect.left;
|
||||
right = (int) rect.right;
|
||||
top = (int) rect.top;
|
||||
bottom = (int) rect.bottom;
|
||||
}
|
||||
for (BinaryMapIndexReader reader : getReaders()) {
|
||||
try {
|
||||
SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest(
|
||||
x, y, title, left, right, top, bottom, getSearchRouteArticleFilter(), null, null);
|
||||
amenities = reader.searchPoiByName(req);
|
||||
} catch (IOException e) {
|
||||
LOG.error(e.getMessage());
|
||||
}
|
||||
if (!Algorithms.isEmpty(amenities)) {
|
||||
article = cacheTravelArticles(reader.getFile(), amenities.get(0), lang);
|
||||
}
|
||||
}
|
||||
return article;
|
||||
}
|
||||
|
||||
private List<BinaryMapIndexReader> getReaders() {
|
||||
if (!app.isApplicationInitializing()) {
|
||||
return app.getResourceManager().getTravelRepositories();
|
||||
} else {
|
||||
|
@ -338,14 +491,16 @@ public class TravelObfHelper implements TravelHelper {
|
|||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Nullable
|
||||
@Override
|
||||
public String getArticleId(@NonNull String title, @NonNull String lang) {
|
||||
public TravelArticleIdentifier getArticleId(@NonNull String title, @NonNull String lang) {
|
||||
TravelArticle a = null;
|
||||
for (TravelArticle article : cachedArticles.values()) {
|
||||
if (article.getTitle().equals(title)) {
|
||||
a = article;
|
||||
break;
|
||||
for (Map<String, TravelArticle> articles : cachedArticles.values()) {
|
||||
for (TravelArticle article : articles.values()) {
|
||||
if (article.getTitle().equals(title)) {
|
||||
a = article;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (a == null) {
|
||||
|
@ -354,17 +509,18 @@ public class TravelObfHelper implements TravelHelper {
|
|||
a = article;
|
||||
}
|
||||
}
|
||||
return a != null && a.getRouteId() != null ? a.getRouteId() : "";
|
||||
return a != null ? a.generateIdentifier() : null;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ArrayList<String> getArticleLangs(@NonNull String routeId) {
|
||||
public ArrayList<String> getArticleLangs(@NonNull TravelArticleIdentifier articleId) {
|
||||
ArrayList<String> res = new ArrayList<>();
|
||||
res.add("en");
|
||||
for (TravelArticle article : popularArticles) {
|
||||
if (article.getRouteId().equals(routeId)) {
|
||||
res.add(article.getLang());
|
||||
TravelArticle article = getArticleById(articleId, "");
|
||||
if (article != null) {
|
||||
Map<String, TravelArticle> articles = cachedArticles.get(articleId);
|
||||
if (articles != null) {
|
||||
res.addAll(articles.keySet());
|
||||
}
|
||||
}
|
||||
return res;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package net.osmand.plus.wikivoyage.data;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import net.osmand.plus.wikivoyage.data.TravelArticle.TravelArticleIdentifier;
|
||||
import net.osmand.util.Algorithms;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -9,25 +13,52 @@ public class WikivoyageSearchResult {
|
|||
|
||||
private static final int SHOW_LANGS = 3;
|
||||
|
||||
String routeId;
|
||||
List<String> articleTitles = new ArrayList<>();
|
||||
List<String> langs = new ArrayList<>();
|
||||
List<String> isPartOf = new ArrayList<>();
|
||||
String imageTitle;
|
||||
TravelArticleIdentifier articleId;
|
||||
|
||||
public String getRouteId() {
|
||||
return routeId;
|
||||
String imageTitle;
|
||||
String isPartOf;
|
||||
|
||||
List<String> langs = new ArrayList<>();
|
||||
|
||||
public WikivoyageSearchResult(@NonNull TravelArticle article, @Nullable List<String> langs) {
|
||||
articleId = article.generateIdentifier();
|
||||
imageTitle = article.imageTitle;
|
||||
isPartOf = article.isPartOf;
|
||||
if (langs != null) {
|
||||
this.langs = langs;
|
||||
}
|
||||
}
|
||||
|
||||
public List<String> getArticleTitles() {
|
||||
return articleTitles;
|
||||
public WikivoyageSearchResult(String routeId, String articleTitle, String isPartOf, String imageTitle, @Nullable List<String> langs) {
|
||||
TravelArticle article = new TravelArticle();
|
||||
article.routeId = routeId;
|
||||
article.title = articleTitle;
|
||||
|
||||
this.articleId = article.generateIdentifier();
|
||||
this.imageTitle = imageTitle;
|
||||
this.isPartOf = isPartOf;
|
||||
if (langs != null) {
|
||||
this.langs = langs;
|
||||
}
|
||||
}
|
||||
|
||||
public TravelArticleIdentifier getArticleId() {
|
||||
return articleId;
|
||||
}
|
||||
|
||||
public String getArticleTitle() {
|
||||
return articleId.title;
|
||||
}
|
||||
|
||||
public String getArticleRouteId() {
|
||||
return articleId.routeId;
|
||||
}
|
||||
|
||||
public List<String> getLangs() {
|
||||
return langs;
|
||||
}
|
||||
|
||||
public List<String> getIsPartOf() {
|
||||
public String getIsPartOf() {
|
||||
return isPartOf;
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ public class SavedArticlesTabFragment extends BaseOsmAndFragment implements Trav
|
|||
public void openArticle(TravelArticle article) {
|
||||
FragmentManager fm = getFragmentManager();
|
||||
if (fm != null) {
|
||||
WikivoyageArticleDialogFragment.showInstanceByTitle(app, fm, article.getTitle(), article.getLang());
|
||||
WikivoyageArticleDialogFragment.showInstance(app, fm, article.generateIdentifier(), article.getLang());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -37,6 +37,7 @@ import net.osmand.plus.download.DownloadIndexesThread.DownloadEvents;
|
|||
import net.osmand.plus.wikipedia.WikiArticleHelper;
|
||||
import net.osmand.plus.wikivoyage.article.WikivoyageArticleDialogFragment;
|
||||
import net.osmand.plus.wikivoyage.data.TravelArticle;
|
||||
import net.osmand.plus.wikivoyage.data.TravelArticle.TravelArticleIdentifier;
|
||||
import net.osmand.plus.wikivoyage.data.TravelHelper;
|
||||
import net.osmand.plus.wikivoyage.data.TravelLocalDataHelper;
|
||||
import net.osmand.plus.wikivoyage.search.WikivoyageSearchDialogFragment;
|
||||
|
@ -50,8 +51,8 @@ public class WikivoyageExploreActivity extends TabActivity implements DownloadEv
|
|||
TravelLocalDataHelper.Listener {
|
||||
|
||||
private static final String TAB_SELECTED = "tab_selected";
|
||||
private static final String ROUTE_ID_KEY = "route_id_key";
|
||||
private static final String SELECTED_LANG_KEY = "selected_lang_key";
|
||||
private static final String ARTICLE_ID_KEY = "article_id";
|
||||
private static final String SELECTED_LANG_KEY = "selected_lang";
|
||||
|
||||
private static final int EXPLORE_POSITION = 0;
|
||||
private static final int SAVED_ARTICLES_POSITION = 1;
|
||||
|
@ -182,9 +183,9 @@ public class WikivoyageExploreActivity extends TabActivity implements DownloadEv
|
|||
BottomNavigationView bottomNav = (BottomNavigationView) findViewById(R.id.bottom_navigation);
|
||||
bottomNav.setSelectedItemId(R.id.action_saved_articles);
|
||||
}
|
||||
String articleId = intent.getStringExtra(ROUTE_ID_KEY);
|
||||
TravelArticleIdentifier articleId = intent.getParcelableExtra(ARTICLE_ID_KEY);
|
||||
String selectedLang = intent.getStringExtra(SELECTED_LANG_KEY);
|
||||
if (!Algorithms.isEmpty(articleId)) {
|
||||
if (articleId != null) {
|
||||
WikivoyageArticleDialogFragment.showInstance(app, getSupportFragmentManager(), articleId, selectedLang);
|
||||
}
|
||||
}
|
||||
|
@ -201,8 +202,8 @@ public class WikivoyageExploreActivity extends TabActivity implements DownloadEv
|
|||
String title = WikiArticleHelper.decodeTitleFromTravelUrl(data.getQueryParameter("title"));
|
||||
String selectedLang = data.getQueryParameter("lang");
|
||||
if (!Algorithms.isEmpty(title) && !Algorithms.isEmpty(selectedLang)) {
|
||||
String articleId = app.getTravelHelper().getArticleId(title, selectedLang);
|
||||
if (!articleId.isEmpty()) {
|
||||
TravelArticleIdentifier articleId = app.getTravelHelper().getArticleId(title, selectedLang);
|
||||
if (articleId != null) {
|
||||
WikivoyageArticleDialogFragment.showInstance(app, getSupportFragmentManager(), articleId, selectedLang);
|
||||
}
|
||||
}
|
||||
|
@ -279,7 +280,7 @@ public class WikivoyageExploreActivity extends TabActivity implements DownloadEv
|
|||
|
||||
private void applyIntentParameters(Intent intent, TravelArticle article) {
|
||||
intent.putExtra(TAB_SELECTED, viewPager.getCurrentItem());
|
||||
intent.putExtra(ROUTE_ID_KEY, article.getRouteId());
|
||||
intent.putExtra(ARTICLE_ID_KEY, article.generateIdentifier());
|
||||
intent.putExtra(SELECTED_LANG_KEY, article.getLang());
|
||||
}
|
||||
|
||||
|
|
|
@ -76,7 +76,8 @@ public class ArticleTravelCard extends BaseTravelCard {
|
|||
@Override
|
||||
public void onClick(View v) {
|
||||
if (fragmentManager != null) {
|
||||
WikivoyageArticleDialogFragment.showInstance(app, fragmentManager, article.getRouteId(), article.getLang());
|
||||
WikivoyageArticleDialogFragment.showInstance(app, fragmentManager,
|
||||
article.generateIdentifier(), article.getLang());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -7,6 +7,7 @@ import androidx.annotation.NonNull;
|
|||
import net.osmand.GPXUtilities.GPXFile;
|
||||
import net.osmand.GPXUtilities.Metadata;
|
||||
import net.osmand.GPXUtilities.WptPt;
|
||||
import net.osmand.data.LatLon;
|
||||
import net.osmand.data.PointDescription;
|
||||
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
|
||||
import net.osmand.plus.R;
|
||||
|
@ -14,12 +15,13 @@ import net.osmand.plus.activities.MapActivity;
|
|||
import net.osmand.plus.mapcontextmenu.controllers.WptPtMenuController;
|
||||
import net.osmand.plus.wikivoyage.article.WikivoyageArticleDialogFragment;
|
||||
import net.osmand.plus.wikivoyage.data.TravelArticle;
|
||||
import net.osmand.plus.wikivoyage.data.TravelArticle.TravelArticleIdentifier;
|
||||
|
||||
public class WikivoyageWptPtMenuController extends WptPtMenuController {
|
||||
|
||||
private WikivoyageWptPtMenuController(@NonNull MapActivity mapActivity, @NonNull PointDescription pointDescription, @NonNull WptPt wpt, @NonNull TravelArticle article) {
|
||||
super(new WikivoyageWptPtMenuBuilder(mapActivity, wpt), mapActivity, pointDescription, wpt);
|
||||
final String tripId = article.getRouteId();
|
||||
final TravelArticleIdentifier articleId = article.generateIdentifier();
|
||||
final String lang = article.getLang();
|
||||
leftTitleButtonController = new TitleButtonController() {
|
||||
@Override
|
||||
|
@ -27,7 +29,7 @@ public class WikivoyageWptPtMenuController extends WptPtMenuController {
|
|||
MapActivity mapActivity = getMapActivity();
|
||||
if (mapActivity != null) {
|
||||
WikivoyageArticleDialogFragment.showInstance(mapActivity.getMyApplication(),
|
||||
mapActivity.getSupportFragmentManager(), tripId, lang);
|
||||
mapActivity.getSupportFragmentManager(), articleId, lang);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -42,7 +44,7 @@ public class WikivoyageWptPtMenuController extends WptPtMenuController {
|
|||
String title = metadata != null ? metadata.getArticleTitle() : null;
|
||||
String lang = metadata != null ? metadata.getArticleLang() : null;
|
||||
if (!TextUtils.isEmpty(title) && !TextUtils.isEmpty(lang)) {
|
||||
return mapActivity.getMyApplication().getTravelHelper().getArticleByTitle(title, lang);
|
||||
return mapActivity.getMyApplication().getTravelHelper().getArticleByTitle(title, new LatLon(wpt.lat, wpt.lon), lang);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -83,8 +83,8 @@ public class SearchRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView
|
|||
rc.transform(new CropCircleTransformation())
|
||||
.placeholder(placeholder)
|
||||
.into(holder.icon);
|
||||
holder.title.setText(searchRes.getArticleTitles().get(0));
|
||||
holder.leftDescr.setText(searchRes.getIsPartOf().get(0));
|
||||
holder.title.setText(searchRes.getArticleTitle());
|
||||
holder.leftDescr.setText(searchRes.getIsPartOf());
|
||||
holder.rightDescr.setText(searchRes.getFirstLangsString());
|
||||
} else {
|
||||
WikivoyageSearchHistoryItem historyItem = (WikivoyageSearchHistoryItem) item;
|
||||
|
|
|
@ -112,8 +112,7 @@ public class WikivoyageSearchDialogFragment extends WikiBaseDialogFragment {
|
|||
Object item = adapter.getItem(pos);
|
||||
if (item instanceof WikivoyageSearchResult) {
|
||||
WikivoyageSearchResult res = (WikivoyageSearchResult) item;
|
||||
WikivoyageArticleDialogFragment
|
||||
.showInstance(fm, res.getRouteId(), new ArrayList<>(res.getLangs()));
|
||||
WikivoyageArticleDialogFragment.showInstance(fm, res.getArticleId(), new ArrayList<>(res.getLangs()));
|
||||
} else if (item instanceof WikivoyageSearchHistoryItem) {
|
||||
WikivoyageSearchHistoryItem historyItem = (WikivoyageSearchHistoryItem) item;
|
||||
WikivoyageArticleDialogFragment
|
||||
|
|
Loading…
Reference in a new issue