diff --git a/mobile/libs/android-support-v4.jar b/mobile/libs/android-support-v4.jar index 428bdbc0..cf12d283 100644 Binary files a/mobile/libs/android-support-v4.jar and b/mobile/libs/android-support-v4.jar differ diff --git a/mobile/res/drawable-hdpi/drawer_shadow.9.png b/mobile/res/drawable-hdpi/drawer_shadow.9.png new file mode 100644 index 00000000..224cc4ff Binary files /dev/null and b/mobile/res/drawable-hdpi/drawer_shadow.9.png differ diff --git a/mobile/res/drawable-hdpi/ic_drawer.png b/mobile/res/drawable-hdpi/ic_drawer.png new file mode 100644 index 00000000..ff7b1def Binary files /dev/null and b/mobile/res/drawable-hdpi/ic_drawer.png differ diff --git a/mobile/res/drawable-mdpi/drawer_shadow.9.png b/mobile/res/drawable-mdpi/drawer_shadow.9.png new file mode 100644 index 00000000..3797f99c Binary files /dev/null and b/mobile/res/drawable-mdpi/drawer_shadow.9.png differ diff --git a/mobile/res/drawable-mdpi/ic_drawer.png b/mobile/res/drawable-mdpi/ic_drawer.png new file mode 100644 index 00000000..fb681ba2 Binary files /dev/null and b/mobile/res/drawable-mdpi/ic_drawer.png differ diff --git a/mobile/res/drawable-xhdpi/drawer_shadow.9.png b/mobile/res/drawable-xhdpi/drawer_shadow.9.png new file mode 100644 index 00000000..fa3d853e Binary files /dev/null and b/mobile/res/drawable-xhdpi/drawer_shadow.9.png differ diff --git a/mobile/res/drawable-xhdpi/ic_drawer.png b/mobile/res/drawable-xhdpi/ic_drawer.png new file mode 100644 index 00000000..b9bc3d70 Binary files /dev/null and b/mobile/res/drawable-xhdpi/ic_drawer.png differ diff --git a/mobile/res/layout/activity_main.xml b/mobile/res/layout/activity_main.xml index 01392b66..9adcdcae 100644 --- a/mobile/res/layout/activity_main.xml +++ b/mobile/res/layout/activity_main.xml @@ -1,18 +1,33 @@ - + - - + - \ No newline at end of file + + + + + + + + \ No newline at end of file diff --git a/mobile/res/values/strings.xml b/mobile/res/values/strings.xml index 2e067082..37c4591c 100644 --- a/mobile/res/values/strings.xml +++ b/mobile/res/values/strings.xml @@ -7,6 +7,8 @@ Share using… Copy to clipboard Settings + Show navigation menu + Hide navigation menu Reload IITC Print Version Toggle fullscreen diff --git a/mobile/src/com/cradle/iitc_mobile/IITC_JSInterface.java b/mobile/src/com/cradle/iitc_mobile/IITC_JSInterface.java index 9a67439e..0822a5e2 100644 --- a/mobile/src/com/cradle/iitc_mobile/IITC_JSInterface.java +++ b/mobile/src/com/cradle/iitc_mobile/IITC_JSInterface.java @@ -18,12 +18,14 @@ import android.widget.AdapterView; import android.widget.ListView; import android.widget.Toast; +import com.cradle.iitc_mobile.IITC_NavigationHelper.Pane; import com.cradle.iitc_mobile.share.ShareActivity; import org.json.JSONArray; import org.json.JSONException; import java.util.HashMap; +import java.util.Locale; // provide communication between IITC script and android app public class IITC_JSInterface { @@ -102,14 +104,14 @@ public class IITC_JSInterface { iitcm.runOnUiThread(new Runnable() { @Override public void run() { - IITC_NavigationHelper navigation = iitcm.getNavigationHelper(); - Integer button = IITC_Mobile.PANES.get(id); + Pane pane; + try { + pane = Pane.valueOf(id.toUpperCase(Locale.getDefault())); + } catch (IllegalArgumentException e) { + pane = Pane.MAP; + } - if (button == null) - button = android.R.id.home; - - navigation.switchTo(button); - iitcm.backStackUpdate(button); + iitcm.setCurrentPane(pane); } }); } diff --git a/mobile/src/com/cradle/iitc_mobile/IITC_Mobile.java b/mobile/src/com/cradle/iitc_mobile/IITC_Mobile.java index c3959f15..e9c25609 100644 --- a/mobile/src/com/cradle/iitc_mobile/IITC_Mobile.java +++ b/mobile/src/com/cradle/iitc_mobile/IITC_Mobile.java @@ -17,8 +17,8 @@ import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.preference.PreferenceManager; +import android.support.v4.widget.DrawerLayout; import android.util.Log; -import android.util.SparseArray; import android.view.Menu; import android.view.MenuItem; import android.view.View; @@ -27,19 +27,25 @@ import android.view.WindowManager; import android.webkit.CookieManager; import android.webkit.WebSettings; import android.webkit.WebView; +import android.widget.ListView; import android.widget.SearchView; import android.widget.Toast; +import com.cradle.iitc_mobile.IITC_NavigationHelper.Pane; + import java.io.IOException; import java.net.URISyntaxException; import java.util.ArrayList; -import java.util.HashMap; +import java.util.Locale; +import java.util.Stack; public class IITC_Mobile extends Activity { private static final int REQUEST_LOGIN = 1; private IITC_WebView mIitcWebView; + private DrawerLayout mDrawerLayout; + private ListView mDrawerList; private OnSharedPreferenceChangeListener mSharedPrefChangeListener; private final String mIntelUrl = "https://www.ingress.com/intel"; private boolean mIsLocEnabled = false; @@ -57,32 +63,11 @@ public class IITC_Mobile extends Activity { private IITC_NavigationHelper mNavigationHelper; // Used for custom back stack handling - private final ArrayList mBackStack = new ArrayList(); + private final Stack mBackStack = new Stack(); private boolean mBackStackPush = true; - private int mCurrentPane = android.R.id.home; + private Pane mCurrentPane = Pane.MAP; private boolean mBackButtonPressed = false; - public static final SparseArray PANE_TITLES = new SparseArray(); - public static final HashMap PANES = new HashMap(); - - static { - PANES.put("map", android.R.id.home); - PANES.put("info", R.id.menu_info); - PANES.put("full", R.id.menu_full); - PANES.put("compact", R.id.menu_compact); - PANES.put("public", R.id.menu_public); - PANES.put("faction", R.id.menu_faction); - PANES.put("debug", R.id.menu_debug); - - // No need to declare android.R.id.home - that title is default - PANE_TITLES.append(R.id.menu_info, "Info"); - PANE_TITLES.append(R.id.menu_full, "Full"); - PANE_TITLES.append(R.id.menu_compact, "Compact"); - PANE_TITLES.append(R.id.menu_public, "Public"); - PANE_TITLES.append(R.id.menu_faction, "Faction"); - PANE_TITLES.append(R.id.menu_debug, "Debug"); - } - @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -92,9 +77,11 @@ public class IITC_Mobile extends Activity { setContentView(R.layout.activity_main); mIitcWebView = (IITC_WebView) findViewById(R.id.iitc_webview); + mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); + mDrawerList = (ListView) findViewById(R.id.left_drawer); // pass ActionBar to helper because we deprecated getActionBar - mNavigationHelper = new IITC_NavigationHelper(this, super.getActionBar()); + mNavigationHelper = new IITC_NavigationHelper(this, super.getActionBar(), mDrawerList, mDrawerLayout); // do something if user changed something in the settings mSharedPrefs = PreferenceManager.getDefaultSharedPreferences(this); @@ -224,8 +211,8 @@ public class IITC_Mobile extends Activity { (SearchView) mSearchMenuItem.getActionView(); searchView.setQuery(query, false); searchView.clearFocus(); - mNavigationHelper.switchTo(android.R.id.home); - backStackUpdate(android.R.id.home); + + switchToPane(Pane.MAP); mIitcWebView.loadUrl("javascript:search('" + query + "');"); return; } @@ -318,11 +305,19 @@ public class IITC_Mobile extends Activity { public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); + mNavigationHelper.onConfigurationChanged(newConfig); + Log.d("iitcm", "configuration changed...restoring...reset idleTimer"); mIitcWebView.loadUrl("javascript: window.idleTime = 0"); mIitcWebView.loadUrl("javascript: window.renderUpdateStatus()"); } + @Override + protected void onPostCreate(Bundle savedInstanceState) { + super.onPostCreate(savedInstanceState); + mNavigationHelper.onPostCreate(savedInstanceState); + } + // we want a self defined behavior for the back button @Override public void onBackPressed() { @@ -364,31 +359,30 @@ public class IITC_Mobile extends Activity { // shouldn't be called when back stack is empty // catch wrong usage if (mBackStack.isEmpty()) { - // Empty back stack means we should be at home (ie map) screen - mNavigationHelper.switchTo(android.R.id.home); - mIitcWebView.loadUrl("javascript: window.show('map');"); - return; + mBackStack.push(Pane.MAP); } - int index = mBackStack.size() - 1; - int itemId = mBackStack.remove(index); + + Pane pane = mBackStack.pop(); mBackStackPush = false; - handleMenuItemSelected(itemId); + switchToPane(pane); } - public void backStackUpdate(int itemId) { + public void setCurrentPane(Pane pane) { // ensure no double adds - if (itemId == mCurrentPane) return; - if (itemId == android.R.id.home) { - mBackStack.clear(); - mBackStackPush = true; - } else { - if (mBackStackPush) - mBackStack.add(mCurrentPane); - else - mBackStackPush = true; - } + if (pane == mCurrentPane) return; - mCurrentPane = itemId; + if (mBackStackPush) + mBackStack.push(mCurrentPane); + else + mBackStackPush = true; + + mCurrentPane = pane; + mNavigationHelper.switchTo(pane); + } + + public void switchToPane(Pane pane) { + String name = pane.name().toLowerCase(Locale.getDefault()); + mIitcWebView.loadUrl("javascript: window.show('" + name + "');"); } @Override @@ -411,16 +405,17 @@ public class IITC_Mobile extends Activity { @Override public boolean onOptionsItemSelected(MenuItem item) { + if (mNavigationHelper.onOptionsItemSelected(item)) + return true; + // Handle item selection final int itemId = item.getItemId(); - boolean result = handleMenuItemSelected(itemId); - return result || super.onOptionsItemSelected(item); - } - public boolean handleMenuItemSelected(int itemId) { switch (itemId) { case android.R.id.home: - mIitcWebView.loadUrl("javascript: window.show('map');"); + mBackStack.clear(); + mBackStackPush = false; + switchToPane(Pane.MAP); return true; case R.id.reload_button: reloadIITC(); @@ -430,13 +425,13 @@ public class IITC_Mobile extends Activity { return true; case R.id.layer_chooser: // Force map view to handle potential issue with back stack - if (!mBackStack.isEmpty() && mCurrentPane != android.R.id.home) - mIitcWebView.loadUrl("javascript: window.show('map');"); + if (!mBackStack.isEmpty() && mCurrentPane != Pane.MAP) + switchToPane(Pane.MAP); // the getLayers function calls the setLayers method of IITC_JSInterface mIitcWebView.loadUrl("javascript: window.layerChooser.getLayers()"); return true; case R.id.locate: // get the users current location and focus it on map - mIitcWebView.loadUrl("javascript: window.show('map');"); + switchToPane(Pane.MAP); // get location from network by default if (!mIsLocEnabled) { mIitcWebView.loadUrl("javascript: " + @@ -456,22 +451,22 @@ public class IITC_Mobile extends Activity { startActivity(intent); return true; case R.id.menu_info: - mIitcWebView.loadUrl("javascript: window.show('info');"); + switchToPane(Pane.INFO); return true; case R.id.menu_full: - mIitcWebView.loadUrl("javascript: window.show('full');"); + switchToPane(Pane.FULL); return true; case R.id.menu_compact: - mIitcWebView.loadUrl("javascript: window.show('compact');"); + switchToPane(Pane.COMPACT); return true; case R.id.menu_public: - mIitcWebView.loadUrl("javascript: window.show('public');"); + switchToPane(Pane.PUBLIC); return true; case R.id.menu_faction: - mIitcWebView.loadUrl("javascript: window.show('faction');"); + switchToPane(Pane.FACTION); return true; case R.id.menu_debug: - mIitcWebView.loadUrl("javascript: window.show('debug')"); + switchToPane(Pane.DEBUG); return true; case R.id.menu_clear_cookies: CookieManager cm = CookieManager.getInstance(); @@ -485,8 +480,9 @@ public class IITC_Mobile extends Activity { public void reloadIITC() { mNavigationHelper.reset(); mBackStack.clear(); + mBackStackPush = true; // iitc starts on map after reload - mCurrentPane = android.R.id.home; + mCurrentPane = Pane.MAP; loadUrl(mIntelUrl); mReloadNeeded = false; } diff --git a/mobile/src/com/cradle/iitc_mobile/IITC_NavigationHelper.java b/mobile/src/com/cradle/iitc_mobile/IITC_NavigationHelper.java index ac1b7adc..9283441a 100644 --- a/mobile/src/com/cradle/iitc_mobile/IITC_NavigationHelper.java +++ b/mobile/src/com/cradle/iitc_mobile/IITC_NavigationHelper.java @@ -3,11 +3,20 @@ package com.cradle.iitc_mobile; import android.app.ActionBar; import android.app.ActionBar.OnNavigationListener; import android.content.SharedPreferences; +import android.os.Bundle; import android.preference.PreferenceManager; +import android.support.v4.app.ActionBarDrawerToggle; +import android.support.v4.widget.DrawerLayout; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; +import android.widget.ListView; +import android.widget.TextView; import android.widget.Toast; -public class IITC_NavigationHelper implements OnNavigationListener { +public class IITC_NavigationHelper extends ActionBarDrawerToggle implements OnNavigationListener, OnItemClickListener { // Show/hide the up arrow on the very left // getActionBar().setDisplayHomeAsUpEnabled(enabled); @@ -20,6 +29,60 @@ public class IITC_NavigationHelper implements OnNavigationListener { // Makes the icon/title clickable // getActionBar().setHomeButtonEnabled(enabled); + public static enum Pane { + MAP, INFO, FULL, COMPACT, PUBLIC, FACTION, DEBUG + }; + + public String getPaneTitle(Pane pane) + { + switch (pane) { + case INFO: + return "Info"; + case FULL: + return "Full"; + case COMPACT: + return "Compact"; + case PUBLIC: + return "Public"; + case FACTION: + return "Faction"; + case DEBUG: + return "Debug"; + default: + return mIitc.getString(R.string.app_name); + } + } + + private class NavigationAdapter extends ArrayAdapter { + public NavigationAdapter() { + super(mIitc, android.R.layout.simple_list_item_1); + + addAll(Pane.values()); + // TODO: remove debug according to preferences + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + /* + * LayoutInflater inflater = ((Activity) getContext()).getLayoutInflater(); + * TextView view = (TextView) inflater.inflate(android.R.layout.simple_list_item_1, parent, false); + * + * ActivityInfo info = getItem(position).activityInfo; + * CharSequence label = info.loadLabel(mPackageManager); + * Drawable icon = info.loadIcon(mPackageManager); + * + * view.setText(label); + * view.setCompoundDrawablePadding((int) getResources().getDimension(R.dimen.icon_margin)); + * view.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null); + * + * return view; + */ + TextView view = (TextView) super.getView(position, convertView, parent); + view.setText(getPaneTitle(getItem(position))); + return view; + } + } + private class HighlighterAdapter extends ArrayAdapter { public HighlighterAdapter() { super(mIitc, android.R.layout.simple_list_item_1); @@ -43,43 +106,61 @@ public class IITC_NavigationHelper implements OnNavigationListener { private ActionBar mActionBar; private SharedPreferences mPrefs; private HighlighterAdapter mHighlighters; + private NavigationAdapter mNavigationAdapter; + private DrawerLayout mDrawerLayout; + private ListView mDrawerList; private String mActiveHighlighter = null; private boolean mDesktopMode = false; private boolean mFullscreen = false; private boolean mHideInFullscreen = false; - private int mPane = android.R.id.home; + private Pane mPane = Pane.MAP; + + public IITC_NavigationHelper(IITC_Mobile activity, ActionBar bar, ListView drawerList, DrawerLayout drawerLayout) { + super(activity, drawerLayout, R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close); - public IITC_NavigationHelper(IITC_Mobile activity, ActionBar bar) { mIitc = activity; mActionBar = bar; + mDrawerList = drawerList; + mDrawerLayout = drawerLayout; + mPrefs = PreferenceManager.getDefaultSharedPreferences(activity); mHighlighters = new HighlighterAdapter(); mActionBar.setDisplayShowHomeEnabled(true); // show icon mActionBar.setListNavigationCallbacks(mHighlighters, this); + mNavigationAdapter = new NavigationAdapter(); + mDrawerList.setAdapter(mNavigationAdapter); + mDrawerList.setOnItemClickListener(this); + mDrawerLayout.setDrawerListener(this); + onPrefChanged(); // also calls updateActionBar() } private void updateActionBar() { + // TODO setDisplayHomeAsUpEnabled should always be true on mobile mode + // TODO hide draw list in desktop mode boolean showHighlighter = true; if (mDesktopMode) { mActionBar.setDisplayHomeAsUpEnabled(false); // Hide "up" indicator mActionBar.setHomeButtonEnabled(false); // Make icon unclickable mActionBar.setTitle(mIitc.getString(R.string.app_name)); + mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); + setDrawerIndicatorEnabled(false); } else { - if (mPane != android.R.id.home) { - mActionBar.setDisplayHomeAsUpEnabled(true); // Show "up" indicator - mActionBar.setHomeButtonEnabled(true);// Make icon clickable + mActionBar.setDisplayHomeAsUpEnabled(true); // Show "up" indicator + mActionBar.setHomeButtonEnabled(true);// Make icon clickable + mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED); + if (mPane != Pane.MAP) { showHighlighter = false; + setDrawerIndicatorEnabled(false); } - else { - mActionBar.setDisplayHomeAsUpEnabled(false); // Hide "up" indicator - mActionBar.setHomeButtonEnabled(false); // Make icon unclickable - } - mActionBar.setTitle(IITC_Mobile.PANE_TITLES.get(mPane, mIitc.getString(R.string.app_name))); + else + setDrawerIndicatorEnabled(true); + + mActionBar.setTitle(getPaneTitle(mPane)); } if (mHighlighters.getCount() < 2) // there should always be "No Highlights" @@ -116,6 +197,7 @@ public class IITC_NavigationHelper implements OnNavigationListener { public boolean onNavigationItemSelected(int position, long itemId) { String name = mHighlighters.getItem(position); mIitc.getWebView().loadUrl("javascript: window.changePortalHighlights('" + name + "')"); + return true; } @@ -127,7 +209,7 @@ public class IITC_NavigationHelper implements OnNavigationListener { public void reset() { mHighlighters.clear(); - mPane = android.R.id.home; + mPane = Pane.MAP; updateActionBar(); } @@ -151,8 +233,33 @@ public class IITC_NavigationHelper implements OnNavigationListener { updateActionBar(); } - public void switchTo(int button) { - mPane = button; + public void switchTo(Pane pane) { + mPane = pane; + updateActionBar(); } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + Pane item = mNavigationAdapter.getItem(position); + mIitc.switchToPane(item); + mDrawerLayout.closeDrawer(mDrawerList); + } + + @Override + public void onDrawerOpened(View drawerView) { + // TODO Auto-generated method stub + super.onDrawerOpened(drawerView); + } + + @Override + public void onDrawerClosed(View drawerView) { + // TODO Auto-generated method stub + super.onDrawerClosed(drawerView); + } + + public void onPostCreate(Bundle savedInstanceState) { + // Sync the toggle state after onRestoreInstanceState has occurred. + syncState(); + } }