Refactoring mapillary controls

This commit is contained in:
Alexey Kulish 2017-05-04 23:48:07 +03:00
parent 271facfb11
commit 3d59d1903e
18 changed files with 812 additions and 563 deletions

View file

@ -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;

View file

@ -2,8 +2,8 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="@dimen/mapillary_card_width"
android:layout_height="@dimen/mapillary_card_height"
android:layout_width="@dimen/context_img_card_width"
android:layout_height="@dimen/context_img_card_height"
android:orientation="vertical">
<FrameLayout
@ -24,7 +24,9 @@
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginLeft="10dp"
android:src="@drawable/ic_logo_mapillary"/>
android:visibility="gone"
tools:src="@drawable/ic_action_photo_dark"
tools:visibility="visible"/>
<TextView
android:id="@+id/watermark"
@ -35,10 +37,12 @@
android:paddingTop="4dp"
android:paddingRight="8dp"
android:paddingBottom="8dp"
android:background="@color/popup_bg_color"
android:background="@color/map_widget_dark"
android:textColor="@color/color_white"
android:textSize="@dimen/default_sub_text_size"
tools:text="\@user123 | mapillary.com"/>
android:visibility="gone"
tools:text="\@user123"
tools:visibility="visible"/>
<ProgressBar
android:id="@+id/progress"

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/mapillary_card_width"
android:layout_height="@dimen/mapillary_card_height"
android:layout_width="@dimen/context_img_card_width"
android:layout_height="@dimen/context_img_card_height"
android:background="?attr/bg_card"
android:gravity="center"
android:orientation="vertical">

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/mapillary_card_width"
android:layout_height="@dimen/mapillary_card_height"
android:layout_width="@dimen/context_img_card_width"
android:layout_height="@dimen/context_img_card_height"
android:background="?attr/bg_card"
android:orientation="vertical">

View file

@ -11,7 +11,7 @@
<dimen name="quick_action_widget_height_big">200dp</dimen>
<dimen name="quick_action_widget_height_small">100dp</dimen>
<dimen name="mapillary_card_width">280dp</dimen>
<dimen name="mapillary_card_height">160dp</dimen>
<dimen name="context_img_card_width">280dp</dimen>
<dimen name="context_img_card_height">160dp</dimen>
</resources>

View file

@ -895,6 +895,7 @@ public class OsmandSettings {
public final OsmandPreference<Boolean> SHOW_MAPILLARY = new BooleanPreference("show_mapillary", false).makeGlobal();
public final OsmandPreference<Boolean> MAPILLARY_FIRST_DIALOG_SHOWN = new BooleanPreference("mapillary_first_dialog_shown", false).makeGlobal();
public final OsmandPreference<Boolean> MAPILLARY_MENU_COLLAPSED = new BooleanPreference("mapillary_menu_collapsed", false).makeGlobal();
// this value string is synchronized with settings_pref.xml preference name
public final OsmandPreference<String> PREFERRED_LOCALE = new StringPreference("preferred_locale", "").makeGlobal();

View file

@ -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){

View file

@ -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<Boolean> collapsedPref;
private boolean collapsed;
private OnCollExpListener onCollExpListener;
public interface OnCollExpListener {
void onCollapseExpand(boolean collapsed);
}
public CollapsableView(@NonNull View contenView, @NonNull OsmandPreference<Boolean> 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() {

View file

@ -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;

View file

@ -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();
}

View file

@ -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<AbstractCard> 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<? extends AbstractCard> 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;
}
}
}

View file

@ -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> {
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 <P> void execute(AsyncTask<P, ?, ?> 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<I extends ImageCard> extends AsyncTask<Void, Void, List<I>> {
private OsmandApplication app;
private LatLon latLon;
private Listener<I> listener;
private ImageCardFactory<I> imageCardFactory;
private List<I> result;
public interface Listener<T extends ImageCard> {
void onFinish(List<T> cardList);
}
public GetImageCardsTask(@NonNull ImageCardFactory<I> imageCardFactory,
@NonNull OsmandApplication app, LatLon latLon, Listener<I> listener) {
this.imageCardFactory = imageCardFactory;
this.app = app;
this.latLon = latLon;
this.listener = listener;
}
@Override
protected List<I> doInBackground(Void... params) {
List<I> result = new ArrayList<>();
try {
final Map<String, String> 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<I> cardList) {
result = cardList;
if (listener != null) {
listener.onFinish(result);
}
}
}
private static <T extends ImageCard> void sortImagesInfo(List<T> cardList, @NonNull final Location location) {
List<T> targetCards = new ArrayList<>();
List<T> 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<ImageCard>() {
@Override
public int compare(ImageCard i1, ImageCard i2) {
return Float.compare(i1.bearingDiff, i2.bearingDiff);
}
});
Collections.sort(otherCards, new Comparator<ImageCard>() {
@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<Void, Void, Bitmap> {
@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();
}
}
}

View file

@ -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() {
}
}

View file

@ -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
}
});
}
}
}

View file

@ -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<MapillaryImageCard> {
@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
}
};
}
}

View file

@ -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;
}
}

View file

@ -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<MapillaryImageInfo> 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<Void, MapillaryImageInfo, List<MapillaryImageInfo>> {
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<MapillaryImageInfo> 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<MapillaryImageInfo> 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<String, String> 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<MapillaryImageInfo> 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<MapillaryImageInfo> infoList, final float azimuth, final LatLon menuLatLon) {
Collections.sort(infoList, new Comparator<MapillaryImageInfo>() {
@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<Void, Void, Void> {
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();
}
}
}
}

View file

@ -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<AbstractCard> 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<MapillaryImageCard>() {
@Override
public void onFinish(List<MapillaryImageCard> cardList) {
if (!menuBuilder.isHidden()) {
List<AbstractCard> 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);