add adapter and popular destinations

This commit is contained in:
Chumva 2018-04-24 19:51:06 +03:00
parent 3d3b9fb9f3
commit 91115b90d4
11 changed files with 448 additions and 28 deletions

View file

@ -2,25 +2,30 @@
<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="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="@dimen/list_content_padding"
android:layout_marginTop="@dimen/list_content_padding"
android:background="@drawable/travel_card_bg">
android:layout_marginLeft="@dimen/text_margin_small"
android:layout_marginRight="@dimen/text_margin_small"
android:background="@drawable/travel_card_bg"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="@dimen/wikivoyage_explore_card_image_height"
android:layout_gravity="center_horizontal"
android:orientation="vertical">
android:orientation="vertical"
android:background="@color/wikivoyage_open_beta_card_image_background">
<ImageView
android:id="@+id/background_image"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="@string/welcome_to_open_beta"
tools:src="@drawable/img_help_wikivoyage_articles" />
</LinearLayout>
<TextView
android:id="@+id/title"
@ -53,7 +58,7 @@
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/bottom_button_text"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_sheet_title_height"
android:layout_gravity="center"
android:background="?attr/selectableItemBackground"
@ -63,6 +68,5 @@
osmand:typeface="@string/font_roboto_medium"
tools:text="@string/get_unlimited_access" />
</LinearLayout>
</LinearLayout>

View file

@ -2,11 +2,13 @@
<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="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="@dimen/list_content_padding"
android:layout_marginTop="@dimen/list_content_padding"
android:layout_marginLeft="@dimen/text_margin_small"
android:layout_marginRight="@dimen/text_margin_small"
android:background="@drawable/travel_card_bg">
<LinearLayout
@ -16,9 +18,9 @@
android:orientation="vertical">
<LinearLayout
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/wikivoyage_start_editing_image_background"
android:background="@color/wikivoyage_start_editing_card_image_background"
android:orientation="horizontal">
<TextView
@ -64,7 +66,7 @@
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/bottom_button_text"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="@dimen/bottom_sheet_title_height"
android:layout_gravity="center"
android:gravity="center"

View file

@ -207,4 +207,5 @@
<dimen name="wikivoyage_search_icon_margin_left">21dp</dimen>
<dimen name="wikivoyage_search_icon_margin_right">33dp</dimen>
<dimen name="wikivoyage_search_divider_margin_start">82dp</dimen>
<dimen name="wikivoyage_explore_card_image_height">216dp</dimen>
</resources>

View file

@ -428,6 +428,7 @@
<color name="wikivoyage_primary_text_light">#212121</color>
<color name="wikivoyage_primary_text_dark">#cccccc</color>
<color name="wikivoyage_secondary_text">#727272</color>
<color name="wikivoyage_start_editing_image_background">#339966</color>
<color name="wikivoyage_start_editing_card_image_background">#339966</color>
<color name="wikivoyage_open_beta_card_image_background">#008bf8</color>
</resources>

View file

@ -9,6 +9,7 @@
3. All your modified/created strings are in the top of the file (to make easier find what\'s translated).
PLEASE: Have a look at http://code.google.com/p/osmand/wiki/UIConsistency, it may really improve your and our work :-) Thx - Hardy
-->
<string name="popular_destinations">Popular destinations</string>
<string name="start_editing_card_image_text">The free worldwide travel guide that anyone can edit.</string>
<string name="welcome_to_open_beta_description">Travel is based on Wikivoyage. During open beta testing you have the opportunity to evaluate all the features for free. After the end of the beta period, Travel will be available to subscribers of OsmAnd Unlimited and the owners of OsmAnd+</string>
<string name="start_editing_card_description">You can edit any article on Wikivoyage, and we hope that you do. We need your knowledge, your experience, your talent, and your attention</string>

View file

@ -70,6 +70,9 @@ public class TravelDbHelper {
ARTICLES_COL_AGGREGATED_PART_OF +
" FROM " + ARTICLES_TABLE_NAME;
private static final String POPULAR_ARTICLES_TABLE_SELECT = "SELECT *" +
" FROM " + ARTICLES_TABLE_NAME + " ORDER BY RANDOM() LIMIT 100";
private static final String SEARCH_TABLE_NAME = "wikivoyage_search";
private static final String SEARCH_COL_SEARCH_TERM = "search_term";
private static final String SEARCH_COL_CITY_ID = "city_id";
@ -199,6 +202,24 @@ public class TravelDbHelper {
return list;
}
@NonNull
public List<TravelArticle> searchPopular() {
List<TravelArticle> res = new ArrayList<>();
SQLiteConnection conn = openConnection();
if (conn != null) {
TravelArticle travelArticle;
SQLiteCursor cursor = conn.rawQuery(POPULAR_ARTICLES_TABLE_SELECT, null);
if (cursor.moveToFirst()) {
do {
travelArticle = readArticle(cursor);
res.add(travelArticle);
} while (cursor.moveToNext());
}
cursor.close();
}
return res;
}
private void sortSearchResults(final String searchQuery, List<WikivoyageSearchResult> list) {
Collections.sort(list, new Comparator<WikivoyageSearchResult>() {
@Override

View file

@ -0,0 +1,224 @@
package net.osmand.plus.wikivoyage.explore;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.Snackbar;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.squareup.picasso.Callback;
import com.squareup.picasso.Picasso;
import com.squareup.picasso.RequestCreator;
import net.osmand.AndroidUtils;
import net.osmand.plus.IconsCache;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.widgets.tools.CropCircleTransformation;
import net.osmand.plus.widgets.tools.CropRectTransformation;
import net.osmand.plus.wikivoyage.WikivoyageUtils;
import net.osmand.plus.wikivoyage.data.TravelArticle;
import net.osmand.plus.wikivoyage.data.TravelLocalDataHelper;
import net.osmand.plus.wikivoyage.explore.travelcards.ArticleTravelCard;
import net.osmand.plus.wikivoyage.explore.travelcards.OpenBetaTravelCard;
import net.osmand.plus.wikivoyage.explore.travelcards.StartEditingTravelCard;
import java.util.ArrayList;
import java.util.List;
public class ExploreRvAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private static final int HEADER_TYPE = 3;
private static final int ITEM_TYPE = 4;
private final OsmandSettings settings;
private final List<Object> items = new ArrayList<>();
private ExploreRvAdapter.Listener listener;
OsmandApplication app;
private final Drawable readIcon;
private final Drawable deleteIcon;
public void setListener(ExploreRvAdapter.Listener listener) {
this.listener = listener;
}
ExploreRvAdapter(OsmandApplication app) {
this.app = app;
this.settings = app.getSettings();
int colorId = settings.isLightContent()
? R.color.wikivoyage_active_light : R.color.wikivoyage_active_dark;
IconsCache ic = app.getIconsCache();
readIcon = ic.getIcon(R.drawable.ic_action_read_article, colorId);
deleteIcon = ic.getIcon(R.drawable.ic_action_read_later_fill, colorId);
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
boolean header = viewType == HEADER_TYPE;
RecyclerView.ViewHolder holder = null;
View itemView = null;
int layoutId = 0;
if (viewType == OpenBetaTravelCard.TYPE) {
layoutId = R.layout.wikivoyage_open_beta_card;
itemView = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
return new OpenBetaTravelCard.OpenBetaTravelVH(itemView);
}
if (viewType == StartEditingTravelCard.TYPE) {
layoutId = R.layout.wikivoyage_start_editing_card;
itemView = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
return new StartEditingTravelCard.StartEditingTravelVH(itemView);
}
if (viewType == ArticleTravelCard.TYPE) {
layoutId = ArticleTravelCard.USE_ALTERNATIVE_CARD ? R.layout.wikivoyage_article_card_alternative : R.layout.wikivoyage_article_card;
itemView = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
return new ArticleTravelCard.ArticleTravelVH(itemView);
}
if (viewType == HEADER_TYPE) {
layoutId = R.layout.wikivoyage_list_header;
itemView = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
return new HeaderVH(itemView);
}
return null;
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
if (viewHolder instanceof HeaderVH) {
final HeaderVH holder = (HeaderVH) viewHolder;
holder.title.setText((String) getItem(position));
holder.description.setText(String.valueOf(items.size() - 3));
} else if (viewHolder instanceof ArticleTravelCard.ArticleTravelVH) {
if (getItem(position) instanceof ArticleTravelCard) {
ArticleTravelCard articleTravelCard = (ArticleTravelCard) getItem(position);
articleTravelCard.bindViewHolder(viewHolder);
}
} else if (viewHolder instanceof OpenBetaTravelCard.OpenBetaTravelVH) {
if (getItem(position) instanceof OpenBetaTravelCard) {
OpenBetaTravelCard openBetaTravelCard = (OpenBetaTravelCard) getItem(position);
openBetaTravelCard.bindViewHolder(viewHolder);
}
} else if (viewHolder instanceof StartEditingTravelCard.StartEditingTravelVH) {
if (getItem(position) instanceof StartEditingTravelCard) {
StartEditingTravelCard startEditingTravelCard = (StartEditingTravelCard) getItem(position);
startEditingTravelCard.bindViewHolder(viewHolder);
}
}
}
@Override
public int getItemViewType(int position) {
if (getItem(position) instanceof String) {
return HEADER_TYPE;
}
if (getItem(position) instanceof OpenBetaTravelCard) {
return ((OpenBetaTravelCard) getItem(position)).getCardType();
}
if (getItem(position) instanceof StartEditingTravelCard) {
return ((StartEditingTravelCard) getItem(position)).getCardType();
}
if (getItem(position) instanceof ArticleTravelCard) {
return ((ArticleTravelCard) getItem(position)).getCardType();
}
return -1;
}
@Override
public int getItemCount() {
return items.size();
}
private Object getItem(int position) {
return items.get(position);
}
@NonNull
public List<Object> getItems() {
return items;
}
public void setItems(List<Object> items) {
this.items.clear();
this.items.addAll(items);
}
static class HeaderVH extends RecyclerView.ViewHolder {
final TextView title;
final TextView description;
HeaderVH(View itemView) {
super(itemView);
title = (TextView) itemView.findViewById(R.id.title);
description = (TextView) itemView.findViewById(R.id.description);
}
}
class ItemVH extends RecyclerView.ViewHolder {
final TextView title;
final TextView content;
final TextView partOf;
final ImageView icon;
final TextView leftButton;
final TextView rightButton;
final View divider;
final View shadow;
ItemVH(final View itemView) {
super(itemView);
title = (TextView) itemView.findViewById(R.id.title);
content = (TextView) itemView.findViewById(R.id.content);
partOf = (TextView) itemView.findViewById(R.id.part_of);
icon = (ImageView) itemView.findViewById(R.id.icon);
leftButton = (TextView) itemView.findViewById(R.id.left_button);
rightButton = (TextView) itemView.findViewById(R.id.right_button);
divider = itemView.findViewById(R.id.divider);
shadow = itemView.findViewById(R.id.shadow);
View.OnClickListener readClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
Object item = getItemByPosition();
if (item != null && item instanceof TravelArticle) {
if (listener != null) {
listener.openArticle((TravelArticle) item);
}
}
}
};
itemView.setOnClickListener(readClickListener);
leftButton.setOnClickListener(readClickListener);
rightButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
}
});
}
@Nullable
private Object getItemByPosition() {
int pos = getAdapterPosition();
if (pos != RecyclerView.NO_POSITION) {
return getItem(pos);
}
return null;
}
}
interface Listener {
void openArticle(TravelArticle article);
}
}

View file

@ -3,41 +3,69 @@ package net.osmand.plus.wikivoyage.explore;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.base.BaseOsmAndFragment;
import net.osmand.plus.wikivoyage.explore.travelcards.BaseTravelCard;
import net.osmand.plus.wikivoyage.article.WikivoyageArticleDialogFragment;
import net.osmand.plus.wikivoyage.data.TravelArticle;
import net.osmand.plus.wikivoyage.explore.travelcards.ArticleTravelCard;
import net.osmand.plus.wikivoyage.explore.travelcards.OpenBetaTravelCard;
import net.osmand.plus.wikivoyage.explore.travelcards.StartEditingTravelCard;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class ExploreTabFragment extends BaseOsmAndFragment {
boolean nightMode;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
OsmandApplication app = getMyApplication();
boolean nightMode = !getSettings().isLightContent();
final OsmandApplication app = getMyApplication();
nightMode = !getSettings().isLightContent();
final View mainView = inflater.inflate(R.layout.fragment_explore_tab, container, false);
ArrayList<BaseTravelCard> items = new ArrayList<>();
OpenBetaTravelCard openBetaTravelCard = new OpenBetaTravelCard(app, nightMode, getFragmentManager());
StartEditingTravelCard startEditingTravelCard = new StartEditingTravelCard(app, nightMode);
items.add(openBetaTravelCard);
items.add(startEditingTravelCard);
ExploreRvAdapter adapter = new ExploreRvAdapter(app);
adapter.setListener(new ExploreRvAdapter.Listener() {
@Override
public void openArticle(TravelArticle article) {
FragmentManager fm = getFragmentManager();
if (fm != null) {
WikivoyageArticleDialogFragment.showInstance(app, fm, article.getCityId(), article.getLang());
}
}
});
final RecyclerView rv = (RecyclerView) mainView.findViewById(R.id.recycler_view);
rv.setLayoutManager(new LinearLayoutManager(getContext()));
adapter.setItems(getItems());
rv.setAdapter(adapter);
return mainView;
}
private List<Object> getItems() {
List<Object> items = new LinkedList<>();
List<TravelArticle> savedArticles = getMyApplication().getTravelDbHelper().searchPopular();
if (!savedArticles.isEmpty()) {
items.add(new OpenBetaTravelCard(getMyApplication(), nightMode, getFragmentManager()));
items.add(new StartEditingTravelCard(getMyApplication(), nightMode));
items.add(getString(R.string.popular_destinations));
for (TravelArticle article : savedArticles) {
items.add(new ArticleTravelCard(getMyApplication(), nightMode, article, getFragmentManager()));
}
}
return items;
}
}

View file

@ -0,0 +1,134 @@
package net.osmand.plus.wikivoyage.explore.travelcards;
import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.squareup.picasso.Callback;
import com.squareup.picasso.Picasso;
import com.squareup.picasso.RequestCreator;
import net.osmand.plus.IconsCache;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.widgets.tools.CropCircleTransformation;
import net.osmand.plus.widgets.tools.CropRectTransformation;
import net.osmand.plus.wikivoyage.WikivoyageUtils;
import net.osmand.plus.wikivoyage.article.WikivoyageArticleDialogFragment;
import net.osmand.plus.wikivoyage.data.TravelArticle;
import net.osmand.plus.wikivoyage.data.TravelLocalDataHelper;
public class ArticleTravelCard extends BaseTravelCard {
public static final int TYPE = 2;
public static final boolean USE_ALTERNATIVE_CARD = false;
private TravelArticle article;
private final Drawable readIcon;
private FragmentManager fragmentManager;
public ArticleTravelCard(OsmandApplication app, boolean nightMode, TravelArticle article, FragmentManager fragmentManager) {
super(app, nightMode);
this.article = article;
int colorId = app.getSettings().isLightContent()
? R.color.wikivoyage_active_light : R.color.wikivoyage_active_dark;
IconsCache ic = app.getIconsCache();
readIcon = ic.getIcon(R.drawable.ic_action_read_article, colorId);
this.fragmentManager = fragmentManager;
}
@Override
public void bindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder) {
if (viewHolder instanceof ArticleTravelVH) {
final ArticleTravelVH holder = (ArticleTravelVH) viewHolder;
RequestCreator rc = Picasso.get()
.load(TravelArticle.getImageUrl(article.getImageTitle(), false));
WikivoyageUtils.setupNetworkPolicy(app.getSettings(), rc);
rc.transform(USE_ALTERNATIVE_CARD ? new CropRectTransformation() : new CropCircleTransformation())
.into(holder.icon, new Callback() {
@Override
public void onSuccess() {
holder.icon.setVisibility(View.VISIBLE);
}
@Override
public void onError(Exception e) {
holder.icon.setVisibility(View.GONE);
}
});
holder.title.setText(article.getTitle());
holder.content.setText(article.getPartialContent());
holder.partOf.setText(article.getGeoDescription());
holder.leftButton.setText(app.getString(R.string.shared_string_read));
View.OnClickListener readClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
if (fragmentManager != null) {
WikivoyageArticleDialogFragment.showInstance(app, fragmentManager, article.getCityId(), article.getLang());
}
}
};
holder.leftButton.setOnClickListener(readClickListener);
holder.itemView.setOnClickListener(readClickListener);
holder.leftButton.setCompoundDrawablesWithIntrinsicBounds(readIcon, null, null, null);
updateSaveButton(holder);
}
}
private void updateSaveButton(final ArticleTravelVH holder) {
if (article != null) {
final TravelLocalDataHelper helper = app.getTravelDbHelper().getLocalDataHelper();
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_delete : 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 (article != null) {
if (saved) {
helper.removeArticleFromSaved(article);
} else {
app.getTravelDbHelper().createGpxFile(article);
helper.addArticleToSaved(article);
}
updateSaveButton(holder);
}
}
});
}
}
public static class ArticleTravelVH extends RecyclerView.ViewHolder {
final TextView title;
final TextView content;
final TextView partOf;
final ImageView icon;
final TextView leftButton;
final TextView rightButton;
final View divider;
final View shadow;
public ArticleTravelVH(final View itemView) {
super(itemView);
title = (TextView) itemView.findViewById(R.id.title);
content = (TextView) itemView.findViewById(R.id.content);
partOf = (TextView) itemView.findViewById(R.id.part_of);
icon = (ImageView) itemView.findViewById(R.id.icon);
leftButton = (TextView) itemView.findViewById(R.id.left_button);
rightButton = (TextView) itemView.findViewById(R.id.right_button);
divider = itemView.findViewById(R.id.divider);
shadow = itemView.findViewById(R.id.shadow);
}
}
@Override
public int getCardType() {
return TYPE;
}
}

View file

@ -13,6 +13,8 @@ import net.osmand.plus.dialogs.ChoosePlanDialogFragment;
public class OpenBetaTravelCard extends BaseTravelCard {
public static final int TYPE = 0;
private FragmentManager fragmentManager;
public OpenBetaTravelCard(OsmandApplication app, boolean nightMode, FragmentManager fragmentManager) {
@ -37,14 +39,14 @@ public class OpenBetaTravelCard extends BaseTravelCard {
}
}
class OpenBetaTravelVH extends RecyclerView.ViewHolder {
public static class OpenBetaTravelVH extends RecyclerView.ViewHolder {
final TextView title;
final TextView description;
final TextView button;
final ImageView backgroundImage;
OpenBetaTravelVH(final View itemView) {
public OpenBetaTravelVH(final View itemView) {
super(itemView);
title = (TextView) itemView.findViewById(R.id.title);
description = (TextView) itemView.findViewById(R.id.description);
@ -55,6 +57,6 @@ public class OpenBetaTravelCard extends BaseTravelCard {
@Override
public int getCardType() {
return 0;
return TYPE;
}
}

View file

@ -14,6 +14,8 @@ import net.osmand.plus.R;
public class StartEditingTravelCard extends BaseTravelCard {
public static final int TYPE = 1;
public StartEditingTravelCard(OsmandApplication app, boolean nightMode) {
super(app, nightMode);
}
@ -39,14 +41,14 @@ public class StartEditingTravelCard extends BaseTravelCard {
}
}
class StartEditingTravelVH extends RecyclerView.ViewHolder {
public static class StartEditingTravelVH extends RecyclerView.ViewHolder {
final TextView title;
final TextView description;
final TextView button;
final ImageView backgroundImage;
StartEditingTravelVH(final View itemView) {
public StartEditingTravelVH(final View itemView) {
super(itemView);
title = (TextView) itemView.findViewById(R.id.title);
description = (TextView) itemView.findViewById(R.id.description);
@ -57,6 +59,6 @@ public class StartEditingTravelCard extends BaseTravelCard {
@Override
public int getCardType() {
return 1;
return TYPE;
}
}