Travel GPX card

This commit is contained in:
Dima-1 2021-01-24 23:48:41 +02:00
parent fd76a4054f
commit f1569fd5fb
6 changed files with 392 additions and 3 deletions

View file

@ -273,6 +273,10 @@ public class Amenity extends MapObject {
return null; return null;
} }
public String getTagContent(String tag) {
return getTagContent(tag, null);
}
public String getTagContent(String tag, String lang) { public String getTagContent(String tag, String lang) {
if (lang != null) { if (lang != null) {
String translateName = getAdditionalInfo(tag + ":" + lang); String translateName = getAdditionalInfo(tag + ":" + lang);

View file

@ -0,0 +1,242 @@
<?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:layout_marginTop="@dimen/content_padding_small"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginEnd="@dimen/content_padding"
android:background="?attr/wikivoyage_travel_card_bg">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:orientation="vertical"
android:paddingBottom="@dimen/bottom_sheet_content_padding_small"
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"/>
<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_distance_16"
android:tint="@color/icon_color_default_light"
android:contentDescription="@string/distance" />
<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_distance_16"
android:tint="@color/icon_color_default_light"
android:contentDescription="@string/distance" />
</LinearLayout>
<TextView
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="3"
android:textAppearance="@style/TextAppearance.ContextMenuSubtitle"
android:textColor="@null"
tools:text="Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard." />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<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/context_menu_padding_margin_tiny"
android:paddingLeft="@dimen/bottom_sheet_content_padding_small"
android:paddingRight="@dimen/bottom_sheet_content_padding_small"
android:paddingTop="@dimen/context_menu_padding_margin_tiny"
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/context_menu_padding_margin_tiny"
android:paddingLeft="@dimen/bottom_sheet_content_padding_small"
android:paddingRight="@dimen/bottom_sheet_content_padding_small"
android:paddingTop="@dimen/context_menu_padding_margin_tiny"
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>

View file

@ -0,0 +1,8 @@
package net.osmand.plus.wikivoyage.data;
public class TravelGpx extends TravelArticle {
public String user;
public float totalDistance = 0;
public double diffElevationUp = 0;
public double diffElevationDown = 0;
}

View 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.StartEditingTravelCard.StartEditingTravelVH;
import net.osmand.plus.wikivoyage.explore.travelcards.TravelDownloadUpdateCard; import net.osmand.plus.wikivoyage.explore.travelcards.TravelDownloadUpdateCard;
import net.osmand.plus.wikivoyage.explore.travelcards.TravelDownloadUpdateCard.DownloadUpdateVH; 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;
import net.osmand.plus.wikivoyage.explore.travelcards.TravelNeededMapsCard.NeededMapsVH; import net.osmand.plus.wikivoyage.explore.travelcards.TravelNeededMapsCard.NeededMapsVH;
@ -48,6 +50,9 @@ public class ExploreRvAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
case ArticleTravelCard.TYPE: case ArticleTravelCard.TYPE:
return new ArticleTravelVH(inflate(parent, R.layout.wikivoyage_article_card)); 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: case TravelDownloadUpdateCard.TYPE:
return new DownloadUpdateVH(inflate(parent, R.layout.travel_download_update_card)); 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 headerTravelCard = (HeaderTravelCard) item;
headerTravelCard.setArticleItemCount(getArticleItemCount()); headerTravelCard.setArticleItemCount(getArticleItemCount());
headerTravelCard.bindViewHolder(viewHolder); 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) { } else if (viewHolder instanceof ArticleTravelVH && item instanceof ArticleTravelCard) {
ArticleTravelCard articleTravelCard = (ArticleTravelCard) item; ArticleTravelCard articleTravelCard = (ArticleTravelCard) item;
articleTravelCard.setLastItem(position == getLastArticleItemIndex()); articleTravelCard.setLastItem(position == getLastArticleItemIndex());
@ -96,7 +105,7 @@ public class ExploreRvAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
public int getArticleItemCount() { public int getArticleItemCount() {
int count = 0; int count = 0;
for (BaseTravelCard o : items) { for (BaseTravelCard o : items) {
if (o instanceof ArticleTravelCard) { if (o instanceof ArticleTravelCard || o instanceof TravelGpxCard) {
count++; count++;
} }
} }
@ -106,7 +115,7 @@ public class ExploreRvAdapter extends RecyclerView.Adapter<RecyclerView.ViewHold
private int getLastArticleItemIndex() { private int getLastArticleItemIndex() {
for (int i = items.size() - 1; i > 0; i--) { for (int i = items.size() - 1; i > 0; i--) {
BaseTravelCard o = items.get(i); BaseTravelCard o = items.get(i);
if (o instanceof ArticleTravelCard) { if (o instanceof ArticleTravelCard || o instanceof TravelGpxCard) {
return i; return i;
} }
} }

View file

@ -28,6 +28,7 @@ import net.osmand.plus.download.DownloadResources;
import net.osmand.plus.download.DownloadValidationManager; import net.osmand.plus.download.DownloadValidationManager;
import net.osmand.plus.download.IndexItem; import net.osmand.plus.download.IndexItem;
import net.osmand.plus.wikivoyage.data.TravelArticle; 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.TravelHelper;
import net.osmand.plus.wikivoyage.data.TravelLocalDataHelper; import net.osmand.plus.wikivoyage.data.TravelLocalDataHelper;
import net.osmand.plus.wikivoyage.explore.travelcards.ArticleTravelCard; import net.osmand.plus.wikivoyage.explore.travelcards.ArticleTravelCard;
@ -36,6 +37,7 @@ import net.osmand.plus.wikivoyage.explore.travelcards.HeaderTravelCard;
import net.osmand.plus.wikivoyage.explore.travelcards.OpenBetaTravelCard; import net.osmand.plus.wikivoyage.explore.travelcards.OpenBetaTravelCard;
import net.osmand.plus.wikivoyage.explore.travelcards.StartEditingTravelCard; import net.osmand.plus.wikivoyage.explore.travelcards.StartEditingTravelCard;
import net.osmand.plus.wikivoyage.explore.travelcards.TravelDownloadUpdateCard; 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 net.osmand.plus.wikivoyage.explore.travelcards.TravelNeededMapsCard;
import java.io.IOException; import java.io.IOException;
@ -183,7 +185,11 @@ public class ExploreTabFragment extends BaseOsmAndFragment implements DownloadEv
List<TravelArticle> popularArticles = app.getTravelHelper().getPopularArticles(); List<TravelArticle> popularArticles = app.getTravelHelper().getPopularArticles();
for (TravelArticle article : popularArticles) { for (TravelArticle article : popularArticles) {
items.add(new ArticleTravelCard(app, nightMode, article, fm)); if (article instanceof TravelGpx) {
items.add(new TravelGpxCard(app, nightMode, (TravelGpx) article, fm));
} else {
items.add(new ArticleTravelCard(app, nightMode, article, fm));
}
} }
} }
} }

View file

@ -0,0 +1,120 @@
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.FragmentManager;
import androidx.recyclerview.widget.RecyclerView;
import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.wikipedia.WikiArticleHelper;
import net.osmand.plus.wikivoyage.article.WikivoyageArticleDialogFragment;
import net.osmand.plus.wikivoyage.data.TravelGpx;
import net.osmand.plus.wikivoyage.data.TravelLocalDataHelper;
public class TravelGpxCard extends BaseTravelCard {
public static final int TYPE = 3;
private final TravelGpx article;
private final Drawable readIcon;
private final FragmentManager fragmentManager;
private boolean isLastItem;
public TravelGpxCard(@NonNull OsmandApplication app, boolean nightMode, @NonNull TravelGpx article,
@NonNull FragmentManager fragmentManager) {
super(app, nightMode);
this.article = article;
readIcon = getActiveIcon(R.drawable.ic_action_read_article);
this.fragmentManager = fragmentManager;
}
@Override
public void bindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder) {
if (viewHolder instanceof TravelGpxVH) {
final TravelGpxVH holder = (TravelGpxVH) viewHolder;
holder.title.setText(article.getTitle());
holder.content.setText(WikiArticleHelper.getPartialContent(article.getContent()));
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 (fragmentManager != null) {
WikivoyageArticleDialogFragment.showInstance(app, fragmentManager,
article.generateIdentifier(), article.getLang());
}
}
};
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 {
final TextView title;
final TextView content;
final TextView distance;
final TextView diffElevationUp;
final TextView diffElevationDown;
final TextView leftButton;
final TextView rightButton;
final View divider;
final View shadow;
public TravelGpxVH(final View itemView) {
super(itemView);
title = itemView.findViewById(R.id.title);
content = itemView.findViewById(R.id.content);
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;
}
}