Improved permalink/portal link
Now shows a dialog from which you can: * share the permalink using the standard android share feature * copy the link to the clipboard * open the intel map link with an installed browser * show the map with an installed map application (that supports geo: URIs)
@ -52,7 +52,6 @@ window.renderPortalDetails = function(guid) {
|
|||||||
var poslinks = 'window.showPortalPosLinks('+lat+','+lng+',\''+escapeJavascriptString(d.portalV2.descriptiveText.TITLE)+'\')';
|
var poslinks = 'window.showPortalPosLinks('+lat+','+lng+',\''+escapeJavascriptString(d.portalV2.descriptiveText.TITLE)+'\')';
|
||||||
var portalDetailObj = window.getPortalDescriptionFromDetailsExtended(d);
|
var portalDetailObj = window.getPortalDescriptionFromDetailsExtended(d);
|
||||||
|
|
||||||
|
|
||||||
var portalDetailedDescription = '';
|
var portalDetailedDescription = '';
|
||||||
|
|
||||||
if(portalDetailObj) {
|
if(portalDetailObj) {
|
||||||
@ -101,8 +100,12 @@ window.renderPortalDetails = function(guid) {
|
|||||||
+ randDetails
|
+ randDetails
|
||||||
+ resoDetails
|
+ resoDetails
|
||||||
+ '<div class="linkdetails">'
|
+ '<div class="linkdetails">'
|
||||||
+ '<aside><a href="'+perma+'" onclick="return androidCopy(this.href)" title="Create a URL link to this portal" >Portal link</a></aside>'
|
+ (
|
||||||
+ '<aside><a onclick="'+poslinks+'" title="Link to alternative maps (Google, etc)">Map links</a></aside>'
|
typeof android !== 'undefined' && android && android.intentPosLink // Android handles both links via a dialog
|
||||||
|
? '<aside><a onclick="'+poslinks+'" title="Create a URL link to this portal" >Portal link</a></aside>'
|
||||||
|
: '<aside><a href="'+perma+'" onclick="return androidCopy(this.href)" title="Create a URL link to this portal" >Portal link</a></aside>'
|
||||||
|
+ '<aside><a onclick="'+poslinks+'" title="Link to alternative maps (Google, etc)">Map links</a></aside>'
|
||||||
|
)
|
||||||
+ '<aside><a onclick="window.reportPortalIssue()" title="Report issues with this portal to Niantic/Google">Report issue</a></aside>'
|
+ '<aside><a onclick="window.reportPortalIssue()" title="Report issues with this portal to Niantic/Google">Report issue</a></aside>'
|
||||||
+ '</div>'
|
+ '</div>'
|
||||||
);
|
);
|
||||||
|
@ -176,7 +176,7 @@ window.showPortalPosLinks = function(lat, lng, name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (typeof android !== 'undefined' && android && android.intentPosLink) {
|
if (typeof android !== 'undefined' && android && android.intentPosLink) {
|
||||||
android.intentPosLink(lat, lng, encoded_name);
|
android.intentPosLink(lat, lng, map.getZoom(), name);
|
||||||
} else {
|
} else {
|
||||||
var qrcode = '<div id="qrcode"></div>';
|
var qrcode = '<div id="qrcode"></div>';
|
||||||
var script = '<script>$(\'#qrcode\').qrcode({text:\'GEO:'+lat+','+lng+'\'});</script>';
|
var script = '<script>$(\'#qrcode\').qrcode({text:\'GEO:'+lat+','+lng+'\'});</script>';
|
||||||
@ -200,6 +200,15 @@ window.androidCopy = function(text) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.androidPermalink = function() {
|
||||||
|
if(typeof android === 'undefined' || !android || !android.copy)
|
||||||
|
return true; // i.e. execute other actions
|
||||||
|
|
||||||
|
var center = map.getCenter();
|
||||||
|
android.intentPosLink(center.lat, center.lng, map.getZoom(), null);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
window.reportPortalIssue = function(info) {
|
window.reportPortalIssue = function(info) {
|
||||||
var t = 'Redirecting you to a Google Help Page.\n\nThe text box contains all necessary information. Press CTRL+C to copy it.';
|
var t = 'Redirecting you to a Google Help Page.\n\nThe text box contains all necessary information. Press CTRL+C to copy it.';
|
||||||
var d = window.portals[window.selectedPortal].options.details;
|
var d = window.portals[window.selectedPortal].options.details;
|
||||||
|
2
main.js
@ -96,7 +96,7 @@ document.getElementsByTagName('body')[0].innerHTML = ''
|
|||||||
// redeeming removed from stock site, so commented out for now. it may return...
|
// redeeming removed from stock site, so commented out for now. it may return...
|
||||||
// + ' <input id="redeem" placeholder="Redeem code…" type="text"/>'
|
// + ' <input id="redeem" placeholder="Redeem code…" type="text"/>'
|
||||||
+ ' <div id="toolbox">'
|
+ ' <div id="toolbox">'
|
||||||
+ ' <a onmouseover="setPermaLink(this)" onclick="setPermaLink(this);return androidCopy(this.href)" title="URL link to this map view">Permalink</a>'
|
+ ' <a onmouseover="setPermaLink(this)" onclick="setPermaLink(this);return androidPermalink()" title="URL link to this map view">Permalink</a>'
|
||||||
+ ' <a onclick="window.aboutIITC()" style="cursor: help">About IITC</a>'
|
+ ' <a onclick="window.aboutIITC()" style="cursor: help">About IITC</a>'
|
||||||
+ ' </div>'
|
+ ' </div>'
|
||||||
+ ' </div>'
|
+ ' </div>'
|
||||||
|
BIN
mobile/res/drawable-hdpi/ic_dialog_browser.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
mobile/res/drawable-hdpi/ic_dialog_copy.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
mobile/res/drawable-hdpi/ic_dialog_share.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
mobile/res/drawable-mdpi/ic_dialog_browser.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
mobile/res/drawable-mdpi/ic_dialog_copy.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
mobile/res/drawable-mdpi/ic_dialog_share.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
mobile/res/drawable-xhdpi/ic_dialog_browser.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
mobile/res/drawable-xhdpi/ic_dialog_copy.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
mobile/res/drawable-xhdpi/ic_dialog_share.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
@ -1,5 +1,11 @@
|
|||||||
package com.cradle.iitc_mobile;
|
package com.cradle.iitc_mobile;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONException;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.content.ClipData;
|
import android.content.ClipData;
|
||||||
import android.content.ClipboardManager;
|
import android.content.ClipboardManager;
|
||||||
@ -7,17 +13,11 @@ import android.content.Context;
|
|||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.DialogInterface.OnClickListener;
|
import android.content.DialogInterface.OnClickListener;
|
||||||
import android.content.DialogInterface.OnMultiChoiceClickListener;
|
import android.content.DialogInterface.OnMultiChoiceClickListener;
|
||||||
import android.content.Intent;
|
import android.os.Bundle;
|
||||||
import android.net.Uri;
|
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.webkit.JavascriptInterface;
|
import android.webkit.JavascriptInterface;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.json.JSONArray;
|
|
||||||
import org.json.JSONException;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
// provide communication between IITC script and android app
|
// provide communication between IITC script and android app
|
||||||
public class IITC_JSInterface {
|
public class IITC_JSInterface {
|
||||||
|
|
||||||
@ -35,13 +35,18 @@ public class IITC_JSInterface {
|
|||||||
context = c;
|
context = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
// send geo intent for navigation apps like gmaps or waze etc...
|
// open dialog to send geo intent for navigation apps like gmaps or waze etc...
|
||||||
@JavascriptInterface
|
@JavascriptInterface
|
||||||
public void intentPosLink(String lat, String lng, String portal_name) {
|
public void intentPosLink(double lat, double lng, int zoom, String portalName) {
|
||||||
String uri = "geo:" + lat + "," + lng + "?q=" + lat + "," + lng;
|
Bundle args = new Bundle();
|
||||||
Intent intent = new Intent(android.content.Intent.ACTION_VIEW,
|
args.putDouble("lat", lat);
|
||||||
Uri.parse(uri));
|
args.putDouble("lng", lng);
|
||||||
context.startActivity(intent);
|
args.putInt("zoom", zoom);
|
||||||
|
args.putString("title", portalName);
|
||||||
|
|
||||||
|
IITC_ShareDialog dialog = new IITC_ShareDialog();
|
||||||
|
dialog.setArguments(args);
|
||||||
|
dialog.show(((Activity) context).getFragmentManager(), "ShareDialog");
|
||||||
}
|
}
|
||||||
|
|
||||||
// disable javascript injection while spinner is enabled
|
// disable javascript injection while spinner is enabled
|
||||||
|
194
mobile/src/com/cradle/iitc_mobile/IITC_ShareDialog.java
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
package com.cradle.iitc_mobile;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.app.AlertDialog;
|
||||||
|
import android.app.Dialog;
|
||||||
|
import android.app.DialogFragment;
|
||||||
|
import android.content.ClipData;
|
||||||
|
import android.content.ClipboardManager;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.ComponentInfo;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.pm.ResolveInfo;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.Parcelable;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
public class IITC_ShareDialog extends DialogFragment {
|
||||||
|
private abstract class Action {
|
||||||
|
private int mIcon;
|
||||||
|
private String mLabel;
|
||||||
|
|
||||||
|
private Action(String label, int icon) {
|
||||||
|
mLabel = label;
|
||||||
|
mIcon = icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract void invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class OnClickListener implements DialogInterface.OnClickListener {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
mAdapter.getItem(which).invoke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ActionAdapter extends ArrayAdapter<Action> {
|
||||||
|
private LayoutInflater mInflater;
|
||||||
|
|
||||||
|
public ActionAdapter(Context context) {
|
||||||
|
super(context, android.R.layout.simple_list_item_1, ACTIONS);
|
||||||
|
mInflater = LayoutInflater.from(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View getView(int position, View convertView, ViewGroup parent) {
|
||||||
|
Action action = getItem(position);
|
||||||
|
|
||||||
|
if (convertView == null)
|
||||||
|
convertView = mInflater.inflate(android.R.layout.simple_list_item_1, null);
|
||||||
|
|
||||||
|
TextView tv = (TextView) convertView;
|
||||||
|
tv.setText(action.mLabel);
|
||||||
|
tv.setCompoundDrawablePadding(8);
|
||||||
|
tv.setCompoundDrawablesWithIntrinsicBounds(action.mIcon, 0, 0, 0);
|
||||||
|
return convertView;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final Action[] ACTIONS = {
|
||||||
|
new Action("Share…", R.drawable.ic_dialog_share) {
|
||||||
|
void invoke() {
|
||||||
|
Intent intent = new Intent(Intent.ACTION_SEND);
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
|
||||||
|
intent.setType("text/plain");
|
||||||
|
intent.putExtra(Intent.EXTRA_TEXT, getUrl());
|
||||||
|
intent.putExtra(Intent.EXTRA_SUBJECT, mTitle);
|
||||||
|
|
||||||
|
startIntent(intent);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Action("View map with app…", R.drawable.location_map) {
|
||||||
|
void invoke() {
|
||||||
|
String geoUri = "geo:" + mLl;
|
||||||
|
Intent intent = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(geoUri));
|
||||||
|
|
||||||
|
startIntent(intent);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Action("Open with browser…", R.drawable.ic_dialog_browser) {
|
||||||
|
void invoke() {
|
||||||
|
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(getUrl()));
|
||||||
|
|
||||||
|
startIntent(intent);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Action("Copy to clipboard", R.drawable.ic_dialog_copy) {
|
||||||
|
void invoke() {
|
||||||
|
ClipData clip = ClipData.newPlainText("Copied text", getUrl());
|
||||||
|
|
||||||
|
ClipboardManager clipboard = (ClipboardManager) getActivity().getSystemService(
|
||||||
|
Activity.CLIPBOARD_SERVICE);
|
||||||
|
clipboard.setPrimaryClip(clip);
|
||||||
|
|
||||||
|
Toast.makeText(getActivity(), "copied to clipboard", Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private ActionAdapter mAdapter;
|
||||||
|
private boolean mIsPortal = true;
|
||||||
|
private String mLl;
|
||||||
|
private String mTitle;
|
||||||
|
private int mZoom;
|
||||||
|
|
||||||
|
private String getUrl() {
|
||||||
|
String url = "http://www.ingress.com/intel?ll=" + mLl + "&z=" + mZoom;
|
||||||
|
if (mIsPortal)
|
||||||
|
url += "&pll=" + mLl;
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startIntent(Intent intent) {
|
||||||
|
// for geo: and Intel Map intents, the user may choose a default application to handle the intent. Since we have
|
||||||
|
// suitable intent filters declared, it might be that we *are* the default application. In theses cases, a list
|
||||||
|
// of designated applications is presented to the user
|
||||||
|
|
||||||
|
String packageName = getActivity().getPackageName();
|
||||||
|
|
||||||
|
PackageManager pm = getActivity().getPackageManager();
|
||||||
|
ResolveInfo mInfo = pm.resolveActivity(intent, 0);
|
||||||
|
|
||||||
|
if (mInfo.activityInfo.packageName.equals(packageName)) {
|
||||||
|
// note: Intent.createChooser would be shorter, but it also includes IITCm.
|
||||||
|
// Therefore, we'll filter the available activities
|
||||||
|
String label = null;
|
||||||
|
if (intent.getAction().equals(Intent.ACTION_SEND))
|
||||||
|
label = "Share via";
|
||||||
|
else if (intent.getAction().equals(Intent.ACTION_VIEW))
|
||||||
|
label = "Open with";
|
||||||
|
|
||||||
|
List<Intent> intents = new ArrayList<Intent>();
|
||||||
|
List<ResolveInfo> activities = getActivity().getPackageManager().queryIntentActivities(intent, 0);
|
||||||
|
|
||||||
|
if (!activities.isEmpty()) {
|
||||||
|
for (ResolveInfo resolveInfo : activities) {
|
||||||
|
ComponentInfo info;
|
||||||
|
if (resolveInfo.activityInfo != null)
|
||||||
|
info = resolveInfo.activityInfo;
|
||||||
|
else
|
||||||
|
// Exactly one if these two must be non-null (according to docs)
|
||||||
|
info = resolveInfo.serviceInfo;
|
||||||
|
|
||||||
|
if (info.packageName.equals(packageName)) // don't show IITCm
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// setComponent is used to route the intent towards the component
|
||||||
|
// setPackage is used to prevent Android from showing IITCm
|
||||||
|
// (without a package set, Android would still show all available components, including IITCm)
|
||||||
|
intents.add(new Intent(intent)
|
||||||
|
.setComponent(new ComponentName(info.packageName, info.name))
|
||||||
|
.setPackage(info.packageName));
|
||||||
|
}
|
||||||
|
|
||||||
|
intent = Intent.createChooser(intents.remove(intents.size() - 1), label);
|
||||||
|
intent.putExtra(Intent.EXTRA_INITIAL_INTENTS, intents.toArray(new Parcelable[] {}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
startActivity(intent);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||||
|
Bundle args = getArguments();
|
||||||
|
mTitle = args.getString("title");
|
||||||
|
mLl = args.getDouble("lat") + "," + args.getDouble("lng");
|
||||||
|
mZoom = args.getInt("zoom");
|
||||||
|
|
||||||
|
if (mTitle == null) {
|
||||||
|
mTitle = "Intel Map";
|
||||||
|
mIsPortal = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mAdapter = new ActionAdapter(getActivity());
|
||||||
|
|
||||||
|
return new AlertDialog.Builder(getActivity())
|
||||||
|
.setTitle(mTitle)
|
||||||
|
.setAdapter(mAdapter, new OnClickListener())
|
||||||
|
.create();
|
||||||
|
}
|
||||||
|
}
|