Merge pull request #10675 from osmandapp/travel_obf_gpx_track
Travel obf with gpx tracks
This commit is contained in:
commit
899e2d6aa5
10 changed files with 754 additions and 78 deletions
|
@ -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);
|
||||
|
|
282
OsmAnd/res/layout/wikivoyage_travel_gpx_card.xml
Normal file
282
OsmAnd/res/layout/wikivoyage_travel_gpx_card.xml
Normal file
|
@ -0,0 +1,282 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:osmand="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/background_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/wikivoyage_card_bg_color">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="@dimen/content_padding">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/content_padding"
|
||||
android:layout_marginRight="@dimen/content_padding"
|
||||
android:layout_marginStart="@dimen/content_padding"
|
||||
android:layout_marginEnd="@dimen/content_padding">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/title"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/default_title_line_height"
|
||||
android:layout_marginBottom="@dimen/measurement_tool_menu_title_padding_bottom"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="?attr/active_color_basic"
|
||||
android:textSize="@dimen/default_list_text_size"
|
||||
osmand:typeface="@string/font_roboto_medium"
|
||||
tools:text="London" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/distance"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textAppearance="@style/TextAppearance.ContextMenuSubtitle"
|
||||
android:textColor="@null"
|
||||
tools:text="5.3 km" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/distance_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="@dimen/content_padding_half"
|
||||
android:layout_marginRight="@dimen/content_padding_half"
|
||||
android:layout_marginStart="@dimen/content_padding_half"
|
||||
android:layout_marginLeft="@dimen/content_padding_half"
|
||||
osmand:srcCompat="@drawable/ic_action_distance_16"
|
||||
android:contentDescription="@string/distance"/>
|
||||
|
||||
<View
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="@dimen/content_padding_half"
|
||||
android:layout_marginRight="@dimen/content_padding_half"
|
||||
android:background="?attr/wikivoyage_card_divider_color" />
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/diff_ele_down"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textAppearance="@style/TextAppearance.ContextMenuSubtitle"
|
||||
android:textColor="@null"
|
||||
tools:text="145 m" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/down_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="@dimen/content_padding_half"
|
||||
android:layout_marginRight="@dimen/content_padding_half"
|
||||
android:layout_marginStart="@dimen/content_padding_half"
|
||||
android:layout_marginLeft="@dimen/content_padding_half"
|
||||
osmand:srcCompat="@drawable/ic_action_arrow_down_16"
|
||||
android:tint="@color/icon_color_default_light"
|
||||
android:contentDescription="@string/distance" />
|
||||
|
||||
<View
|
||||
android:layout_width="1dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="@dimen/content_padding_half"
|
||||
android:layout_marginRight="@dimen/content_padding_half"
|
||||
android:background="?attr/wikivoyage_card_divider_color" />
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/diff_ele_up"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textAppearance="@style/TextAppearance.ContextMenuSubtitle"
|
||||
android:textColor="@null"
|
||||
tools:text="15 m" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/up_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginEnd="@dimen/content_padding_half"
|
||||
android:layout_marginRight="@dimen/content_padding_half"
|
||||
android:layout_marginStart="@dimen/content_padding_half"
|
||||
android:layout_marginLeft="@dimen/content_padding_half"
|
||||
osmand:srcCompat="@drawable/ic_action_arrow_up_16"
|
||||
android:tint="@color/icon_color_default_light"
|
||||
android:contentDescription="@string/distance" />
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingTop="@dimen/content_padding_half"
|
||||
android:paddingBottom="@dimen/content_padding_small">
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/user_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/btn_border_bg_light"
|
||||
android:gravity="center_vertical"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:paddingTop="@dimen/subHeaderPadding"
|
||||
android:paddingBottom="@dimen/subHeaderPadding"
|
||||
android:paddingLeft="@dimen/bottom_sheet_content_padding_small"
|
||||
android:paddingRight="@dimen/bottom_sheet_content_padding_small"
|
||||
android:textAppearance="@style/TextAppearance.ContextMenuSubtitle"
|
||||
android:textColor="?attr/active_color_basic"
|
||||
android:textSize="@dimen/default_desc_text_size"
|
||||
osmand:typeface="@string/font_roboto_medium"
|
||||
android:drawablePadding="@dimen/content_padding_small_half"
|
||||
android:drawableStart="@drawable/ic_action_user_account_16"
|
||||
android:drawableLeft="@drawable/ic_action_user_account_16"
|
||||
tools:drawableTint="?attr/wikivoyage_active_color"
|
||||
tools:text="Lorem Ipsum" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:visibility="invisible"
|
||||
android:layout_height="1dp"
|
||||
android:background="?attr/wikivoyage_card_divider_color" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="@dimen/content_padding_small_half"
|
||||
android:paddingBottom="@dimen/content_padding_small_half">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/bottom_sheet_content_padding_small"
|
||||
android:layout_marginStart="@dimen/bottom_sheet_content_padding_small"
|
||||
android:background="@drawable/rounded_background_3dp">
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/left_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:drawablePadding="@dimen/content_padding_small"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:letterSpacing="@dimen/text_button_letter_spacing"
|
||||
android:maxLines="1"
|
||||
android:paddingBottom="@dimen/content_padding_half"
|
||||
android:paddingLeft="@dimen/bottom_sheet_content_padding_small"
|
||||
android:paddingRight="@dimen/bottom_sheet_content_padding_small"
|
||||
android:paddingTop="@dimen/content_padding_half"
|
||||
android:textColor="?attr/wikivoyage_active_color"
|
||||
android:textSize="@dimen/default_desc_text_size"
|
||||
osmand:typeface="@string/font_roboto_medium"
|
||||
tools:drawableLeft="@drawable/ic_action_read_article"
|
||||
tools:drawableTint="?attr/wikivoyage_active_color"
|
||||
tools:ignore="UnusedAttribute"
|
||||
tools:text="Read"
|
||||
android:paddingStart="@dimen/bottom_sheet_content_padding_small"
|
||||
android:paddingEnd="@dimen/bottom_sheet_content_padding_small"
|
||||
tools:drawableStart="@drawable/ic_action_read_article" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="@dimen/bottom_sheet_content_padding_small"
|
||||
android:layout_marginRight="@dimen/bottom_sheet_content_padding_small"
|
||||
android:background="@drawable/rounded_background_3dp">
|
||||
|
||||
<net.osmand.plus.widgets.TextViewEx
|
||||
android:id="@+id/right_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:drawablePadding="@dimen/content_padding_small"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:letterSpacing="@dimen/text_button_letter_spacing"
|
||||
android:maxLines="1"
|
||||
android:paddingBottom="@dimen/content_padding_half"
|
||||
android:paddingLeft="@dimen/bottom_sheet_content_padding_small"
|
||||
android:paddingRight="@dimen/bottom_sheet_content_padding_small"
|
||||
android:paddingTop="@dimen/content_padding_half"
|
||||
android:textColor="?attr/wikivoyage_active_color"
|
||||
android:textSize="@dimen/default_desc_text_size"
|
||||
osmand:typeface="@string/font_roboto_medium"
|
||||
tools:drawableRight="@drawable/ic_action_read_later_fill"
|
||||
tools:drawableTint="?attr/wikivoyage_active_color"
|
||||
tools:ignore="UnusedAttribute"
|
||||
tools:text="Delete"
|
||||
tools:drawableEnd="@drawable/ic_action_read_later_fill"
|
||||
android:paddingEnd="@dimen/bottom_sheet_content_padding_small"
|
||||
android:paddingStart="@dimen/bottom_sheet_content_padding_small" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<View
|
||||
android:id="@+id/divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="?attr/wikivoyage_card_divider_color" />
|
||||
|
||||
<include
|
||||
android:id="@+id/shadow"
|
||||
layout="@layout/card_bottom_divider"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<include
|
||||
android:id="@+id/list_item_divider"
|
||||
layout="@layout/list_item_divider"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</LinearLayout>
|
14
OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelGpx.java
Normal file
14
OsmAnd/src/net/osmand/plus/wikivoyage/data/TravelGpx.java
Normal file
|
@ -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;
|
||||
}
|
|
@ -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));
|
||||
|
|
|
@ -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<TravelArticle> loadPopularArticles() {
|
||||
String lang = app.getLanguage();
|
||||
List<TravelArticle> popularArticles = new ArrayList<>();
|
||||
for (BinaryMapIndexReader reader : getReaders()) {
|
||||
final List<Pair<File, Amenity>> amenities = new ArrayList<>();
|
||||
final LatLon location = app.getMapViewTrackingUtilities().getMapLocation();
|
||||
for (final BinaryMapIndexReader reader : getReaders()) {
|
||||
try {
|
||||
final LatLon location = app.getMapViewTrackingUtilities().getMapLocation();
|
||||
SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest(
|
||||
location, POPULAR_ARTICLES_SEARCH_RADIUS, -1, getSearchFilter(false), null);
|
||||
List<Amenity> amenities = reader.searchPoi(req);
|
||||
if (amenities.size() > 0) {
|
||||
Collections.sort(amenities, new Comparator<Amenity>() {
|
||||
@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<Pair<File, Amenity>>() {
|
||||
@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<File, Amenity> 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<Pair<File, Amenity>> 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<Amenity>() {
|
||||
@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<String, TravelArticle> articles = readArticles(file, amenity);
|
||||
Map<String, TravelArticle> 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<String, TravelArticle> readRoutePoint(File file, Amenity amenity) {
|
||||
Map<String, TravelArticle> 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<BinaryMapDataObject> segmentList = new ArrayList<>();
|
||||
|
||||
for (BinaryMapIndexReader reader : getReaders()) {
|
||||
try {
|
||||
if (article.file != null && !article.file.equals(reader.getFile())) {
|
||||
continue;
|
||||
}
|
||||
BinaryMapIndexReader.SearchRequest<BinaryMapDataObject> sr = BinaryMapIndexReader.buildSearchRequest(
|
||||
0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE, 15, null,
|
||||
new ResultMatcher<BinaryMapDataObject>() {
|
||||
@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<String> 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<Amenity> getPointList(@NonNull final TravelArticle article) {
|
||||
final List<Amenity> pointList = new ArrayList<>();
|
||||
|
@ -197,14 +340,14 @@ public class TravelObfHelper implements TravelHelper {
|
|||
}
|
||||
SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest(0, 0,
|
||||
Algorithms.emptyIfNull(article.title), 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE,
|
||||
getSearchFilter(true), new ResultMatcher<Amenity>() {
|
||||
getSearchFilter(ROUTE_ARTICLE_POINT), new ResultMatcher<Amenity>() {
|
||||
|
||||
@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<Amenity> searchRequest = BinaryMapIndexReader.buildSearchPoiRequest(0, 0, searchQuery,
|
||||
0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE, getSearchFilter(false), new ResultMatcher<Amenity>() {
|
||||
0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE, getSearchFilter(ROUTE_ARTICLE), new ResultMatcher<Amenity>() {
|
||||
@Override
|
||||
public boolean publish(Amenity object) {
|
||||
List<String> otherNames = object.getAllNames(false);
|
||||
|
@ -441,7 +584,7 @@ public class TravelObfHelper implements TravelHelper {
|
|||
for (BinaryMapIndexReader reader : getReaders()) {
|
||||
try {
|
||||
SearchRequest<Amenity> 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<Amenity>() {
|
||||
boolean done = false;
|
||||
|
||||
|
@ -530,12 +673,13 @@ public class TravelObfHelper implements TravelHelper {
|
|||
}
|
||||
SearchRequest<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest(0, 0,
|
||||
Algorithms.emptyIfNull(articleId.title), 0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE,
|
||||
getSearchFilter(false), new ResultMatcher<Amenity>() {
|
||||
getSearchFilter(ROUTE_ARTICLE), new ResultMatcher<Amenity>() {
|
||||
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<Amenity> req = BinaryMapIndexReader.buildSearchPoiRequest(
|
||||
x, y, title, left, right, top, bottom, getSearchFilter(false),
|
||||
x, y, title, left, right, top, bottom, getSearchFilter(ROUTE_ARTICLE),
|
||||
new ResultMatcher<Amenity>() {
|
||||
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;
|
||||
|
|
|
@ -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<RecyclerView.ViewHold
|
|||
case ArticleTravelCard.TYPE:
|
||||
return new ArticleTravelVH(inflate(parent, R.layout.wikivoyage_article_card));
|
||||
|
||||
case TravelGpxCard.TYPE:
|
||||
return new TravelGpxVH(inflate(parent, R.layout.wikivoyage_travel_gpx_card));
|
||||
|
||||
case TravelDownloadUpdateCard.TYPE:
|
||||
return new DownloadUpdateVH(inflate(parent, R.layout.travel_download_update_card));
|
||||
|
||||
|
@ -74,6 +79,10 @@ public class ExploreRvAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
|
|||
HeaderTravelCard headerTravelCard = (HeaderTravelCard) item;
|
||||
headerTravelCard.setArticleItemCount(getArticleItemCount());
|
||||
headerTravelCard.bindViewHolder(viewHolder);
|
||||
} else if (viewHolder instanceof ArticleTravelVH && item instanceof TravelGpxCard) {
|
||||
TravelGpxCard travelGpxCard = (TravelGpxCard) item;
|
||||
travelGpxCard.setLastItem(position == getLastArticleItemIndex());
|
||||
travelGpxCard.bindViewHolder(viewHolder);
|
||||
} else if (viewHolder instanceof ArticleTravelVH && item instanceof ArticleTravelCard) {
|
||||
ArticleTravelCard articleTravelCard = (ArticleTravelCard) item;
|
||||
articleTravelCard.setLastItem(position == getLastArticleItemIndex());
|
||||
|
@ -96,7 +105,7 @@ public class ExploreRvAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
|
|||
public int getArticleItemCount() {
|
||||
int count = 0;
|
||||
for (BaseTravelCard o : items) {
|
||||
if (o instanceof ArticleTravelCard) {
|
||||
if (o instanceof ArticleTravelCard || o instanceof TravelGpxCard) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
@ -106,7 +115,7 @@ public class ExploreRvAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
|
|||
private int getLastArticleItemIndex() {
|
||||
for (int i = items.size() - 1; i > 0; i--) {
|
||||
BaseTravelCard o = items.get(i);
|
||||
if (o instanceof ArticleTravelCard) {
|
||||
if (o instanceof ArticleTravelCard || o instanceof TravelGpxCard) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<TravelArticle> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<RecyclerView.ViewHolder> {
|
||||
|
||||
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<RecyclerView.Vi
|
|||
private final Drawable readIcon;
|
||||
private final Drawable deleteIcon;
|
||||
private PicassoUtils picasso;
|
||||
boolean nightMode;
|
||||
|
||||
public void setListener(Listener listener) {
|
||||
this.listener = listener;
|
||||
|
@ -54,21 +62,34 @@ public class SavedArticlesRvAdapter extends RecyclerView.Adapter<RecyclerView.Vi
|
|||
this.app = app;
|
||||
this.settings = app.getSettings();
|
||||
picasso = PicassoUtils.getPicasso(app);
|
||||
nightMode = !app.getSettings().isLightContent();
|
||||
readIcon = getActiveIcon(R.drawable.ic_action_read_article);
|
||||
deleteIcon = getActiveIcon(R.drawable.ic_action_read_later_fill);
|
||||
}
|
||||
|
||||
int colorId = settings.isLightContent()
|
||||
? R.color.wikivoyage_active_light : R.color.wikivoyage_active_dark;
|
||||
UiUtilities ic = app.getUIUtilities();
|
||||
readIcon = ic.getIcon(R.drawable.ic_action_read_article, colorId);
|
||||
deleteIcon = ic.getIcon(R.drawable.ic_action_read_later_fill, colorId);
|
||||
private Drawable getActiveIcon(@DrawableRes int iconId) {
|
||||
int colorId = nightMode ? R.color.wikivoyage_active_dark : R.color.wikivoyage_active_light;
|
||||
return app.getUIUtilities().getIcon(iconId, colorId);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
boolean header = viewType == HEADER_TYPE;
|
||||
int layoutId = header ? R.layout.wikivoyage_list_header : R.layout.wikivoyage_article_card;
|
||||
View itemView = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
|
||||
return header ? new HeaderVH(itemView) : new ItemVH(itemView);
|
||||
switch (viewType) {
|
||||
case HEADER_TYPE:
|
||||
return new HeaderVH(inflate(parent, R.layout.wikivoyage_list_header));
|
||||
case ARTICLE_TYPE:
|
||||
return new ItemVH(inflate(parent, R.layout.wikivoyage_article_card));
|
||||
case GPX_TYPE:
|
||||
return new TravelGpxCard.TravelGpxVH(inflate(parent, R.layout.wikivoyage_travel_gpx_card));
|
||||
default:
|
||||
throw new RuntimeException("Unsupported view type: " + viewType);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private View inflate(@NonNull ViewGroup parent, @LayoutRes int layoutId) {
|
||||
return LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -77,7 +98,7 @@ public class SavedArticlesRvAdapter extends RecyclerView.Adapter<RecyclerView.Vi
|
|||
final HeaderVH holder = (HeaderVH) viewHolder;
|
||||
holder.title.setText((String) getItem(position));
|
||||
holder.description.setText(String.valueOf(items.size() - 1));
|
||||
} else {
|
||||
} else if (viewHolder instanceof ItemVH) {
|
||||
final ItemVH holder = (ItemVH) viewHolder;
|
||||
TravelArticle article = (TravelArticle) getItem(position);
|
||||
final String url = TravelArticle.getImageUrl(article.getImageTitle(), false);
|
||||
|
@ -111,6 +132,52 @@ public class SavedArticlesRvAdapter extends RecyclerView.Adapter<RecyclerView.Vi
|
|||
holder.rightButton.setCompoundDrawablesWithIntrinsicBounds(null, null, deleteIcon, null);
|
||||
holder.divider.setVisibility(lastItem ? View.GONE : View.VISIBLE);
|
||||
holder.shadow.setVisibility(lastItem ? View.VISIBLE : View.GONE);
|
||||
} else if (viewHolder instanceof TravelGpxCard.TravelGpxVH) {
|
||||
final TravelGpx article = (TravelGpx) getItem(position);
|
||||
final TravelGpxCard.TravelGpxVH holder = (TravelGpxCard.TravelGpxVH) viewHolder;
|
||||
holder.title.setText(article.getTitle());
|
||||
Drawable icon = getActiveIcon(R.drawable.ic_action_user_account_16);
|
||||
holder.user.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
|
||||
holder.user.setText(WikiArticleHelper.getPartialContent(article.user));
|
||||
AndroidUtils.setBackground(app, holder.user, nightMode, R.drawable.btn_border_bg_light, R.drawable.btn_border_bg_dark);
|
||||
holder.distance.setText(OsmAndFormatter.getFormattedDistance(article.totalDistance, app));
|
||||
holder.diffElevationUp.setText(OsmAndFormatter.getFormattedAlt(article.diffElevationUp, app));
|
||||
holder.diffElevationDown.setText(OsmAndFormatter.getFormattedAlt(article.diffElevationDown, app));
|
||||
holder.leftButton.setText(app.getString(R.string.shared_string_view));
|
||||
View.OnClickListener readClickListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (listener != null) {
|
||||
listener.openArticle(article);
|
||||
}
|
||||
}
|
||||
};
|
||||
holder.leftButton.setOnClickListener(readClickListener);
|
||||
holder.itemView.setOnClickListener(readClickListener);
|
||||
holder.leftButton.setCompoundDrawablesWithIntrinsicBounds(readIcon, null, null, null);
|
||||
updateSaveButton(holder, article);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSaveButton(final TravelGpxCard.TravelGpxVH holder, final TravelGpx article) {
|
||||
if (article != null) {
|
||||
final TravelLocalDataHelper helper = app.getTravelHelper().getBookmarksHelper();
|
||||
final boolean saved = helper.isArticleSaved(article);
|
||||
Drawable icon = getActiveIcon(saved ? R.drawable.ic_action_read_later_fill : R.drawable.ic_action_read_later);
|
||||
holder.rightButton.setText(saved ? R.string.shared_string_remove : R.string.shared_string_save);
|
||||
holder.rightButton.setCompoundDrawablesWithIntrinsicBounds(null, null, icon, null);
|
||||
holder.rightButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (saved) {
|
||||
helper.removeArticleFromSaved(article);
|
||||
} else {
|
||||
app.getTravelHelper().createGpxFile(article);
|
||||
helper.addArticleToSaved(article);
|
||||
}
|
||||
updateSaveButton(holder, article);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -118,8 +185,10 @@ public class SavedArticlesRvAdapter extends RecyclerView.Adapter<RecyclerView.Vi
|
|||
public int getItemViewType(int position) {
|
||||
if (getItem(position) instanceof String) {
|
||||
return HEADER_TYPE;
|
||||
} else if (getItem(position) instanceof TravelGpx) {
|
||||
return GPX_TYPE;
|
||||
}
|
||||
return ITEM_TYPE;
|
||||
return ARTICLE_TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -8,6 +8,7 @@ import android.view.ViewGroup;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
|
@ -17,12 +18,15 @@ import net.osmand.PlatformUtil;
|
|||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.base.BaseOsmAndFragment;
|
||||
import net.osmand.plus.track.TrackMenuFragment;
|
||||
import net.osmand.plus.wikivoyage.article.WikivoyageArticleDialogFragment;
|
||||
import net.osmand.plus.wikivoyage.data.TravelArticle;
|
||||
import net.osmand.plus.wikivoyage.data.TravelGpx;
|
||||
import net.osmand.plus.wikivoyage.data.TravelLocalDataHelper;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
@ -48,9 +52,17 @@ public class SavedArticlesTabFragment extends BaseOsmAndFragment implements Trav
|
|||
adapter.setListener(new SavedArticlesRvAdapter.Listener() {
|
||||
@Override
|
||||
public void openArticle(TravelArticle article) {
|
||||
FragmentManager fm = getFragmentManager();
|
||||
if (fm != null) {
|
||||
WikivoyageArticleDialogFragment.showInstance(app, fm, article.generateIdentifier(), article.getLang());
|
||||
if (article instanceof TravelGpx) {
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity != null) {
|
||||
File file = app.getTravelHelper().createGpxFile(article);
|
||||
TrackMenuFragment.openTrack(getActivity(), file, null);
|
||||
}
|
||||
} else {
|
||||
FragmentManager fm = getFragmentManager();
|
||||
if (fm != null) {
|
||||
WikivoyageArticleDialogFragment.showInstance(app, fm, article.generateIdentifier(), article.getLang());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
package net.osmand.plus.wikivoyage.explore.travelcards;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import net.osmand.AndroidUtils;
|
||||
import net.osmand.plus.OsmAndFormatter;
|
||||
import net.osmand.plus.OsmandApplication;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.track.TrackMenuFragment;
|
||||
import net.osmand.plus.wikivoyage.data.TravelGpx;
|
||||
import net.osmand.plus.wikivoyage.data.TravelLocalDataHelper;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class TravelGpxCard extends BaseTravelCard {
|
||||
|
||||
public static final int TYPE = 3;
|
||||
|
||||
private final TravelGpx article;
|
||||
private final Drawable readIcon;
|
||||
private final FragmentActivity activity;
|
||||
private boolean isLastItem;
|
||||
|
||||
public TravelGpxCard(@NonNull OsmandApplication app, boolean nightMode, @NonNull TravelGpx article,
|
||||
@NonNull FragmentActivity activity) {
|
||||
super(app, nightMode);
|
||||
this.article = article;
|
||||
readIcon = getActiveIcon(R.drawable.ic_action_read_article);
|
||||
this.activity = activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder) {
|
||||
if (viewHolder instanceof TravelGpxVH) {
|
||||
final TravelGpxVH holder = (TravelGpxVH) viewHolder;
|
||||
holder.title.setText(article.getTitle());
|
||||
Drawable icon = getActiveIcon(R.drawable.ic_action_user_account_16);
|
||||
holder.user.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
|
||||
holder.user.setText(article.user);
|
||||
AndroidUtils.setBackground(app, holder.user, nightMode, R.drawable.btn_border_bg_light, R.drawable.btn_border_bg_dark);
|
||||
holder.distance.setText(OsmAndFormatter.getFormattedDistance(article.totalDistance, app));
|
||||
holder.diffElevationUp.setText(OsmAndFormatter.getFormattedAlt(article.diffElevationUp, app));
|
||||
holder.diffElevationDown.setText(OsmAndFormatter.getFormattedAlt(article.diffElevationDown, app));
|
||||
holder.leftButton.setText(app.getString(R.string.shared_string_view));
|
||||
View.OnClickListener readClickListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (activity != null) {
|
||||
File file = app.getTravelHelper().createGpxFile(article);
|
||||
TrackMenuFragment.openTrack(activity, file, null);
|
||||
}
|
||||
}
|
||||
};
|
||||
holder.leftButton.setOnClickListener(readClickListener);
|
||||
holder.itemView.setOnClickListener(readClickListener);
|
||||
holder.leftButton.setCompoundDrawablesWithIntrinsicBounds(readIcon, null, null, null);
|
||||
updateSaveButton(holder);
|
||||
holder.divider.setVisibility(isLastItem ? View.GONE : View.VISIBLE);
|
||||
holder.shadow.setVisibility(isLastItem ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSaveButton(final TravelGpxVH holder) {
|
||||
if (article != null) {
|
||||
final TravelLocalDataHelper helper = app.getTravelHelper().getBookmarksHelper();
|
||||
final boolean saved = helper.isArticleSaved(article);
|
||||
Drawable icon = getActiveIcon(saved ? R.drawable.ic_action_read_later_fill : R.drawable.ic_action_read_later);
|
||||
holder.rightButton.setText(saved ? R.string.shared_string_remove : R.string.shared_string_save);
|
||||
holder.rightButton.setCompoundDrawablesWithIntrinsicBounds(null, null, icon, null);
|
||||
holder.rightButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (saved) {
|
||||
helper.removeArticleFromSaved(article);
|
||||
} else {
|
||||
app.getTravelHelper().createGpxFile(article);
|
||||
helper.addArticleToSaved(article);
|
||||
}
|
||||
updateSaveButton(holder);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public static class TravelGpxVH extends RecyclerView.ViewHolder {
|
||||
|
||||
public final TextView title;
|
||||
public final TextView user;
|
||||
public final TextView distance;
|
||||
public final TextView diffElevationUp;
|
||||
public final TextView diffElevationDown;
|
||||
public final TextView leftButton;
|
||||
public final TextView rightButton;
|
||||
public final View divider;
|
||||
public final View shadow;
|
||||
|
||||
public TravelGpxVH(final View itemView) {
|
||||
super(itemView);
|
||||
title = itemView.findViewById(R.id.title);
|
||||
user = itemView.findViewById(R.id.user_name);
|
||||
distance = itemView.findViewById(R.id.distance);
|
||||
diffElevationUp = itemView.findViewById(R.id.diff_ele_up);
|
||||
diffElevationDown = itemView.findViewById(R.id.diff_ele_down);
|
||||
leftButton = itemView.findViewById(R.id.left_button);
|
||||
rightButton = itemView.findViewById(R.id.right_button);
|
||||
divider = itemView.findViewById(R.id.divider);
|
||||
shadow = itemView.findViewById(R.id.shadow);
|
||||
}
|
||||
}
|
||||
|
||||
public void setLastItem(boolean lastItem) {
|
||||
isLastItem = lastItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCardType() {
|
||||
return TYPE;
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue