diff --git a/OsmAnd-java/src/main/java/net/osmand/data/Amenity.java b/OsmAnd-java/src/main/java/net/osmand/data/Amenity.java index 14d0abab79..861a7c9b93 100644 --- a/OsmAnd-java/src/main/java/net/osmand/data/Amenity.java +++ b/OsmAnd-java/src/main/java/net/osmand/data/Amenity.java @@ -274,6 +274,10 @@ public class Amenity extends MapObject { return null; } + public String getTagContent(String tag) { + return getTagContent(tag, null); + } + public String getTagContent(String tag, String lang) { if (lang != null) { String translateName = getAdditionalInfo(tag + ":" + lang); diff --git a/OsmAnd/res/layout/wikivoyage_travel_gpx_card.xml b/OsmAnd/res/layout/wikivoyage_travel_gpx_card.xml new file mode 100644 index 0000000000..44077a0dcd --- /dev/null +++ b/OsmAnd/res/layout/wikivoyage_travel_gpx_card.xml @@ -0,0 +1,282 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelGpx.java b/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelGpx.java new file mode 100644 index 0000000000..185fdc922c --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelGpx.java @@ -0,0 +1,14 @@ +package net.osmand.plus.wikivoyage.data; + +public class TravelGpx extends TravelArticle { + + public static final String DISTANCE = "distance"; + public static final String DIFF_ELE_UP = "diff_ele_up"; + public static final String DIFF_ELE_DOWN = "diff_ele_down"; + public static final String USER = "user"; + + public String user; + public float totalDistance = 0; + public double diffElevationUp = 0; + public double diffElevationDown = 0; +} diff --git a/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelLocalDataHelper.java b/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelLocalDataHelper.java index 02ee5a32c8..c2ccc442c3 100644 --- a/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelLocalDataHelper.java +++ b/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelLocalDataHelper.java @@ -143,7 +143,8 @@ public class TravelLocalDataHelper { @Nullable private TravelArticle getArticle(String title, String lang) { for (TravelArticle article : savedArticles) { - if (article.title != null && article.title.equals(title) && article.lang != null && article.lang.equals(lang)) { + if (Algorithms.stringsEqual(article.title, title) + && Algorithms.stringsEqual(article.lang, lang)) { return article; } } @@ -477,12 +478,12 @@ public class TravelLocalDataHelper { SQLiteConnection conn = openConnection(false); if (conn != null) { try { - conn.execSQL("DELETE FROM " + BOOKMARKS_TABLE_NAME + - " WHERE " + BOOKMARKS_COL_ARTICLE_TITLE + " = ?" + - " AND " + BOOKMARKS_COL_ROUTE_ID + " = ?" + - " AND " + BOOKMARKS_COL_LANG + " = ?" + - " AND " + BOOKMARKS_COL_TRAVEL_BOOK + " = ?", - new Object[]{article.title, article.routeId, article.lang, travelBook}); + String query = "DELETE FROM " + BOOKMARKS_TABLE_NAME + + " WHERE " + BOOKMARKS_COL_ARTICLE_TITLE + " = ?" + + " AND " + BOOKMARKS_COL_ROUTE_ID + " = ?" + + " AND " + BOOKMARKS_COL_LANG + ((article.lang != null) ? " = '" + article.lang + "'" : " IS NULL") + + " AND " + BOOKMARKS_COL_TRAVEL_BOOK + " = ?"; + conn.execSQL(query, new Object[]{article.title, article.routeId, travelBook}); } finally { conn.close(); } @@ -537,7 +538,12 @@ public class TravelLocalDataHelper { @NonNull private TravelArticle readSavedArticle(SQLiteCursor cursor) { - TravelArticle res = new TravelArticle(); + TravelArticle res; + if (cursor.getString(cursor.getColumnIndex(BOOKMARKS_COL_LANG)) == null) { + res = new TravelGpx(); + } else { + res = new TravelArticle(); + } res.title = cursor.getString(cursor.getColumnIndex(BOOKMARKS_COL_ARTICLE_TITLE)); res.lang = cursor.getString(cursor.getColumnIndex(BOOKMARKS_COL_LANG)); res.aggregatedPartOf = cursor.getString(cursor.getColumnIndex(BOOKMARKS_COL_IS_PART_OF)); diff --git a/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelObfHelper.java b/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelObfHelper.java index 0f14896a94..294cf2cd13 100644 --- a/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelObfHelper.java +++ b/OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelObfHelper.java @@ -2,6 +2,7 @@ package net.osmand.plus.wikivoyage.data; import android.os.AsyncTask; import android.text.TextUtils; +import android.util.Pair; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -13,6 +14,7 @@ import net.osmand.IndexConstants; import net.osmand.OsmAndCollator; import net.osmand.PlatformUtil; import net.osmand.ResultMatcher; +import net.osmand.binary.BinaryMapDataObject; import net.osmand.binary.BinaryMapIndexReader; import net.osmand.binary.BinaryMapIndexReader.SearchPoiTypeFilter; import net.osmand.binary.BinaryMapIndexReader.SearchRequest; @@ -46,8 +48,18 @@ import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; +import gnu.trove.iterator.TIntObjectIterator; + +import static net.osmand.GPXUtilities.Track; +import static net.osmand.GPXUtilities.TrkSegment; import static net.osmand.GPXUtilities.WptPt; import static net.osmand.GPXUtilities.writeGpxFile; +import static net.osmand.plus.helpers.GpxUiHelper.getGpxTitle; +import static net.osmand.plus.wikivoyage.data.TravelGpx.DIFF_ELE_DOWN; +import static net.osmand.plus.wikivoyage.data.TravelGpx.DIFF_ELE_UP; +import static net.osmand.plus.wikivoyage.data.TravelGpx.DISTANCE; +import static net.osmand.plus.wikivoyage.data.TravelGpx.USER; +import static net.osmand.util.Algorithms.capitalizeFirstLetter; public class TravelObfHelper implements TravelHelper { @@ -55,9 +67,13 @@ public class TravelObfHelper implements TravelHelper { private static final String WORLD_WIKIVOYAGE_FILE_NAME = "World_wikivoyage.travel.obf"; public static final String ROUTE_ARTICLE = "route_article"; public static final String ROUTE_ARTICLE_POINT = "route_article_point"; + public static final String ROUTE_TRACK = "route_track"; public static final int POPULAR_ARTICLES_SEARCH_RADIUS = 100000; public static final int ARTICLE_SEARCH_RADIUS = 50000; + public static final int GPX_TRACKS_SEARCH_RADIUS = 10000; public static final int MAX_POPULAR_ARTICLES_COUNT = 30; + public static final String REF_TAG = "ref"; + public static final String NAME_TAG = "name"; private final OsmandApplication app; private final Collator collator; @@ -91,47 +107,69 @@ public class TravelObfHelper implements TravelHelper { public synchronized List loadPopularArticles() { String lang = app.getLanguage(); List popularArticles = new ArrayList<>(); - for (BinaryMapIndexReader reader : getReaders()) { + final List> amenities = new ArrayList<>(); + final LatLon location = app.getMapViewTrackingUtilities().getMapLocation(); + for (final BinaryMapIndexReader reader : getReaders()) { try { - final LatLon location = app.getMapViewTrackingUtilities().getMapLocation(); - SearchRequest req = BinaryMapIndexReader.buildSearchPoiRequest( - location, POPULAR_ARTICLES_SEARCH_RADIUS, -1, getSearchFilter(false), null); - List amenities = reader.searchPoi(req); - if (amenities.size() > 0) { - Collections.sort(amenities, new Comparator() { - @Override - public int compare(Amenity a1, Amenity a2) { - int d1 = (int) (MapUtils.getDistance(a1.getLocation().getLatitude(), a1.getLocation().getLongitude(), - location.getLatitude(), location.getLongitude())); - int d2 = (int) (MapUtils.getDistance(a2.getLocation().getLatitude(), a2.getLocation().getLongitude(), - location.getLatitude(), location.getLongitude())); - return d1 < d2 ? -1 : (d1 == d2 ? 0 : 1); - } - }); - for (Amenity amenity : amenities) { - if (!Algorithms.isEmpty(amenity.getName(lang))) { - TravelArticle article = cacheTravelArticles(reader.getFile(), amenity, lang, false, null); - if (article != null) { - popularArticles.add(article); - if (popularArticles.size() >= MAX_POPULAR_ARTICLES_COUNT) { - break; - } - } + searchAmenity(amenities, location, reader, POPULAR_ARTICLES_SEARCH_RADIUS, -1, ROUTE_ARTICLE); + searchAmenity(amenities, location, reader, GPX_TRACKS_SEARCH_RADIUS, 15, ROUTE_TRACK); + } catch (Exception e) { + LOG.error(e.getMessage(), e); + } + } + + if (amenities.size() > 0) { + Collections.sort(amenities, new Comparator>() { + @Override + public int compare(Pair article1, Pair article2) { + int d1 = (int) (MapUtils.getDistance(((Amenity) article1.second).getLocation(), location)); + int d2 = (int) (MapUtils.getDistance(((Amenity) article2.second).getLocation(), location)); + return d1 < d2 ? -1 : (d1 == d2 ? 0 : 1); + } + }); + for (Pair amenity : amenities) { + if (!Algorithms.isEmpty(amenity.second.getName(lang))) { + TravelArticle article = cacheTravelArticles(amenity.first, amenity.second, lang, false, null); + if (article != null) { + popularArticles.add(article); + if (popularArticles.size() >= MAX_POPULAR_ARTICLES_COUNT) { + break; } } } - } catch (Exception e) { - LOG.error(e.getMessage(), e); } } this.popularArticles = popularArticles; return popularArticles; } + private void searchAmenity(final List> amenitiesList, LatLon location, + final BinaryMapIndexReader reader, int searchRadius, int zoom, + String searchFilter) throws IOException { + reader.searchPoi(BinaryMapIndexReader.buildSearchPoiRequest( + location, searchRadius, zoom, getSearchFilter(searchFilter), new ResultMatcher() { + @Override + public boolean publish(Amenity object) { + amenitiesList.add(new Pair<>(reader.getFile(), object)); + return false; + } + + @Override + public boolean isCancelled() { + return false; + } + })); + } + @Nullable private TravelArticle cacheTravelArticles(File file, Amenity amenity, String lang, boolean readPoints, @Nullable GpxReadCallback callback) { TravelArticle article = null; - Map articles = readArticles(file, amenity); + Map articles; + if (ROUTE_TRACK.equals(amenity.getSubType())) { + articles = readRoutePoint(file, amenity); + } else { + articles = readArticles(file, amenity); + } if (!Algorithms.isEmpty(articles)) { TravelArticleIdentifier newArticleId = articles.values().iterator().next().generateIdentifier(); cachedArticles.put(newArticleId, articles); @@ -140,12 +178,41 @@ public class TravelObfHelper implements TravelHelper { return article; } + private Map readRoutePoint(File file, Amenity amenity) { + Map articles = new HashMap<>(); + TravelGpx res = new TravelGpx(); + res.file = file; + String title = amenity.getName("en"); + res.title = createTitle(Algorithms.isEmpty(title) ? amenity.getName() : title); + res.lat = amenity.getLocation().getLatitude(); + res.lon = amenity.getLocation().getLongitude(); + res.routeId = Algorithms.emptyIfNull(amenity.getTagContent(Amenity.ROUTE_ID)); + try { + res.totalDistance = Float.parseFloat(Algorithms.emptyIfNull(amenity.getTagContent(DISTANCE))); + } catch (NumberFormatException e) { + LOG.debug(e.getMessage(), e); + } + try { + res.diffElevationUp = Double.parseDouble(Algorithms.emptyIfNull(amenity.getTagContent(DIFF_ELE_UP))); + } catch (NumberFormatException e) { + LOG.debug(e.getMessage(), e); + } + try { + res.diffElevationDown = Double.parseDouble(Algorithms.emptyIfNull(amenity.getTagContent(DIFF_ELE_DOWN))); + } catch (NumberFormatException e) { + LOG.debug(e.getMessage(), e); + } + res.user = Algorithms.emptyIfNull(amenity.getTagContent(USER)); + articles.put("en", res); + return articles; + } + @NonNull - private SearchPoiTypeFilter getSearchFilter(final boolean articlePoints) { + private SearchPoiTypeFilter getSearchFilter(final String filterSubcategory) { return new SearchPoiTypeFilter() { @Override public boolean accept(PoiCategory type, String subcategory) { - return subcategory.equals(articlePoints ? ROUTE_ARTICLE_POINT : ROUTE_ARTICLE); + return subcategory.equals(filterSubcategory); } @Override @@ -176,9 +243,9 @@ public class TravelObfHelper implements TravelHelper { res.isParentOf = Algorithms.emptyIfNull(amenity.getTagContent(Amenity.IS_PARENT_OF, lang)); res.lat = amenity.getLocation().getLatitude(); res.lon = amenity.getLocation().getLongitude(); - res.imageTitle = Algorithms.emptyIfNull(amenity.getTagContent(Amenity.IMAGE_TITLE, null)); - res.routeId = Algorithms.emptyIfNull(amenity.getTagContent(Amenity.ROUTE_ID, null)); - res.routeSource = Algorithms.emptyIfNull(amenity.getTagContent(Amenity.ROUTE_SOURCE, null)); + res.imageTitle = Algorithms.emptyIfNull(amenity.getTagContent(Amenity.IMAGE_TITLE)); + res.routeId = Algorithms.emptyIfNull(amenity.getTagContent(Amenity.ROUTE_ID)); + res.routeSource = Algorithms.emptyIfNull(amenity.getTagContent(Amenity.ROUTE_SOURCE)); res.originalId = 0; res.lang = lang; res.contentsJson = Algorithms.emptyIfNull(amenity.getTagContent(Amenity.CONTENT_JSON, lang)); @@ -186,6 +253,82 @@ public class TravelObfHelper implements TravelHelper { return res; } + @Nullable + private GPXFile buildTravelGpxFile(@NonNull final TravelGpx article) { + String routeId = article.getRouteId(); + final String ref = routeId.substring(routeId.length() - 3); + final List segmentList = new ArrayList<>(); + + for (BinaryMapIndexReader reader : getReaders()) { + try { + if (article.file != null && !article.file.equals(reader.getFile())) { + continue; + } + BinaryMapIndexReader.SearchRequest sr = BinaryMapIndexReader.buildSearchRequest( + 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE, 15, null, + new ResultMatcher() { + @Override + public boolean publish(BinaryMapDataObject object) { + if (object.getPointsLength() > 1) { + if (getTagValue(object, REF_TAG).equals(ref) + && createTitle(getTagValue(object, NAME_TAG)).equals(article.title)) { + segmentList.add(object); + } + } + return false; + } + + @Override + public boolean isCancelled() { + return false; + } + }); + reader.searchMapIndex(sr); + if (!Algorithms.isEmpty(segmentList)) { + break; + } + } catch (Exception e) { + System.out.println(e.getMessage()); + } + } + GPXFile gpxFile = null; + if (!segmentList.isEmpty()) { + Track track = new Track(); + for (BinaryMapDataObject segment : segmentList) { + TrkSegment trkSegment = new TrkSegment(); + for (int i = 0; i < segment.getPointsLength(); i++) { + WptPt point = new WptPt(); + point.lat = MapUtils.get31LatitudeY(segment.getPoint31YTile(i)); + point.lon = MapUtils.get31LongitudeX(segment.getPoint31XTile(i)); + trkSegment.points.add(point); + } + track.segments.add(trkSegment); + } + gpxFile = new GPXFile(article.getTitle(), article.getLang(), ""); + gpxFile.tracks = new ArrayList<>(); + gpxFile.tracks.add(track); + } + article.gpxFile = gpxFile; + return gpxFile; + } + + private String getTagValue(BinaryMapDataObject object, String tag) { + BinaryMapIndexReader.MapIndex mi = object.getMapIndex(); + TIntObjectIterator it = object.getObjectNames().iterator(); + while (it.hasNext()) { + it.advance(); + BinaryMapIndexReader.TagValuePair tp = mi.decodeType(it.key()); + if (tp.tag.equals(tag)) { + return it.value(); + } + } + return ""; + } + + private String createTitle(String name) { + return capitalizeFirstLetter(getGpxTitle(name)); + } + @NonNull private synchronized List getPointList(@NonNull final TravelArticle article) { final List pointList = new ArrayList<>(); @@ -197,14 +340,14 @@ public class TravelObfHelper implements TravelHelper { } SearchRequest req = BinaryMapIndexReader.buildSearchPoiRequest(0, 0, Algorithms.emptyIfNull(article.title), 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE, - getSearchFilter(true), new ResultMatcher() { + getSearchFilter(ROUTE_ARTICLE_POINT), new ResultMatcher() { @Override public boolean publish(Amenity amenity) { String amenityLang = amenity.getTagSuffix(Amenity.LANG_YES + ":"); if (Algorithms.stringsEqual(lang, amenityLang) && Algorithms.stringsEqual(article.routeId, - Algorithms.emptyIfNull(amenity.getTagContent(Amenity.ROUTE_ID, null)))) { + Algorithms.emptyIfNull(amenity.getTagContent(Amenity.ROUTE_ID)))) { pointList.add(amenity); } return false; @@ -246,7 +389,7 @@ public class TravelObfHelper implements TravelHelper { } String category = amenity.getTagSuffix("category_"); if (category != null) { - wptPt.category = Algorithms.capitalizeFirstLetter(category); + wptPt.category = capitalizeFirstLetter(category); } return wptPt; } @@ -266,7 +409,7 @@ public class TravelObfHelper implements TravelHelper { for (BinaryMapIndexReader reader : getReaders()) { try { SearchRequest searchRequest = BinaryMapIndexReader.buildSearchPoiRequest(0, 0, searchQuery, - 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE, getSearchFilter(false), new ResultMatcher() { + 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE, getSearchFilter(ROUTE_ARTICLE), new ResultMatcher() { @Override public boolean publish(Amenity object) { List otherNames = object.getAllNames(false); @@ -441,7 +584,7 @@ public class TravelObfHelper implements TravelHelper { for (BinaryMapIndexReader reader : getReaders()) { try { SearchRequest req = BinaryMapIndexReader.buildSearchPoiRequest( - 0, 0, title, 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE, getSearchFilter(false), + 0, 0, title, 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE, getSearchFilter(ROUTE_ARTICLE), new ResultMatcher() { boolean done = false; @@ -530,12 +673,13 @@ public class TravelObfHelper implements TravelHelper { } SearchRequest req = BinaryMapIndexReader.buildSearchPoiRequest(0, 0, Algorithms.emptyIfNull(articleId.title), 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE, - getSearchFilter(false), new ResultMatcher() { + getSearchFilter(ROUTE_ARTICLE), new ResultMatcher() { boolean done = false; @Override public boolean publish(Amenity amenity) { - if (Algorithms.stringsEqual(articleId.routeId, Algorithms.emptyIfNull(amenity.getTagContent(Amenity.ROUTE_ID, null))) || isDbArticle) { + if (Algorithms.stringsEqual(articleId.routeId, + Algorithms.emptyIfNull(amenity.getTagContent(Amenity.ROUTE_ID))) || isDbArticle) { amenities.add(amenity); done = true; } @@ -606,7 +750,7 @@ public class TravelObfHelper implements TravelHelper { for (BinaryMapIndexReader reader : getReaders()) { try { SearchRequest req = BinaryMapIndexReader.buildSearchPoiRequest( - x, y, title, left, right, top, bottom, getSearchFilter(false), + x, y, title, left, right, top, bottom, getSearchFilter(ROUTE_ARTICLE), new ResultMatcher() { boolean done = false; @@ -693,7 +837,12 @@ public class TravelObfHelper implements TravelHelper { @NonNull @Override public File createGpxFile(@NonNull TravelArticle article) { - final GPXFile gpx = article.getGpxFile(); + final GPXFile gpx; + if (article instanceof TravelGpx) { + gpx = buildTravelGpxFile((TravelGpx) article); + } else { + gpx = article.getGpxFile(); + } File file = app.getAppPath(IndexConstants.GPX_TRAVEL_DIR + getGPXName(article)); writeGpxFile(file, gpx); return file; diff --git a/OsmAnd/src/net/osmand/plus/wikivoyage/explore/ExploreRvAdapter.java b/OsmAnd/src/net/osmand/plus/wikivoyage/explore/ExploreRvAdapter.java index a95614bdb8..5341edcb9d 100644 --- a/OsmAnd/src/net/osmand/plus/wikivoyage/explore/ExploreRvAdapter.java +++ b/OsmAnd/src/net/osmand/plus/wikivoyage/explore/ExploreRvAdapter.java @@ -20,6 +20,8 @@ import net.osmand.plus.wikivoyage.explore.travelcards.StartEditingTravelCard; import net.osmand.plus.wikivoyage.explore.travelcards.StartEditingTravelCard.StartEditingTravelVH; import net.osmand.plus.wikivoyage.explore.travelcards.TravelDownloadUpdateCard; import net.osmand.plus.wikivoyage.explore.travelcards.TravelDownloadUpdateCard.DownloadUpdateVH; +import net.osmand.plus.wikivoyage.explore.travelcards.TravelGpxCard; +import net.osmand.plus.wikivoyage.explore.travelcards.TravelGpxCard.TravelGpxVH; import net.osmand.plus.wikivoyage.explore.travelcards.TravelNeededMapsCard; import net.osmand.plus.wikivoyage.explore.travelcards.TravelNeededMapsCard.NeededMapsVH; @@ -48,6 +50,9 @@ public class ExploreRvAdapter extends RecyclerView.Adapter 0; i--) { BaseTravelCard o = items.get(i); - if (o instanceof ArticleTravelCard) { + if (o instanceof ArticleTravelCard || o instanceof TravelGpxCard) { return i; } } diff --git a/OsmAnd/src/net/osmand/plus/wikivoyage/explore/ExploreTabFragment.java b/OsmAnd/src/net/osmand/plus/wikivoyage/explore/ExploreTabFragment.java index f4e4408cba..9055acd4ed 100644 --- a/OsmAnd/src/net/osmand/plus/wikivoyage/explore/ExploreTabFragment.java +++ b/OsmAnd/src/net/osmand/plus/wikivoyage/explore/ExploreTabFragment.java @@ -29,6 +29,7 @@ import net.osmand.plus.download.DownloadResources; import net.osmand.plus.download.DownloadValidationManager; import net.osmand.plus.download.IndexItem; import net.osmand.plus.wikivoyage.data.TravelArticle; +import net.osmand.plus.wikivoyage.data.TravelGpx; import net.osmand.plus.wikivoyage.data.TravelHelper; import net.osmand.plus.wikivoyage.data.TravelLocalDataHelper; import net.osmand.plus.wikivoyage.explore.travelcards.ArticleTravelCard; @@ -37,6 +38,7 @@ import net.osmand.plus.wikivoyage.explore.travelcards.HeaderTravelCard; import net.osmand.plus.wikivoyage.explore.travelcards.OpenBetaTravelCard; import net.osmand.plus.wikivoyage.explore.travelcards.StartEditingTravelCard; import net.osmand.plus.wikivoyage.explore.travelcards.TravelDownloadUpdateCard; +import net.osmand.plus.wikivoyage.explore.travelcards.TravelGpxCard; import net.osmand.plus.wikivoyage.explore.travelcards.TravelNeededMapsCard; import java.io.IOException; @@ -178,17 +180,21 @@ public class ExploreTabFragment extends BaseOsmAndFragment implements DownloadEv List popularArticles = app.getTravelHelper().getPopularArticles(); for (TravelArticle article : popularArticles) { - items.add(new ArticleTravelCard(app, nightMode, article, activity.getSupportFragmentManager())); + if (article instanceof TravelGpx) { + items.add(new TravelGpxCard(app, nightMode, (TravelGpx) article, getActivity())); + } else { + items.add(new ArticleTravelCard(app, nightMode, article, activity.getSupportFragmentManager())); + } + } + items.add(new StartEditingTravelCard(activity, nightMode)); + adapter.setItems(items); + final DownloadIndexesThread downloadThread = app.getDownloadThread(); + if (!downloadThread.getIndexes().isDownloadedFromInternet) { + waitForIndexes = true; + downloadThread.runReloadIndexFilesSilent(); + } else { + checkDownloadIndexes(); } - } - items.add(new StartEditingTravelCard(activity, nightMode)); - adapter.setItems(items); - final DownloadIndexesThread downloadThread = app.getDownloadThread(); - if (!downloadThread.getIndexes().isDownloadedFromInternet) { - waitForIndexes = true; - downloadThread.runReloadIndexFilesSilent(); - } else { - checkDownloadIndexes(); } } } diff --git a/OsmAnd/src/net/osmand/plus/wikivoyage/explore/SavedArticlesRvAdapter.java b/OsmAnd/src/net/osmand/plus/wikivoyage/explore/SavedArticlesRvAdapter.java index 8996e4d375..a01de6e6cb 100644 --- a/OsmAnd/src/net/osmand/plus/wikivoyage/explore/SavedArticlesRvAdapter.java +++ b/OsmAnd/src/net/osmand/plus/wikivoyage/explore/SavedArticlesRvAdapter.java @@ -7,6 +7,8 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.DrawableRes; +import androidx.annotation.LayoutRes; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.recyclerview.widget.RecyclerView; @@ -16,16 +18,20 @@ import com.squareup.picasso.Callback; import com.squareup.picasso.Picasso; import com.squareup.picasso.RequestCreator; +import net.osmand.AndroidUtils; import net.osmand.PicassoUtils; +import net.osmand.plus.OsmAndFormatter; import net.osmand.plus.OsmandApplication; -import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.R; import net.osmand.plus.UiUtilities; +import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.widgets.tools.CropCircleTransformation; import net.osmand.plus.wikipedia.WikiArticleHelper; import net.osmand.plus.wikivoyage.WikivoyageUtils; import net.osmand.plus.wikivoyage.data.TravelArticle; +import net.osmand.plus.wikivoyage.data.TravelGpx; import net.osmand.plus.wikivoyage.data.TravelLocalDataHelper; +import net.osmand.plus.wikivoyage.explore.travelcards.TravelGpxCard; import java.util.ArrayList; import java.util.List; @@ -33,7 +39,8 @@ import java.util.List; public class SavedArticlesRvAdapter extends RecyclerView.Adapter { private static final int HEADER_TYPE = 0; - private static final int ITEM_TYPE = 1; + private static final int ARTICLE_TYPE = 1; + private static final int GPX_TYPE = 2; private final OsmandApplication app; private final OsmandSettings settings; @@ -45,6 +52,7 @@ public class SavedArticlesRvAdapter extends RecyclerView.Adapter