diff --git a/OsmAnd-java/src/net/osmand/map/TileSourceManager.java b/OsmAnd-java/src/net/osmand/map/TileSourceManager.java index 41fb30dbd1..1d296911df 100644 --- a/OsmAnd-java/src/net/osmand/map/TileSourceManager.java +++ b/OsmAnd-java/src/net/osmand/map/TileSourceManager.java @@ -43,6 +43,10 @@ public class TileSourceManager { private static final TileSourceTemplate MAPILLARY_SOURCE = new TileSourceTemplate("Mapillary (raster tiles)", "https://d6a1v2w10ny40.cloudfront.net/v0.1/{0}/{1}/{2}.png", ".png", 17, 0, 256, 16, 32000); + static { + MAPILLARY_SOURCE.setExpirationTimeMinutes(60 * 24); + } + public static class TileSourceTemplate implements ITileSource, Cloneable { private int maxZoom; private int minZoom; diff --git a/OsmAnd/res/layout/mapillary_context_menu_image.xml b/OsmAnd/res/layout/context_menu_card_image.xml similarity index 80% rename from OsmAnd/res/layout/mapillary_context_menu_image.xml rename to OsmAnd/res/layout/context_menu_card_image.xml index 8b4f5c063f..41bc934e91 100644 --- a/OsmAnd/res/layout/mapillary_context_menu_image.xml +++ b/OsmAnd/res/layout/context_menu_card_image.xml @@ -2,8 +2,8 @@ + android:visibility="gone" + tools:src="@drawable/ic_action_photo_dark" + tools:visibility="visible"/> + android:visibility="gone" + tools:text="\@user123" + tools:visibility="visible"/> diff --git a/OsmAnd/res/layout/mapillary_context_menu_action.xml b/OsmAnd/res/layout/mapillary_context_menu_action.xml index 3079aab73b..ccfc6399fa 100644 --- a/OsmAnd/res/layout/mapillary_context_menu_action.xml +++ b/OsmAnd/res/layout/mapillary_context_menu_action.xml @@ -1,8 +1,8 @@ diff --git a/OsmAnd/res/values/dimens.xml b/OsmAnd/res/values/dimens.xml index ba24b50938..509f5371fa 100644 --- a/OsmAnd/res/values/dimens.xml +++ b/OsmAnd/res/values/dimens.xml @@ -11,7 +11,7 @@ 200dp 100dp - 280dp - 160dp + 280dp + 160dp \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/OsmandSettings.java b/OsmAnd/src/net/osmand/plus/OsmandSettings.java index 26411794ee..b46f8914f3 100644 --- a/OsmAnd/src/net/osmand/plus/OsmandSettings.java +++ b/OsmAnd/src/net/osmand/plus/OsmandSettings.java @@ -895,6 +895,7 @@ public class OsmandSettings { public final OsmandPreference SHOW_MAPILLARY = new BooleanPreference("show_mapillary", false).makeGlobal(); public final OsmandPreference MAPILLARY_FIRST_DIALOG_SHOWN = new BooleanPreference("mapillary_first_dialog_shown", false).makeGlobal(); + public final OsmandPreference MAPILLARY_MENU_COLLAPSED = new BooleanPreference("mapillary_menu_collapsed", false).makeGlobal(); // this value string is synchronized with settings_pref.xml preference name public final OsmandPreference PREFERRED_LOCALE = new StringPreference("preferred_locale", "").makeGlobal(); diff --git a/OsmAnd/src/net/osmand/plus/Version.java b/OsmAnd/src/net/osmand/plus/Version.java index d30d0f16f4..57f97bd74b 100644 --- a/OsmAnd/src/net/osmand/plus/Version.java +++ b/OsmAnd/src/net/osmand/plus/Version.java @@ -93,7 +93,12 @@ public class Version { public static boolean isFreeVersion(OsmandApplication ctx){ return ctx.getPackageName().equals(FREE_VERSION_NAME) || ctx.getPackageName().equals(FREE_DEV_VERSION_NAME); - + } + + public static boolean isPaidVersion(OsmandApplication ctx) { + return !isFreeVersion(ctx) + || ctx.getSettings().FULL_VERSION_PURCHASED.get() + || ctx.getSettings().LIVE_UPDATES_PURCHASED.get(); } public static boolean isDeveloperVersion(OsmandApplication ctx){ diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/MenuBuilder.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/MenuBuilder.java index 45174a3ffd..3e29a913c9 100644 --- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/MenuBuilder.java +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/MenuBuilder.java @@ -7,6 +7,7 @@ import android.content.res.Resources; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; import android.net.Uri; +import android.support.annotation.NonNull; import android.support.v7.view.ContextThemeWrapper; import android.support.v7.widget.AppCompatButton; import android.text.ClipboardManager; @@ -32,6 +33,7 @@ import net.osmand.osm.PoiCategory; import net.osmand.plus.IconsCache; import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandPlugin; +import net.osmand.plus.OsmandSettings.OsmandPreference; import net.osmand.plus.R; import net.osmand.plus.activities.MapActivity; import net.osmand.plus.render.RenderingIcons; @@ -66,13 +68,19 @@ public class MenuBuilder { private String text; private boolean needLinks; private boolean url; + private boolean collapsable; + private CollapsableView collapsableView; private OnClickListener onClickListener; - public PlainMenuItem(int iconId, String text, boolean needLinks, boolean url, OnClickListener onClickListener) { + public PlainMenuItem(int iconId, String text, boolean needLinks, boolean url, + boolean collapsable, CollapsableView collapsableView, + OnClickListener onClickListener) { this.iconId = iconId; this.text = text; this.needLinks = needLinks; this.url = url; + this.collapsable = collapsable; + this.collapsableView = collapsableView; this.onClickListener = onClickListener; } @@ -92,25 +100,82 @@ public class MenuBuilder { return url; } + public boolean isCollapsable() { + return collapsable; + } + + public CollapsableView getCollapsableView() { + return collapsableView; + } + public OnClickListener getOnClickListener() { return onClickListener; } } + public static class CollapsableView { + + private View contenView; + private OsmandPreference collapsedPref; + private boolean collapsed; + private OnCollExpListener onCollExpListener; + + public interface OnCollExpListener { + void onCollapseExpand(boolean collapsed); + } + + public CollapsableView(@NonNull View contenView, @NonNull OsmandPreference collapsedPref) { + this.contenView = contenView; + this.collapsedPref = collapsedPref; + } + + public CollapsableView(@NonNull View contenView, boolean collapsed) { + this.contenView = contenView; + this.collapsed = collapsed; + } + + public View getContenView() { + return contenView; + } + + public boolean isCollapsed() { + if (collapsedPref != null) { + return collapsedPref.get(); + } else { + return collapsed; + } + } + + public void setCollapsed(boolean collapsed) { + if (collapsedPref != null) { + collapsedPref.set(collapsed); + } else { + this.collapsed = collapsed; + } + if (onCollExpListener != null) { + onCollExpListener.onCollapseExpand(collapsed); + } + } + + public OnCollExpListener getOnCollExpListener() { + return onCollExpListener; + } + + public void setOnCollExpListener(OnCollExpListener onCollExpListener) { + this.onCollExpListener = onCollExpListener; + } + } + public MenuBuilder(MapActivity mapActivity) { this.mapActivity = mapActivity; this.app = mapActivity.getMyApplication(); - plainMenuItems = new LinkedList<>(); + this.plainMenuItems = new LinkedList<>(); } - public OsmandApplication getApp() { + public OsmandApplication getApplication() { return app; } - public MapActivity getMapActivity() { - return mapActivity; - } - public LatLon getLatLon() { return latLon; } @@ -143,12 +208,12 @@ public class MenuBuilder { public void build(View view) { firstRow = true; hidden = false; - buildPluginRows(view); buildNearestWikiRow(view); if (needBuildPlainMenuItems()) { buildPlainMenuItems(view); } buildInternal(view); + buildPluginRows(view); buildAfter(view); } @@ -166,7 +231,7 @@ public class MenuBuilder { protected void buildPlainMenuItems(View view) { for (PlainMenuItem item : plainMenuItems) { - buildRow(view, item.getIconId(), item.getText(), 0, false, null, + buildRow(view, item.getIconId(), item.getText(), 0, item.collapsable, item.collapsableView, item.isNeedLinks(), 0, item.isUrl(), item.getOnClickListener()); } } @@ -216,15 +281,15 @@ public class MenuBuilder { firstRow = false; } - protected View buildRow(View view, int iconId, String text, int textColor, - boolean collapsable, final View collapsableView, + public View buildRow(View view, int iconId, String text, int textColor, + boolean collapsable, final CollapsableView collapsableView, boolean needLinks, int textLinesLimit, boolean isUrl, OnClickListener onClickListener) { return buildRow(view, getRowIcon(iconId), text, textColor, collapsable, collapsableView, needLinks, textLinesLimit, isUrl, onClickListener); } - protected View buildRow(final View view, Drawable icon, final String text, int textColor, - boolean collapsable, final View collapsableView, boolean needLinks, + public View buildRow(final View view, Drawable icon, final String text, int textColor, + boolean collapsable, final CollapsableView collapsableView, boolean needLinks, int textLinesLimit, boolean isUrl, OnClickListener onClickListener) { if (!isFirstRow()) { @@ -294,7 +359,8 @@ public class MenuBuilder { textView.setTextColor(view.getResources().getColor(textColor)); } - LinearLayout.LayoutParams llTextViewParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); + LinearLayout.LayoutParams llTextViewParams = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT); + llTextViewParams.weight = 1f; llTextViewParams.setMargins(0, 0, dpToPx(10f), 0); llTextViewParams.gravity = Gravity.CENTER_VERTICAL; llText.setLayoutParams(llTextViewParams); @@ -314,22 +380,28 @@ public class MenuBuilder { llIconCollapseParams.gravity = Gravity.CENTER_VERTICAL; iconViewCollapse.setLayoutParams(llIconCollapseParams); iconViewCollapse.setScaleType(ImageView.ScaleType.CENTER_INSIDE); - iconViewCollapse.setImageDrawable(app.getIconsCache().getThemedIcon(collapsableView.getVisibility() == View.GONE ? + iconViewCollapse.setImageDrawable(app.getIconsCache().getThemedIcon(collapsableView.getContenView().getVisibility() == View.GONE ? R.drawable.ic_action_arrow_down : R.drawable.ic_action_arrow_up)); llIconCollapse.addView(iconViewCollapse); ll.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - if (collapsableView.getVisibility() == View.VISIBLE) { - collapsableView.setVisibility(View.GONE); + if (collapsableView.getContenView().getVisibility() == View.VISIBLE) { + collapsableView.setCollapsed(true); + collapsableView.getContenView().setVisibility(View.GONE); iconViewCollapse.setImageDrawable(app.getIconsCache().getThemedIcon(R.drawable.ic_action_arrow_down)); } else { - collapsableView.setVisibility(View.VISIBLE); + collapsableView.setCollapsed(false); + collapsableView.getContenView().setVisibility(View.VISIBLE); iconViewCollapse.setImageDrawable(app.getIconsCache().getThemedIcon(R.drawable.ic_action_arrow_up)); } } }); - baseView.addView(collapsableView); + if (collapsableView.isCollapsed()) { + collapsableView.getContenView().setVisibility(View.GONE); + iconViewCollapse.setImageDrawable(app.getIconsCache().getThemedIcon(R.drawable.ic_action_arrow_down)); + } + baseView.addView(collapsableView.getContenView()); } if (onClickListener != null) { @@ -421,7 +493,13 @@ public class MenuBuilder { } public void addPlainMenuItem(int iconId, String text, boolean needLinks, boolean isUrl, OnClickListener onClickListener) { - plainMenuItems.add(new PlainMenuItem(iconId, text, needLinks, isUrl, onClickListener)); + plainMenuItems.add(new PlainMenuItem(iconId, text, needLinks, isUrl, false, null, onClickListener)); + } + + public void addPlainMenuItem(int iconId, String text, boolean needLinks, boolean isUrl, + boolean collapsable, CollapsableView collapsableView, + OnClickListener onClickListener) { + plainMenuItems.add(new PlainMenuItem(iconId, text, needLinks, isUrl, collapsable, collapsableView, onClickListener)); } public void clearPlainMenuItems() { @@ -460,7 +538,7 @@ public class MenuBuilder { ); } - protected View getCollapsableTextView(Context context, boolean collapsed, String text) { + protected CollapsableView getCollapsableTextView(Context context, boolean collapsed, String text) { final TextView textView = new TextView(context); textView.setVisibility(collapsed ? View.GONE : View.VISIBLE); LinearLayout.LayoutParams llTextDescParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT); @@ -469,10 +547,10 @@ public class MenuBuilder { textView.setTextSize(16); textView.setTextColor(app.getResources().getColor(light ? R.color.ctx_menu_info_text_light : R.color.ctx_menu_info_text_dark)); textView.setText(text); - return textView; + return new CollapsableView(textView, collapsed); } - protected View getCollapsableWikiView(Context context, boolean collapsed) { + protected CollapsableView getCollapsableWikiView(Context context, boolean collapsed) { final LinearLayout view = new LinearLayout(context); view.setOrientation(LinearLayout.VERTICAL); view.setVisibility(collapsed ? View.GONE : View.VISIBLE); @@ -506,7 +584,7 @@ public class MenuBuilder { view.addView(wikiButton); } - return view; + return new CollapsableView(view, collapsed); } protected boolean processNearstWiki() { diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/AmenityMenuBuilder.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/AmenityMenuBuilder.java index 7c45faa03f..27a547a303 100644 --- a/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/AmenityMenuBuilder.java +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/AmenityMenuBuilder.java @@ -59,7 +59,7 @@ public class AmenityMenuBuilder extends MenuBuilder { } private void buildRow(View view, int iconId, String text, String textPrefix, - boolean collapsable, final View collapsableView, + boolean collapsable, final CollapsableView collapsableView, int textColor, boolean isWiki, boolean isText, boolean needLinks, boolean isPhoneNumber, boolean isUrl) { buildRow(view, getRowIcon(iconId), text, textPrefix, collapsable, collapsableView, textColor, @@ -67,7 +67,7 @@ public class AmenityMenuBuilder extends MenuBuilder { } protected void buildRow(final View view, Drawable icon, final String text, final String textPrefix, - boolean collapsable, final View collapsableView, + boolean collapsable, final CollapsableView collapsableView, int textColor, boolean isWiki, boolean isText, boolean needLinks, boolean isPhoneNumber, boolean isUrl) { @@ -180,22 +180,28 @@ public class AmenityMenuBuilder extends MenuBuilder { llIconCollapseParams.gravity = Gravity.CENTER_VERTICAL; iconViewCollapse.setLayoutParams(llIconCollapseParams); iconViewCollapse.setScaleType(ImageView.ScaleType.CENTER_INSIDE); - iconViewCollapse.setImageDrawable(app.getIconsCache().getThemedIcon(collapsableView.getVisibility() == View.GONE ? + iconViewCollapse.setImageDrawable(app.getIconsCache().getThemedIcon(collapsableView.getContenView().getVisibility() == View.GONE ? R.drawable.ic_action_arrow_down : R.drawable.ic_action_arrow_up)); llIconCollapse.addView(iconViewCollapse); ll.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - if (collapsableView.getVisibility() == View.VISIBLE) { - collapsableView.setVisibility(View.GONE); + if (collapsableView.getContenView().getVisibility() == View.VISIBLE) { + collapsableView.setCollapsed(true); + collapsableView.getContenView().setVisibility(View.GONE); iconViewCollapse.setImageDrawable(app.getIconsCache().getThemedIcon(R.drawable.ic_action_arrow_down)); } else { - collapsableView.setVisibility(View.VISIBLE); + collapsableView.setCollapsed(false); + collapsableView.getContenView().setVisibility(View.VISIBLE); iconViewCollapse.setImageDrawable(app.getIconsCache().getThemedIcon(R.drawable.ic_action_arrow_up)); } } }); - baseView.addView(collapsableView); + if (collapsableView.isCollapsed()) { + collapsableView.getContenView().setVisibility(View.GONE); + iconViewCollapse.setImageDrawable(app.getIconsCache().getThemedIcon(R.drawable.ic_action_arrow_down)); + } + baseView.addView(collapsableView.getContenView()); } if (isWiki) { @@ -289,7 +295,7 @@ public class AmenityMenuBuilder extends MenuBuilder { String vl = e.getValue(); String textPrefix = ""; - View collapsableView = null; + CollapsableView collapsableView = null; boolean collapsable = false; boolean isWiki = false; boolean isText = false; @@ -511,7 +517,7 @@ public class AmenityMenuBuilder extends MenuBuilder { private int iconId; private String textPrefix; private String text; - private View collapsableView; + private CollapsableView collapsableView; private boolean collapsable; private int textColor; private boolean isWiki; @@ -523,7 +529,7 @@ public class AmenityMenuBuilder extends MenuBuilder { private String name; public AmenityInfoRow(String key, Drawable icon, String textPrefix, String text, - boolean collapsable, View collapsableView, + boolean collapsable, CollapsableView collapsableView, int textColor, boolean isWiki, boolean isText, boolean needLinks, int order, String name, boolean isPhoneNumber, boolean isUrl) { this.key = key; @@ -543,7 +549,7 @@ public class AmenityMenuBuilder extends MenuBuilder { } public AmenityInfoRow(String key, int iconId, String textPrefix, String text, - boolean collapsable, View collapsableView, + boolean collapsable, CollapsableView collapsableView, int textColor, boolean isWiki, boolean isText, boolean needLinks, int order, String name, boolean isPhoneNumber, boolean isUrl) { this.key = key; diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/cards/AbstractCard.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/cards/AbstractCard.java new file mode 100644 index 0000000000..5be0c1a838 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/cards/AbstractCard.java @@ -0,0 +1,21 @@ +package net.osmand.plus.mapcontextmenu.builders.cards; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; + +public abstract class AbstractCard { + + protected View view; + + public abstract int getCardLayoutId(); + + public View build(Context ctx) { + view = LayoutInflater.from(ctx).inflate(getCardLayoutId(), null); + update(); + return view; + } + + public abstract void update(); + +} diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/cards/CardsRowBuilder.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/cards/CardsRowBuilder.java new file mode 100644 index 0000000000..aea2816c92 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/cards/CardsRowBuilder.java @@ -0,0 +1,123 @@ +package net.osmand.plus.mapcontextmenu.builders.cards; + +import android.support.v4.view.PagerAdapter; +import android.support.v4.view.ViewPager; +import android.view.View; +import android.view.ViewGroup; +import android.widget.LinearLayout; + +import net.osmand.AndroidUtils; +import net.osmand.plus.LockableViewPager; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; +import net.osmand.plus.mapcontextmenu.MenuBuilder; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +public class CardsRowBuilder { + + private MenuBuilder menuBuilder; + private View view; + private OsmandApplication app; + private List cards = new ArrayList<>(); + private LockableViewPager viewPager; + private ViewsPagerAdapter pagerAdapter; + private int dp10; + + public CardsRowBuilder(MenuBuilder menuBuilder, View view) { + this.menuBuilder = menuBuilder; + this.view = view; + this.app = menuBuilder.getApplication(); + this.dp10 = AndroidUtils.dpToPx(app, 10f); + } + + public MenuBuilder getMenuBuilder() { + return menuBuilder; + } + + public LockableViewPager getViewPager() { + return viewPager; + } + + public void setCards(AbstractCard ...cards) { + setCards(Arrays.asList(cards)); + } + + public void setCards(Collection cards) { + this.cards.clear(); + if (cards != null) { + this.cards.addAll(cards); + } + if (!menuBuilder.isHidden()) { + viewPager.setSwipeLocked(itemsCount() < 2); + pagerAdapter.notifyDataSetChanged(); + } + } + + public void setProgressCard() { + setCards(new ProgressCard()); + } + + public void build() { + viewPager = new LockableViewPager(view.getContext()); + ViewPager.LayoutParams params = new ViewPager.LayoutParams(); + params.width = ViewGroup.LayoutParams.MATCH_PARENT; + params.height = (int) app.getResources().getDimension(R.dimen.context_img_card_height) + dp10 + dp10; + viewPager.setLayoutParams(params); + viewPager.setPageMargin(dp10); + viewPager.setPadding(dp10, dp10, dp10, dp10); + viewPager.setClipToPadding(false); + pagerAdapter = new ViewsPagerAdapter(); + viewPager.setAdapter(pagerAdapter); + viewPager.setSwipeLocked(itemsCount() < 2); + //((LinearLayout) view).addView(viewPager); + } + + private int itemsCount() { + return cards.size(); + } + + private View createPageView(int position) { + return cards.get(position).build(view.getContext()); + } + + private class ViewsPagerAdapter extends PagerAdapter { + + @Override + public float getPageWidth(int position) { + return 0.8f; + } + + @Override + public int getItemPosition(Object object) { + return POSITION_NONE; + } + + @Override + public int getCount() { + return itemsCount(); + } + + @Override + public Object instantiateItem(ViewGroup container, int position) { + + View view = createPageView(position); + container.addView(view, 0); + + return view; + } + + @Override + public void destroyItem(ViewGroup collection, int position, Object view) { + collection.removeView((View) view); + } + + @Override + public boolean isViewFromObject(View view, Object object) { + return view == object; + } + } +} diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/cards/ImageCard.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/cards/ImageCard.java new file mode 100644 index 0000000000..8cba5cda4a --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/cards/ImageCard.java @@ -0,0 +1,383 @@ +package net.osmand.plus.mapcontextmenu.builders.cards; + +import android.graphics.Bitmap; +import android.graphics.drawable.Drawable; +import android.os.AsyncTask; +import android.os.Build; +import android.support.annotation.NonNull; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.TextView; + +import net.osmand.AndroidNetworkUtils; +import net.osmand.Location; +import net.osmand.data.LatLon; +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; +import net.osmand.plus.Version; +import net.osmand.util.Algorithms; +import net.osmand.util.MapUtils; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import static java.text.DateFormat.FULL; + +public abstract class ImageCard extends AbstractCard { + + private static final int IMAGES_LIMIT = 15; + + private String type; + // Image location + private LatLon location; + // (optional) Image's camera angle in range [0, 360]. + private double ca = Double.NaN; + // Date When bitmap was captured. + private Date timestamp; + // Image key. + private String key; + // User name + private String userName; + // Image viewer url + private String url; + // Image bitmap url + private String imageUrl; + + private OsmandApplication app; + private int defaultImageLayoutId = R.layout.context_menu_card_image; + + protected Drawable icon; + protected OnClickListener onClickListener; + + private static final DateFormat DATE_FORMAT = SimpleDateFormat.getDateTimeInstance(FULL, FULL, Locale.US); //"yyyy-MM-dd'T'HH:mm:ss"); + private boolean downloading; + private boolean downloaded; + private Bitmap bitmap; + private float bearingDiff = Float.NaN; + private float distance = Float.NaN; + + public interface ImageCardFactory { + T createCard(OsmandApplication app, JSONObject imageObject); + } + + public ImageCard(OsmandApplication app, JSONObject imageObject) { + this.app = app; + try { + if (imageObject.has("type")) { + this.type = imageObject.getString("type"); + } + if (imageObject.has("ca") && !imageObject.isNull("ca")) { + this.ca = imageObject.getDouble("ca"); + } + if (imageObject.has("lat") && imageObject.has("lon")) { + double latitude = imageObject.getDouble("lat"); + double longitude = imageObject.getDouble("lon"); + this.location = new LatLon(latitude, longitude); + } + if (imageObject.has("timestamp")) { + try { + this.timestamp = DATE_FORMAT.parse(imageObject.getString("timestamp")); + } catch (ParseException e) { + e.printStackTrace(); + } + } + if (imageObject.has("key")) { + this.key = imageObject.getString("key"); + } + if (imageObject.has("username")) { + this.userName = imageObject.getString("username"); + } + if (imageObject.has("url")) { + this.url = imageObject.getString("url"); + } + if (imageObject.has("imageUrl")) { + this.imageUrl = imageObject.getString("imageUrl"); + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + + public double getCa() { + return ca; + } + + public String getKey() { + return key; + } + + public String getType() { + return type; + } + + public LatLon getLocation() { + return location; + } + + public Date getTimestamp() { + return timestamp; + } + + public String getUserName() { + return userName; + } + + public String getUrl() { + return url; + } + + public String getImageUrl() { + return imageUrl; + } + + public int getDefaultImageLayoutId() { + return defaultImageLayoutId; + } + + @Override + public int getCardLayoutId() { + return defaultImageLayoutId; + } + + public Drawable getIcon() { + return icon; + } + + public OnClickListener getOnClickListener() { + return onClickListener; + } + + + public boolean isDownloading() { + return downloading; + } + + public void setDownloading(boolean downloading) { + this.downloading = downloading; + } + + public Bitmap getBitmap() { + return bitmap; + } + + public void setBitmap(Bitmap bitmap) { + this.bitmap = bitmap; + } + + public float getBearingDiff() { + return bearingDiff; + } + + public void setBearingDiff(float bearingDiff) { + this.bearingDiff = bearingDiff; + } + + public float getDistance() { + return distance; + } + + public void setDistance(float distance) { + this.distance = distance; + } + + public void update() { + if (view != null) { + ImageView image = (ImageView) view.findViewById(R.id.image); + ImageView iconImageView = (ImageView) view.findViewById(R.id.icon); + TextView watermarkTextView = (TextView) view.findViewById(R.id.watermark); + ProgressBar progress = (ProgressBar) view.findViewById(R.id.progress); + if (icon == null) { + iconImageView.setVisibility(View.GONE); + } else { + iconImageView.setImageDrawable(icon); + iconImageView.setVisibility(View.VISIBLE); + } + if (Algorithms.isEmpty(userName)) { + watermarkTextView.setVisibility(View.GONE); + } else { + watermarkTextView.setText("@" + userName); + watermarkTextView.setVisibility(View.VISIBLE); + } + if (downloading) { + progress.setVisibility(View.VISIBLE); + image.setImageBitmap(null); + } else if (!downloaded) { + execute(new DownloadImageTask()); + } else { + progress.setVisibility(View.GONE); + image.setImageBitmap(bitmap); + } + if (onClickListener != null) { + view.findViewById(R.id.image_card).setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + onClickListener.onClick(v); + } + }); + } else { + view.findViewById(R.id.image_card).setOnClickListener(null); + } + } + } + + @SuppressWarnings("unchecked") + public static

void execute(AsyncTask task, P... requests) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, requests); + } else { + task.execute(requests); + } + } + + public static class GetImageCardsTask extends AsyncTask> { + + private OsmandApplication app; + private LatLon latLon; + private Listener listener; + private ImageCardFactory imageCardFactory; + private List result; + + public interface Listener { + void onFinish(List cardList); + } + + public GetImageCardsTask(@NonNull ImageCardFactory imageCardFactory, + @NonNull OsmandApplication app, LatLon latLon, Listener listener) { + this.imageCardFactory = imageCardFactory; + this.app = app; + this.latLon = latLon; + this.listener = listener; + } + + @Override + protected List doInBackground(Void... params) { + List result = new ArrayList<>(); + try { + final Map pms = new LinkedHashMap<>(); + pms.put("lat", "" + latLon.getLatitude()); + pms.put("lon", "" + latLon.getLongitude()); + Location myLocation = app.getLocationProvider().getLastKnownLocation(); + if (myLocation != null) { + pms.put("myLocation", "" + myLocation.getLatitude() + "," + myLocation.getLongitude()); + } + pms.put("app", Version.isPaidVersion(app) ? "paid" : "free"); + String response = AndroidNetworkUtils.sendRequest(app, "http://osmand.net/api/cm_place.php", pms, + "Requesting location images...", false, false); + + if (!Algorithms.isEmpty(response)) { + JSONObject obj = new JSONObject(response); + JSONArray images = obj.getJSONArray("features"); + if (images.length() > 0) { + for (int i = 0; i < images.length(); i++) { + try { + JSONObject imageObject = (JSONObject) images.get(i); + if (imageObject != JSONObject.NULL) { + result.add(imageCardFactory.createCard(app, imageObject)); + } + } catch (JSONException e) { + e.printStackTrace(); + } + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + final Location loc = new Location(""); + loc.setLatitude(latLon.getLatitude()); + loc.setLongitude(latLon.getLongitude()); + sortImagesInfo(result, loc); + if (result.size() > IMAGES_LIMIT) { + result = result.subList(0, IMAGES_LIMIT); + } + return result; + } + + @Override + protected void onPostExecute(List cardList) { + result = cardList; + if (listener != null) { + listener.onFinish(result); + } + } + } + + private static void sortImagesInfo(List cardList, @NonNull final Location location) { + List targetCards = new ArrayList<>(); + List otherCards = new ArrayList<>(); + for (T c : cardList) { + if (c.getLocation() != null) { + Location l = new Location(""); + l.setLatitude(c.getLocation().getLatitude()); + l.setLongitude(c.getLocation().getLongitude()); + c.setDistance(l.distanceTo(location)); + if (!Double.isNaN(c.getCa())) { + float bearingDiff = Math.abs(MapUtils.unifyRotationDiff( + MapUtils.unifyRotationTo360((float) c.getCa()), l.bearingTo(location))); + c.setBearingDiff(bearingDiff); + if (bearingDiff < 30) { + targetCards.add(c); + } else { + otherCards.add(c); + } + } else { + otherCards.add(c); + } + } + } + Collections.sort(targetCards, new Comparator() { + + @Override + public int compare(ImageCard i1, ImageCard i2) { + return Float.compare(i1.bearingDiff, i2.bearingDiff); + } + }); + Collections.sort(otherCards, new Comparator() { + + @Override + public int compare(ImageCard i1, ImageCard i2) { + return Float.compare(i1.distance, i2.distance); + } + }); + cardList.clear(); + cardList.addAll(targetCards); + cardList.addAll(otherCards); + } + + private class DownloadImageTask extends AsyncTask { + + @Override + protected void onPreExecute() { + downloading = true; + update(); + } + + @Override + protected Bitmap doInBackground(Void... params) { + return AndroidNetworkUtils.downloadImage(app, imageUrl); + } + + @Override + protected void onPostExecute(Bitmap bitmap) { + downloading = false; + downloaded = true; + ImageCard.this.bitmap = bitmap; + update(); + } + } +} diff --git a/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/cards/ProgressCard.java b/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/cards/ProgressCard.java new file mode 100644 index 0000000000..f692b4dfe6 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/mapcontextmenu/builders/cards/ProgressCard.java @@ -0,0 +1,15 @@ +package net.osmand.plus.mapcontextmenu.builders.cards; + +import net.osmand.plus.R; + +public class ProgressCard extends AbstractCard { + + @Override + public int getCardLayoutId() { + return R.layout.context_menu_card_progress; + } + + @Override + public void update() { + } +} diff --git a/OsmAnd/src/net/osmand/plus/mapillary/AddMapillaryPhotoCard.java b/OsmAnd/src/net/osmand/plus/mapillary/AddMapillaryPhotoCard.java new file mode 100644 index 0000000000..4443cd4018 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/mapillary/AddMapillaryPhotoCard.java @@ -0,0 +1,26 @@ +package net.osmand.plus.mapillary; + +import android.view.View; + +import net.osmand.plus.R; +import net.osmand.plus.mapcontextmenu.builders.cards.AbstractCard; + +public class AddMapillaryPhotoCard extends AbstractCard { + + @Override + public int getCardLayoutId() { + return R.layout.mapillary_context_menu_action; + } + + @Override + public void update() { + if (view != null) { + view.findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + // todo open mapillary + } + }); + } + } +} diff --git a/OsmAnd/src/net/osmand/plus/mapillary/MapillaryImageCard.java b/OsmAnd/src/net/osmand/plus/mapillary/MapillaryImageCard.java new file mode 100644 index 0000000000..c599081ec1 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/mapillary/MapillaryImageCard.java @@ -0,0 +1,30 @@ +package net.osmand.plus.mapillary; + +import android.view.View; + +import net.osmand.plus.OsmandApplication; +import net.osmand.plus.R; +import net.osmand.plus.mapcontextmenu.builders.cards.ImageCard; + +import org.json.JSONObject; + +public class MapillaryImageCard extends ImageCard { + + public static class MapillaryImageCardFactory implements ImageCardFactory { + @Override + public MapillaryImageCard createCard(OsmandApplication app, JSONObject imageObject) { + return new MapillaryImageCard(app, imageObject); + } + } + + public MapillaryImageCard(OsmandApplication app, JSONObject imageObject) { + super(app, imageObject); + this.icon = app.getIconsCache().getIcon(R.drawable.ic_logo_mapillary); + this.onClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + // todo + } + }; + } +} diff --git a/OsmAnd/src/net/osmand/plus/mapillary/MapillaryImageInfo.java b/OsmAnd/src/net/osmand/plus/mapillary/MapillaryImageInfo.java deleted file mode 100644 index b32dfde417..0000000000 --- a/OsmAnd/src/net/osmand/plus/mapillary/MapillaryImageInfo.java +++ /dev/null @@ -1,143 +0,0 @@ -package net.osmand.plus.mapillary; - -import android.graphics.Bitmap; - -import net.osmand.data.LatLon; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; - -import static java.text.DateFormat.FULL; - -public class MapillaryImageInfo { - // (optional) Image's camera angle in range [0, 360]. - private double ca = Double.NaN; - // Camera model name. - private String cameraMake; - // Date When bitmap was captured. - private Date capturedAt; - // Image key. - private String key; - // Whether the bitmap is panorama ( true ), or not ( false ). - private boolean pano; - // (optional) Which project the bitmap belongs to. Absent if it doesn't belong to any project. - private String projectKey; - // User who captured the bitmap. - private String userKey; - // Username of who captured the bitmap. - private String userName; - // Image location - private LatLon coordinates; - - private static final DateFormat DATE_FORMAT = SimpleDateFormat.getDateTimeInstance(FULL, FULL, Locale.US); //"yyyy-MM-dd'T'HH:mm:ss"); - private boolean downloading; - private Bitmap bitmap; - - MapillaryImageInfo(JSONObject imgObj) { - try { - JSONObject props = imgObj.getJSONObject("properties"); - if (props.has("ca")) { - this.ca = props.getDouble("ca"); - } - if (props.has("camera_make")) { - this.cameraMake = props.getString("camera_make"); - } - if (props.has("captured_at")) { - try { - this.capturedAt = DATE_FORMAT.parse(props.getString("captured_at")); - } catch (ParseException e) { - e.printStackTrace(); - } - } - if (props.has("key")) { - this.key = props.getString("key"); - } - if (props.has("pano")) { - this.pano = props.getBoolean("pano"); - } - if (props.has("project_key")) { - this.projectKey = props.getString("project_key"); - } - if (props.has("user_key")) { - this.userKey = props.getString("user_key"); - } - if (props.has("username")) { - this.userName = props.getString("username"); - } - - if (imgObj.has("geometry")) { - JSONObject geometry = imgObj.getJSONObject("geometry"); - if (geometry.has("coordinates")) { - JSONArray coordinates = geometry.getJSONArray("coordinates"); - if (coordinates.length() == 2) { - double longitude = coordinates.getDouble(0); - double latitude = coordinates.getDouble(1); - this.coordinates = new LatLon(latitude, longitude); - } - } - } - - } catch (JSONException e) { - e.printStackTrace(); - } - } - - public double getCa() { - return ca; - } - - public String getCameraMake() { - return cameraMake; - } - - public Date getCapturedAt() { - return capturedAt; - } - - public String getKey() { - return key; - } - - public boolean isPano() { - return pano; - } - - public String getProjectKey() { - return projectKey; - } - - public String getUserKey() { - return userKey; - } - - public String getUserName() { - return userName; - } - - public LatLon getCoordinates() { - return coordinates; - } - - public boolean isDownloading() { - return downloading; - } - - public void setDownloading(boolean downloading) { - this.downloading = downloading; - } - - public Bitmap getBitmap() { - return bitmap; - } - - public void setBitmap(Bitmap bitmap) { - this.bitmap = bitmap; - } -} diff --git a/OsmAnd/src/net/osmand/plus/mapillary/MapillaryImageRow.java b/OsmAnd/src/net/osmand/plus/mapillary/MapillaryImageRow.java deleted file mode 100644 index 16bc3a3c76..0000000000 --- a/OsmAnd/src/net/osmand/plus/mapillary/MapillaryImageRow.java +++ /dev/null @@ -1,350 +0,0 @@ -package net.osmand.plus.mapillary; - -import android.graphics.Bitmap; -import android.os.AsyncTask; -import android.support.annotation.NonNull; -import android.support.v4.view.PagerAdapter; -import android.support.v4.view.ViewPager; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.ProgressBar; -import android.widget.TextView; - -import net.osmand.AndroidNetworkUtils; -import net.osmand.AndroidUtils; -import net.osmand.data.LatLon; -import net.osmand.data.RotatedTileBox; -import net.osmand.plus.LockableViewPager; -import net.osmand.plus.OsmandApplication; -import net.osmand.plus.R; -import net.osmand.plus.mapcontextmenu.MenuBuilder; -import net.osmand.util.Algorithms; -import net.osmand.util.MapUtils; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -public class MapillaryImageRow { - - private static final int IMAGES_LIMIT = 15; - - private MenuBuilder menuBuilder; - private View view; - private OsmandApplication app; - private List imageInfoList = new ArrayList<>(); - private boolean updatingInfo; - private boolean downloadingImages; - private boolean updatingInfoInterrupted; - private boolean downloadingImagesInterrupted; - private LockableViewPager viewPager; - private ViewsPagerAdapter pagerAdapter; - private int dp10; - private boolean updated; - - public MapillaryImageRow(MenuBuilder menuBuilder, View view) { - this.menuBuilder = menuBuilder; - this.view = view; - this.app = menuBuilder.getApp(); - this.dp10 = AndroidUtils.dpToPx(app, 10f); - } - - public MapillaryImageRow(MapillaryImageRow imageRow, View view) { - this(imageRow.menuBuilder, view); - this.updatingInfo = imageRow.updatingInfo; - this.downloadingImages = imageRow.downloadingImages; - this.updatingInfoInterrupted = imageRow.updatingInfoInterrupted; - this.downloadingImagesInterrupted = imageRow.downloadingImagesInterrupted; - imageInfoList.addAll(imageRow.imageInfoList); - sortImagesInfo(imageInfoList, - menuBuilder.getMapActivity().getMapView().getCurrentRotatedTileBox().getRotate(), - menuBuilder.getLatLon()); - updated = true; - } - - public MenuBuilder getMenuBuilder() { - return menuBuilder; - } - - public View getView() { - return view; - } - - public void build() { - viewPager = new LockableViewPager(view.getContext()); - ViewPager.LayoutParams params = new ViewPager.LayoutParams(); - params.width = ViewGroup.LayoutParams.MATCH_PARENT; - params.height = (int) app.getResources().getDimension(R.dimen.mapillary_card_height) + dp10 + dp10; - viewPager.setLayoutParams(params); - viewPager.setPageMargin(dp10); - viewPager.setPadding(dp10, dp10, dp10, dp10); - viewPager.setClipToPadding(false); - pagerAdapter = new ViewsPagerAdapter(); - viewPager.setAdapter(pagerAdapter); - viewPager.setSwipeLocked(imageInfoList.size() == 0); - ((LinearLayout) view).addView(viewPager); - - if (!updated) { - new GetImageInfoTask().execute(); - } else { - update(); - } - } - - public void update() { - if (updatingInfoInterrupted || updatingInfo) { - new GetImageInfoTask().execute(); - } else if ((downloadingImagesInterrupted || downloadingImages) && imageInfoList.size() > 0) { - new DownloadImagesTask().execute(); - } - } - - private int itemsCount() { - return updatingInfo ? 1 : imageInfoList.size() + 1; - } - - private View createPageView(ViewGroup container, int position) { - View v; - if (updatingInfo && position == 0) { - v = LayoutInflater.from(view.getContext()).inflate(R.layout.mapillary_context_menu_progress, null); - } else if (position == itemsCount() - 1) { - v = LayoutInflater.from(view.getContext()).inflate(R.layout.mapillary_context_menu_action, null); - v.findViewById(R.id.button).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - // todo open mapillary - } - }); - } else { - v = LayoutInflater.from(view.getContext()).inflate(R.layout.mapillary_context_menu_image, null); - ImageView image = (ImageView) v.findViewById(R.id.image); - TextView watermark = (TextView) v.findViewById(R.id.watermark); - ProgressBar progress = (ProgressBar) v.findViewById(R.id.progress); - if (position < imageInfoList.size()) { - MapillaryImageInfo info = imageInfoList.get(position); - if (info != null) { - if (Algorithms.isEmpty(info.getUserName())) { - watermark.setText("mapillary.com"); - } else { - watermark.setText("@" + info.getUserName() + " | mapillary.com"); - } - if (info.isDownloading()) { - progress.setVisibility(View.VISIBLE); - image.setImageBitmap(null); - } else { - progress.setVisibility(View.GONE); - image.setImageBitmap(info.getBitmap()); - } - v.findViewById(R.id.image_card).setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - // todo open image - } - }); - } - } - } - return v; - } - - private class ViewsPagerAdapter extends PagerAdapter { - - @Override - public float getPageWidth(int position) { - return 0.8f; - } - - @Override - public int getItemPosition(Object object) { - return POSITION_NONE; - } - - @Override - public int getCount() { - return itemsCount(); - } - - @Override - public Object instantiateItem(ViewGroup container, int position) { - - View view = createPageView(container, position); - container.addView(view, 0); - - return view; - } - - @Override - public void destroyItem(ViewGroup collection, int position, Object view) { - collection.removeView((View) view); - } - - @Override - public boolean isViewFromObject(View view, Object object) { - return view == object; - } - } - - private class GetImageInfoTask extends AsyncTask> { - - private RotatedTileBox tb; - private LatLon menuLatLon; - - @Override - protected void onPreExecute() { - updatingInfoInterrupted = false; - if (!menuBuilder.isHidden()) { - updatingInfo = true; - pagerAdapter.notifyDataSetChanged(); - tb = menuBuilder.getMapActivity().getMapView().getCurrentRotatedTileBox().copy(); - menuLatLon = menuBuilder.getLatLon(); - } - } - - @Override - protected List doInBackground(Void... params) { - // https://a.mapillary.com/v3/images/?lookat=12.9981086701,55.6075236275&closeto=13.0006076843,55.6089295863&radius=20&client_id=LXJVNHlDOGdMSVgxZG5mVzlHQ3ZqQTo0NjE5OWRiN2EzNTFkNDg4 - List result = new ArrayList<>(); - try { - LatLon l1 = tb.getLatLonFromPixel(0, 0); - LatLon l2 = tb.getLatLonFromPixel(dp10 * 2, dp10 * 2); - int radius = Math.max(20, (int) MapUtils.getDistance(l1, l2)); - radius = Math.min(500, radius); - //float mx = tb.getPixXFromLatLon(menuLatLon.getLatitude(), menuLatLon.getLongitude()); - //float my = tb.getPixYFromLatLon(menuLatLon.getLatitude(), menuLatLon.getLongitude()); - //LatLon lookAt = tb.getLatLonFromPixel(mx, my - dp10); - - final Map pms = new LinkedHashMap<>(); - //pms.put("lookat", "" + lookAt.getLongitude() + "," + lookAt.getLatitude()); - pms.put("closeto", "" + menuLatLon.getLongitude() + "," + menuLatLon.getLatitude()); - pms.put("radius", "" + radius); - pms.put("client_id", "LXJVNHlDOGdMSVgxZG5mVzlHQ3ZqQTo0NjE5OWRiN2EzNTFkNDg4"); - String response = AndroidNetworkUtils.sendRequest(app, "https://a.mapillary.com/v3/images", pms, - "Requesting mapillary images...", false, false); - - if (!Algorithms.isEmpty(response)) { - JSONObject obj = new JSONObject(response); - JSONArray images = obj.getJSONArray("features"); - if (images.length() > 0) { - for (int i = 0; i < images.length(); i++) { - if (menuBuilder.isHidden()) { - updatingInfoInterrupted = true; - break; - } - if (i > IMAGES_LIMIT) { - break; - } - try { - JSONObject imgObj = (JSONObject) images.get(i); - if (imgObj != JSONObject.NULL) { - result.add(new MapillaryImageInfo(imgObj)); - } - } catch (JSONException e) { - e.printStackTrace(); - } - } - } - } - } catch (Exception e) { - e.printStackTrace(); - } - sortImagesInfo(result, tb.getRotate(), menuLatLon); - return result; - } - - @Override - protected void onPostExecute(List infoList) { - updatingInfo = false; - if (!menuBuilder.isHidden()) { - imageInfoList.addAll(infoList); - pagerAdapter.notifyDataSetChanged(); - viewPager.setSwipeLocked(imageInfoList.size() == 0); - if (imageInfoList.size() > 0) { - new DownloadImagesTask().execute(); - } - } - } - } - - private void sortImagesInfo(List infoList, final float azimuth, final LatLon menuLatLon) { - Collections.sort(infoList, new Comparator() { - - @Override - public int compare(MapillaryImageInfo i1, MapillaryImageInfo i2) { - int res = 0; - if (!Double.isNaN(i1.getCa()) && !Double.isNaN(i2.getCa()) && menuLatLon != null) { - float a1 = Math.abs(MapUtils.unifyRotationDiff(azimuth, (float) i1.getCa())); - float a2 = Math.abs(MapUtils.unifyRotationDiff(azimuth, (float) i2.getCa())); - res = a1 < a2 ? -1 : (a1 == a2 ? 0 : 1); - } - if (res == 0 && i1.getCoordinates() != null && i2.getCoordinates() != null) { - double d1 = MapUtils.getDistance(menuLatLon, i1.getCoordinates()); - double d2 = MapUtils.getDistance(menuLatLon, i2.getCoordinates()); - res = Double.compare(d1, d2); - } - return res; - } - }); - } - - private class DownloadImagesTask extends AsyncTask { - - private static final String urlTemplate = "https://d1cuyjsrcm0gby.cloudfront.net/{key}/thumb-640.jpg?origin=osmand"; - - @Override - protected void onPreExecute() { - downloadingImagesInterrupted = false; - if (!menuBuilder.isHidden()) { - downloadingImages = true; - for (MapillaryImageInfo imageInfo : imageInfoList) { - if (imageInfo.getBitmap() == null) { - imageInfo.setDownloading(true); - } - } - pagerAdapter.notifyDataSetChanged(); - } - } - - @Override - protected Void doInBackground(Void... params) { - for (MapillaryImageInfo imageInfo : imageInfoList) { - if (menuBuilder.isHidden()) { - downloadingImagesInterrupted = true; - break; - } - if (imageInfo.isDownloading()) { - String url = urlTemplate.replace("{key}", imageInfo.getKey()); - Bitmap bitmap = AndroidNetworkUtils.downloadImage(app, url); - imageInfo.setBitmap(bitmap); - imageInfo.setDownloading(false); - publishProgress(); - } - } - return null; - } - - @Override - protected void onProgressUpdate(Void... values) { - if (!menuBuilder.isHidden()) { - pagerAdapter.notifyDataSetChanged(); - } - } - - @Override - protected void onPostExecute(Void aVoid) { - downloadingImages = false; - if (!menuBuilder.isHidden()) { - pagerAdapter.notifyDataSetChanged(); - } - } - } -} \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/mapillary/MapillaryPlugin.java b/OsmAnd/src/net/osmand/plus/mapillary/MapillaryPlugin.java index 022559caaf..c4d9bdd3c9 100644 --- a/OsmAnd/src/net/osmand/plus/mapillary/MapillaryPlugin.java +++ b/OsmAnd/src/net/osmand/plus/mapillary/MapillaryPlugin.java @@ -9,6 +9,7 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; +import android.widget.CompoundButton; import net.osmand.map.ITileSource; import net.osmand.map.TileSourceManager; @@ -23,6 +24,11 @@ import net.osmand.plus.activities.MapActivity; import net.osmand.plus.activities.MapActivityLayers; import net.osmand.plus.base.BottomSheetDialogFragment; import net.osmand.plus.mapcontextmenu.MenuBuilder; +import net.osmand.plus.mapcontextmenu.MenuBuilder.CollapsableView; +import net.osmand.plus.mapcontextmenu.builders.cards.AbstractCard; +import net.osmand.plus.mapcontextmenu.builders.cards.CardsRowBuilder; +import net.osmand.plus.mapcontextmenu.builders.cards.ImageCard; +import net.osmand.plus.mapcontextmenu.builders.cards.ImageCard.GetImageCardsTask; import net.osmand.plus.views.MapInfoLayer; import net.osmand.plus.views.MapTileLayer; import net.osmand.plus.views.OsmandMapTileView; @@ -30,6 +36,7 @@ import net.osmand.plus.views.mapwidgets.MapWidgetRegistry.MapWidgetRegInfo; import net.osmand.plus.views.mapwidgets.TextInfoWidget; import net.osmand.util.Algorithms; +import java.util.ArrayList; import java.util.List; public class MapillaryPlugin extends OsmandPlugin { @@ -40,7 +47,8 @@ public class MapillaryPlugin extends OsmandPlugin { private MapillaryLayer rasterLayer; private TextInfoWidget mapillaryControl; private MapWidgetRegInfo mapillaryWidgetRegInfo; - private MapillaryImageRow contextMenuImageRow; + private CardsRowBuilder contextMenuCardsRow; + private List contextMenuCards; public MapillaryPlugin(OsmandApplication app) { this.app = app; @@ -168,7 +176,7 @@ public class MapillaryPlugin extends OsmandPlugin { private TextInfoWidget createMonitoringControl(final MapActivity map) { mapillaryControl = new TextInfoWidget(map); - mapillaryControl.setText(map.getString(R.string.mapillary), ""); + mapillaryControl.setText("", map.getString(R.string.mapillary)); mapillaryControl.setIcons(R.drawable.widget_mapillary_day, R.drawable.widget_mapillary_night); mapillaryControl.setOnClickListener(new View.OnClickListener() { @Override @@ -195,30 +203,58 @@ public class MapillaryPlugin extends OsmandPlugin { } @Override - public void buildContextMenuRows(@NonNull MenuBuilder menuBuilder, @NonNull View view) { - if (!menuBuilder.getApp().getSettings().isInternetConnectionAvailable()) { + public void buildContextMenuRows(@NonNull final MenuBuilder menuBuilder, @NonNull View view) { + if (!menuBuilder.getApplication().getSettings().isInternetConnectionAvailable()) { return; } - /* - if (!menuBuilder.isFirstRow()) { - menuBuilder.buildRowDivider(view, false); - } - */ - if (contextMenuImageRow != null && contextMenuImageRow.getMenuBuilder() == menuBuilder) { - contextMenuImageRow = new MapillaryImageRow(contextMenuImageRow, view); - contextMenuImageRow.build(); - } else { - contextMenuImageRow = new MapillaryImageRow(menuBuilder, view); - contextMenuImageRow.build(); - } + boolean needUpdateOnly = contextMenuCardsRow != null && contextMenuCardsRow.getMenuBuilder() == menuBuilder; + contextMenuCardsRow = new CardsRowBuilder(menuBuilder, view); + contextMenuCardsRow.build(); + CollapsableView collapsableView = new CollapsableView(contextMenuCardsRow.getViewPager(), + app.getSettings().MAPILLARY_MENU_COLLAPSED); + collapsableView.setOnCollExpListener(new CollapsableView.OnCollExpListener() { + @Override + public void onCollapseExpand(boolean collapsed) { + if (!collapsed && contextMenuCards == null) { + startLoadingImages(menuBuilder); + } + } + }); + menuBuilder.buildRow(view, R.drawable.ic_action_photo_dark, "Online photos", 0, true, + collapsableView, false, 1, false, null); - //menuBuilder.rowBuilt(); + if (needUpdateOnly && contextMenuCards != null) { + contextMenuCardsRow.setCards(contextMenuCards); + } else if (!collapsableView.isCollapsed()) { + startLoadingImages(menuBuilder); + } + } + + private void startLoadingImages(final MenuBuilder menuBuilder) { + contextMenuCards = new ArrayList<>(); + contextMenuCardsRow.setProgressCard(); + ImageCard.execute(new GetImageCardsTask<>( + new MapillaryImageCard.MapillaryImageCardFactory(), + app, menuBuilder.getLatLon(), + new GetImageCardsTask.Listener() { + @Override + public void onFinish(List cardList) { + if (!menuBuilder.isHidden()) { + List cards = new ArrayList<>(); + cards.addAll(cardList); + cards.add(new AddMapillaryPhotoCard()); + contextMenuCardsRow.setCards(cards); + contextMenuCards = cards; + } + } + })); } @Override public void clearContextMenuRows() { - contextMenuImageRow = null; + contextMenuCardsRow = null; + contextMenuCards = null; } public static class MapillaryFirstDialogFragment extends BottomSheetDialogFragment { @@ -236,20 +272,30 @@ public class MapillaryPlugin extends OsmandPlugin { View view = inflater.inflate(R.layout.mapillary_first_dialog, container, false); final SwitchCompat widgetSwitch = (SwitchCompat) view.findViewById(R.id.widget_switch); widgetSwitch.setChecked(showWidget); + widgetSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + showWidget(isChecked); + } + }); view.findViewById(R.id.actionButton).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - FragmentActivity activity = getActivity(); - MapillaryPlugin plugin = OsmandPlugin.getPlugin(MapillaryPlugin.class); - if (plugin != null && activity instanceof MapActivity) { - plugin.setWidgetVisible((MapActivity) activity, widgetSwitch.isChecked()); - } + showWidget(widgetSwitch.isChecked()); dismiss(); } }); return view; } + private void showWidget(boolean show) { + FragmentActivity activity = getActivity(); + MapillaryPlugin plugin = OsmandPlugin.getPlugin(MapillaryPlugin.class); + if (plugin != null && activity instanceof MapActivity) { + plugin.setWidgetVisible((MapActivity) activity, show); + } + } + @Override public void onSaveInstanceState(@NonNull Bundle outState) { outState.putBoolean(KEY_SHOW_WIDGET, showWidget);