diff --git a/build.py b/build.py index 42b1e4bf..8d64942b 100755 --- a/build.py +++ b/build.py @@ -8,7 +8,14 @@ import base64 import sys import os import shutil +import json +import shelve +import hashlib +try: + import urllib2 +except ImportError: + import urllib.request as urllib2 # load settings file from buildsettings import buildSettings @@ -66,6 +73,33 @@ def loaderRaw(var): fn = var.group(1) return readfile(fn) +def loaderMD(var): + fn = var.group(1) + # use different MD.dat's for python 2 vs 3 incase user switches versions, as they are not compatible + db = shelve.open('build/MDv' + str(sys.version_info.major) + '.dat') + if 'files' in db: + files = db['files'] + else: + files = {} + file = readfile(fn) + filemd5 = hashlib.md5(file.encode('utf8')).hexdigest() + # check if file has already been parsed by the github api + if fn in files and filemd5 in files[fn]: + # use the stored copy if nothing has changed to avoid hiting the api more then the 60/hour when not signed in + db.close() + return files[fn][filemd5] + else: + url = 'https://api.github.com/markdown' + payload = {'text': file, 'mode': 'markdown'} + headers = {'Content-Type': 'application/json'} + req = urllib2.Request(url, json.dumps(payload).encode('utf8'), headers) + md = urllib2.urlopen(req).read().decode('utf8').replace('\n', '').replace('\'', '\\\'') + files[fn] = {} + files[fn][filemd5] = md + db['files'] = files + db.close() + return md + def loaderImage(var): fn = var.group(1) return 'data:image/png;base64,{0}'.format(base64.encodestring(open(fn, 'rb').read()).decode('utf8').replace('\n', '')) @@ -86,6 +120,7 @@ def doReplacements(script,updateUrl,downloadUrl): script = re.sub('@@INCLUDERAW:([0-9a-zA-Z_./-]+)@@', loaderRaw, script) script = re.sub('@@INCLUDESTRING:([0-9a-zA-Z_./-]+)@@', loaderString, script) + script = re.sub('@@INCLUDEMD:([0-9a-zA-Z_./-]+)@@', loaderMD, script) script = re.sub('@@INCLUDEIMAGE:([0-9a-zA-Z_./-]+)@@', loaderImage, script) script = script.replace('@@BUILDDATE@@', buildDate) @@ -156,6 +191,14 @@ for fn in glob.glob("plugins/*.user.js"): metafn = fn.replace('.user.js', '.meta.js') saveScriptAndMeta(script, os.path.join(outDir,fn), os.path.join(outDir,metafn)) +def copytree(src, dst, symlinks=False, ignore=None): + for item in os.listdir(src): + s = os.path.join(src, item) + d = os.path.join(dst, item) + if os.path.isdir(s): + shutil.copytree(s, d, symlinks, ignore) + else: + shutil.copy2(s, d) # if we're building mobile too if buildMobile: @@ -169,7 +212,12 @@ if buildMobile: pass shutil.copy(os.path.join(outDir,"total-conversion-build.user.js"), "mobile/assets/iitc.js") - # TODO? also copy plugins - once the mobile app supports plugins, that is + # also copy plugins + try: + os.makedirs("mobile/assets/plugins") + except: + pass + copytree(os.path.join(outDir,"plugins"), "mobile/assets/plugins") # now launch 'ant' to build the mobile project diff --git a/code/map_data.js b/code/map_data.js index f367284b..a4998d4f 100644 --- a/code/map_data.js +++ b/code/map_data.js @@ -47,7 +47,7 @@ window.requestData = function() { portalRenderLimit.init(); // finally send ajax requests $.each(tiles, function(ind, tls) { - data = { minLevelOfDetail: -1 }; + data = { zoom: map.getZoom() }; data.boundsParamsList = tls; window.requests.add(window.postAjax('getThinnedEntitiesV2', data, window.handleDataResponse, window.handleFailedRequest)); }); diff --git a/code/map_data_calc_tools.js b/code/map_data_calc_tools.js index 2f383197..eca1b7e9 100644 --- a/code/map_data_calc_tools.js +++ b/code/map_data_calc_tools.js @@ -1,5 +1,4 @@ - // MAP DATA REQUEST CALCULATORS ////////////////////////////////////// // Ingress Intel splits up requests for map data (portals, links, // fields) into tiles. To get data for the current viewport (i.e. what @@ -23,9 +22,9 @@ window.calculateR = function(convCenterLat) { } window.convertLatLngToPoint = function(latlng, magic, R) { - var x = (magic/2 + latlng.lng * magic / 360)*R; + var x = (magic + latlng.lng * magic / 180)*R; var l = Math.sin(latlng.lat * DEG2RAD); - var y = (magic/2 + 0.5*Math.log((1+l)/(1-l)) * -(magic / (2*Math.PI)))*R; + var y = (magic + Math.log((1+l)/(1-l)) * -(magic / (2*Math.PI)))*R; return {x: Math.floor(x/magic), y: Math.floor(y/magic)}; } @@ -35,13 +34,13 @@ window.convertPointToLatLng = function(x, y, magic, R) { // orig function put together from all over the place // lat: (2 * Math.atan(Math.exp((((y + 1) * magic / R) - (magic/ 2)) / (-1*(magic / (2 * Math.PI))))) - Math.PI / 2) / (Math.PI / 180), // shortened version by your favorite algebra program. - lat: (360*Math.atan(Math.exp(Math.PI - 2*Math.PI*(y+1)/R)))/Math.PI - 90, - lng: 360*x/R-180 + lat: (360*Math.atan(Math.exp(Math.PI - Math.PI*(y+1)/R)))/Math.PI - 90, + lng: 180*x/R-180 }; e.ne = { //lat: (2 * Math.atan(Math.exp(((y * magic / R) - (magic/ 2)) / (-1*(magic / (2 * Math.PI))))) - Math.PI / 2) / (Math.PI / 180), - lat: (360*Math.atan(Math.exp(Math.PI - 2*Math.PI*y/R)))/Math.PI - 90, - lng: 360*(x+1)/R-180 + lat: (360*Math.atan(Math.exp(Math.PI - Math.PI*y/R)))/Math.PI - 90, + lng: 180*(x+1)/R-180 }; return e; } @@ -49,20 +48,7 @@ window.convertPointToLatLng = function(x, y, magic, R) { // calculates the quad key for a given point. The point is not(!) in // lat/lng format. window.pointToQuadKey = function(x, y) { - var quadkey = []; - for(var c = window.map.getZoom(); c > 0; c--) { - // +-------+ quadrants are probably ordered like this - // | 0 | 1 | - // |---|---| - // | 2 | 3 | - // |---|---| - var quadrant = 0; - var e = 1 << c - 1; - (x & e) != 0 && quadrant++; // push right - (y & e) != 0 && (quadrant++, quadrant++); // push down - quadkey.push(quadrant); - } - return quadkey.join(""); + return window.map.getZoom() + "_" + x + "_" + y; } // given quadkey and bounds, returns the format as required by the diff --git a/code/utils_misc.js b/code/utils_misc.js index 84562c92..4d12fcd9 100644 --- a/code/utils_misc.js +++ b/code/utils_misc.js @@ -1,7 +1,8 @@ // UTILS + MISC /////////////////////////////////////////////////////// window.aboutIITC = function(){ - var v = '@@BUILDNAME@@-@@BUILDDATE@@' + var v = '@@BUILDNAME@@-@@BUILDDATE@@'; + var attrib = '@@INCLUDEMD:ATTRIBUTION.md@@'; var a = '' + '
About IITC
' + '
Ingress Intel Total Conversion
' @@ -20,8 +21,11 @@ window.aboutIITC = function(){ + ' MapQuest OSM tiles Courtesy of MapQuest ' + ' ' + '
' - + '
Version: ' + v + '
'; - alert(a); + + '
Version: ' + v + '
' + + '
' + + '
' + attrib + '
'; + alert(a, true, function() {$('.ui-dialog').removeClass('ui-dialog-aboutIITC');}); + $('.ui-dialog').addClass('ui-dialog-aboutIITC'); } diff --git a/main.js b/main.js index 42da45b7..f87807ad 100644 --- a/main.js +++ b/main.js @@ -1,7 +1,7 @@ // ==UserScript== // @id ingress-intel-total-conversion@jonatkins // @name IITC: Ingress intel map total conversion -// @version 0.10.5.@@DATETIMEVERSION@@ +// @version 0.11.0.@@DATETIMEVERSION@@ // @namespace https://github.com/jonatkins/ingress-intel-total-conversion // @updateURL @@UPDATEURL@@ // @downloadURL @@DOWNLOADURL@@ diff --git a/mobile/.gitignore b/mobile/.gitignore index a56e372f..42222e62 100644 --- a/mobile/.gitignore +++ b/mobile/.gitignore @@ -7,3 +7,4 @@ libs/ proguard-project.txt local.properties assets/iitc.js +assets/plugins/ diff --git a/mobile/AndroidManifest.xml b/mobile/AndroidManifest.xml index d3fa4d8f..844d7462 100644 --- a/mobile/AndroidManifest.xml +++ b/mobile/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="11" + android:versionName="0.3" > UI + Plugins + Available plugins Force desktop mode Nice for tablets, looks awful on smartphones Developer options diff --git a/mobile/res/xml/preferences.xml b/mobile/res/xml/preferences.xml index fd50c037..2d72b3e1 100644 --- a/mobile/res/xml/preferences.xml +++ b/mobile/res/xml/preferences.xml @@ -17,6 +17,10 @@ android:title="@string/pref_force_desktop" android:summary="@string/pref_force_desktop_sum" android:defaultValue="false" /> + asset_list = new ArrayList(); + ArrayList asset_values = new ArrayList(); + + for (int i = 0; i < asset_array.length ; i++) { + if (asset_array[i].endsWith("user.js")) { + // find user plugin name for user readable entries + Scanner s = null; + String src = ""; + try { + s = new Scanner(am.open("plugins/" + asset_array[i])).useDelimiter("\\A"); + } catch (IOException e2) { + // TODO Auto-generated catch block + e2.printStackTrace(); + } + if (s != null) src = s.hasNext() ? s.next() : ""; + String header = src.substring(src.indexOf("==UserScript=="), src.indexOf("==/UserScript==")); + // remove new line comments and replace with space + // this way we get double spaces instead of newline + double slash + header = header.replace("\n//", " "); + // get a list of key-value...split on multiple spaces + String[] attributes = header.split(" +"); + String plugin_name = "not found"; + for (int j = 0; j < attributes.length; j++) { + // search for name and use the value + if (attributes[j].equals("@name")) plugin_name = attributes[j+1]; + } + asset_list.add(plugin_name); + // real value + asset_values.add(asset_array[i]); + } + } + + Bundle bundle = getIntent().getExtras(); + bundle.putStringArray("ASSETS", (String[]) asset_list.toArray(new String[0])); + bundle.putStringArray("ASSETS_VAL", (String[]) asset_values.toArray(new String[0])); + settings.setArguments(bundle); // Display the fragment as the main content. getFragmentManager().beginTransaction() diff --git a/mobile/src/com/cradle/iitc_mobile/IITC_SettingsFragment.java b/mobile/src/com/cradle/iitc_mobile/IITC_SettingsFragment.java index 34e3c0c0..5a68f307 100644 --- a/mobile/src/com/cradle/iitc_mobile/IITC_SettingsFragment.java +++ b/mobile/src/com/cradle/iitc_mobile/IITC_SettingsFragment.java @@ -6,6 +6,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.os.Bundle; import android.preference.EditTextPreference; import android.preference.ListPreference; +import android.preference.MultiSelectListPreference; import android.preference.Preference; import android.preference.Preference.OnPreferenceChangeListener; import android.preference.PreferenceFragment; @@ -21,7 +22,12 @@ public class IITC_SettingsFragment extends PreferenceFragment { iitc_version = getArguments().getString("iitc_version"); addPreferencesFromResource(R.xml.preferences); - + + //plugins + MultiSelectListPreference pref_plugins = (MultiSelectListPreference) findPreference("pref_plugins"); + pref_plugins.setEntries(getArguments().getStringArray("ASSETS")); + pref_plugins.setEntryValues(getArguments().getStringArray("ASSETS_VAL")); + // set build version ListPreference pref_build_version = (ListPreference) findPreference("pref_build_version"); PackageManager pm = getActivity().getPackageManager(); diff --git a/mobile/src/com/cradle/iitc_mobile/IITC_WebViewClient.java b/mobile/src/com/cradle/iitc_mobile/IITC_WebViewClient.java index d92d189d..d2a62897 100644 --- a/mobile/src/com/cradle/iitc_mobile/IITC_WebViewClient.java +++ b/mobile/src/com/cradle/iitc_mobile/IITC_WebViewClient.java @@ -3,6 +3,7 @@ package com.cradle.iitc_mobile; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.content.res.AssetManager; import android.net.Uri; import android.net.http.SslError; import android.preference.PreferenceManager; @@ -17,6 +18,7 @@ import java.io.InputStream; import java.io.IOException; import java.net.URL; import java.util.Scanner; +import java.util.Set; public class IITC_WebViewClient extends WebViewClient { private static final ByteArrayInputStream style = new ByteArrayInputStream( @@ -44,7 +46,7 @@ public class IITC_WebViewClient extends WebViewClient { String[] attributes = header.split(" +"); String iitc_version = "not found"; for (int i = 0; i < attributes.length; i++) { - // search vor version and use the value + // search for version and use the value if (attributes[i].equals("@version")) iitc_version = attributes[i+1]; } return iitc_version; @@ -91,6 +93,39 @@ public class IITC_WebViewClient extends WebViewClient { handler.proceed() ; }; + // plugins should be loaded after the main script is injected + @Override + public void onPageFinished(WebView view, String url) { + super.onPageFinished(view, url); + + // get the plugin preferences + SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(context); + Set plugin_list = sharedPref.getStringSet("pref_plugins", null); + + // iterate through all enabled plugins and load them + if (plugin_list != null) { + AssetManager am = context.getAssets(); + String[] plugin_array = plugin_list.toArray(new String[0]); + + for(int i = 0; i < plugin_list.size(); i++) { + if (plugin_array[i].endsWith("user.js")); + { + Log.d("iitcm", "adding plugin " + plugin_array[i]); + Scanner s = null; + String src = ""; + try { + s = new Scanner(am.open("plugins/" + plugin_array[i])).useDelimiter("\\A"); + } catch (IOException e2) { + // TODO Auto-generated catch block + e2.printStackTrace(); + } + if (s != null) src = s.hasNext() ? s.next() : ""; + view.loadUrl("javascript:" + src); + } + } + } + } + // Check every external resource if it’s okay to load it and maybe replace it // with our own content. This is used to block loading Niantic resources // which aren’t required and to inject IITC early into the site. @@ -119,6 +154,11 @@ public class IITC_WebViewClient extends WebViewClient { @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (url.contains("ingress.com")) { + // reload iitc if a poslink is clicked inside the app + if (url.contains("intel?ll=") || (url.contains("latE6") && url.contains("lngE6"))) { + Log.d("iitcm", "should be an internal clicked position link...reload script for: " + url); + ((IITC_Mobile) context).loadUrl(url); + } return false; } else { Log.d("iitcm", "no ingress intel link, start external app to load url: " + url); diff --git a/plugins/player-tracker.user.js b/plugins/player-tracker.user.js index 864a006a..7f20df6c 100644 --- a/plugins/player-tracker.user.js +++ b/plugins/player-tracker.user.js @@ -266,12 +266,13 @@ window.plugin.playerTracker.drawData = function() { if(window.plugin.guessPlayerLevels !== undefined && window.plugin.guessPlayerLevels.fetchLevelByPlayer !== undefined) { var playerLevel = window.plugin.guessPlayerLevels.fetchLevelByPlayer(pguid); - if (playerLevel === undefined) playerLevel = 1; //if player level unknown, assume level 1 if(playerLevel !== undefined) { title += 'Level ' + playerLevel + (playerLevel < (window.MAX_XM_PER_LEVEL.length - 1) ? ' (guessed)' : '') + ''; + } else { + title += 'Level unknown' } } diff --git a/style.css b/style.css index f86398d2..ad563fe2 100644 --- a/style.css +++ b/style.css @@ -766,6 +766,11 @@ h3 { text-decoration: underline; } +.ui-dialog-aboutIITC { + max-width: 600px !important; + width: 600px !important; +} + td { padding: 0; vertical-align: top;