diff --git a/res/drawable-hdpi/drawer_shadow.9.png b/res/drawable-hdpi/drawer_shadow.9.png new file mode 100644 index 0000000..224cc4f Binary files /dev/null and b/res/drawable-hdpi/drawer_shadow.9.png differ diff --git a/res/drawable-hdpi/ic_drawer.png b/res/drawable-hdpi/ic_drawer.png new file mode 100644 index 0000000..ff7b1de Binary files /dev/null and b/res/drawable-hdpi/ic_drawer.png differ diff --git a/res/drawable-mdpi/drawer_shadow.9.png b/res/drawable-mdpi/drawer_shadow.9.png new file mode 100644 index 0000000..3797f99 Binary files /dev/null and b/res/drawable-mdpi/drawer_shadow.9.png differ diff --git a/res/drawable-mdpi/ic_drawer.png b/res/drawable-mdpi/ic_drawer.png new file mode 100644 index 0000000..fb681ba Binary files /dev/null and b/res/drawable-mdpi/ic_drawer.png differ diff --git a/res/drawable-xhdpi/drawer_shadow.9.png b/res/drawable-xhdpi/drawer_shadow.9.png new file mode 100644 index 0000000..fa3d853 Binary files /dev/null and b/res/drawable-xhdpi/drawer_shadow.9.png differ diff --git a/res/drawable-xhdpi/ic_drawer.png b/res/drawable-xhdpi/ic_drawer.png new file mode 100644 index 0000000..b9bc3d7 Binary files /dev/null and b/res/drawable-xhdpi/ic_drawer.png differ diff --git a/res/layout/activity_main.xml b/res/layout/activity_main.xml new file mode 100644 index 0000000..e2ded19 --- /dev/null +++ b/res/layout/activity_main.xml @@ -0,0 +1,27 @@ + + + + + + + + + + \ No newline at end of file diff --git a/res/layout/listitem_folder.xml b/res/layout/listitem_folder.xml new file mode 100644 index 0000000..75bc52f --- /dev/null +++ b/res/layout/listitem_folder.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/res/menu/main.xml b/res/menu/main.xml new file mode 100644 index 0000000..c002028 --- /dev/null +++ b/res/menu/main.xml @@ -0,0 +1,9 @@ + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml new file mode 100644 index 0000000..783b4ac --- /dev/null +++ b/res/values/strings.xml @@ -0,0 +1,15 @@ + + + + I2P-Bote + Settings + Hello world! + + Open nav + Close nav + + Inbox + Outbox + Sent + Trash + diff --git a/src/i2p/bote/BoteHelper.java b/src/i2p/bote/BoteHelper.java new file mode 100644 index 0000000..d9a4eb6 --- /dev/null +++ b/src/i2p/bote/BoteHelper.java @@ -0,0 +1,40 @@ +package i2p.bote; + +import java.util.List; + +import android.content.Context; + +import i2p.bote.folder.EmailFolder; + +public class BoteHelper { + public static EmailFolder getMailFolder(String folderName) { + List folders = I2PBote.getInstance().getEmailFolders(); + for (EmailFolder folder : folders) { + if (folder.getName() == folderName) + return folder; + } + return null; + } + + /** + * Get the translated name of the folder. + * Built-in folders are special-cased; other folders are created by the + * user, so their name is already "translated". + * @param ctx Android Context to get strings from. + * @param folder The folder. + * @return The name of the folder. + */ + public static String getFolderDisplayName(Context ctx, EmailFolder folder) { + String name = folder.getName(); + if ("inbox".equals(name)) + return ctx.getResources().getString(R.string.folder_inbox); + else if ("outbox".equals(name)) + return ctx.getResources().getString(R.string.folder_outbox); + else if ("sent".equals(name)) + return ctx.getResources().getString(R.string.folder_sent); + else if ("trash".equals(name)) + return ctx.getResources().getString(R.string.folder_trash); + else + return name; + } +} diff --git a/src/i2p/bote/FolderAdapter.java b/src/i2p/bote/FolderAdapter.java new file mode 100644 index 0000000..0f130f4 --- /dev/null +++ b/src/i2p/bote/FolderAdapter.java @@ -0,0 +1,40 @@ +package i2p.bote; + +import java.util.List; + +import i2p.bote.folder.EmailFolder; +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.TextView; + +public class FolderAdapter extends ArrayAdapter { + private final LayoutInflater mInflater; + + public FolderAdapter(Context context) { + super(context, android.R.layout.simple_list_item_2); + mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + } + + public void setData(List folders) { + clear(); + if (folders != null) { + for (EmailFolder folder : folders) { + add(folder); + } + } + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View v = mInflater.inflate(R.layout.listitem_folder, parent, false); + EmailFolder folder = getItem(position); + + TextView name = (TextView) v.findViewById(R.id.folder_name); + name.setText(BoteHelper.getFolderDisplayName(getContext(), folder)); + + return v; + } +} diff --git a/src/i2p/bote/FolderFragment.java b/src/i2p/bote/FolderFragment.java new file mode 100644 index 0000000..aab30d0 --- /dev/null +++ b/src/i2p/bote/FolderFragment.java @@ -0,0 +1,25 @@ +package i2p.bote; + +import i2p.bote.folder.EmailFolder; +import android.os.Bundle; +import android.support.v4.app.ListFragment; + +public class FolderFragment extends ListFragment { + public static final String FOLDER_NAME = "folder_name"; + + public static FolderFragment newInstance(String folderName) { + FolderFragment f = new FolderFragment(); + Bundle args = new Bundle(); + args.putString(FOLDER_NAME, folderName); + f.setArguments(args); + return f; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + String folderName = getArguments().getString(FOLDER_NAME); + EmailFolder folder = BoteHelper.getMailFolder(folderName); + } +} diff --git a/src/i2p/bote/MailListActivity.java b/src/i2p/bote/MailListActivity.java new file mode 100644 index 0000000..699e868 --- /dev/null +++ b/src/i2p/bote/MailListActivity.java @@ -0,0 +1,166 @@ +package i2p.bote; + +import i2p.bote.folder.EmailFolder; +import android.os.Bundle; +import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.support.v4.app.ActionBarDrawerToggle; +import android.support.v4.view.GravityCompat; +import android.support.v4.widget.DrawerLayout; +import android.support.v7.app.ActionBarActivity; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.AdapterView; +import android.widget.ListView; + +public class MailListActivity extends ActionBarActivity { + private CharSequence mDrawerTitle; + private CharSequence mTitle; + private SharedPreferences mSharedPrefs; + + /** + * Navigation drawer variables + */ + private DrawerLayout mDrawerLayout; + private FolderAdapter mFolderAdapter; + private ListView mFolderList; + private ActionBarDrawerToggle mDrawerToggle; + + private String mActiveFolder; + + private static final String SHARED_PREFS = "i2p.bote"; + private static final String PREF_NAV_DRAWER_OPENED = "navDrawerOpened"; + private static final String ACTIVE_FOLDER = "activeFolder"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + // Initialize variables + mTitle = mDrawerTitle = getTitle(); + mSharedPrefs = getSharedPreferences(SHARED_PREFS, 0); + mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); + mFolderAdapter = new FolderAdapter(this); + mFolderList = (ListView) findViewById(R.id.drawer); + + // Set the list of folders + // XXX: Does this need a loader? + mFolderAdapter.setData(I2PBote.getInstance().getEmailFolders()); + + // Set a custom shadow that overlays the main content when the drawer opens + mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START); + mFolderList.setChoiceMode(ListView.CHOICE_MODE_SINGLE); + // Set the adapter for the list view + mFolderList.setAdapter(mFolderAdapter); + // Set the list's click listener + mFolderList.setOnItemClickListener(new DrawerItemClickListener()); + + // Enable ActionBar app icon to behave as action to toggle nav drawer + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + getSupportActionBar().setHomeButtonEnabled(true); + + // Set up drawer toggle + mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, + R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close) { + private boolean wasDragged = false; + + /** Called when a drawer has settled in a completely closed state. */ + public void onDrawerClosed(View view) { + // Don't mark as opened if the user closed by dragging + // but uses the action bar icon to open + wasDragged = false; + getSupportActionBar().setTitle(mTitle); + supportInvalidateOptionsMenu(); + } + + /** Called when a drawer has settled in a completely open state. */ + public void onDrawerOpened(View view) { + if (wasDragged && !mSharedPrefs.getBoolean(PREF_NAV_DRAWER_OPENED, false)) { + SharedPreferences.Editor edit = mSharedPrefs.edit(); + edit.putBoolean(PREF_NAV_DRAWER_OPENED, true); + edit.commit(); + } + getSupportActionBar().setTitle(mDrawerTitle); + supportInvalidateOptionsMenu(); + } + + /** Called when the drawer motion state changes. */ + public void onDrawerStateChanged(int newState) { + if (newState == DrawerLayout.STATE_DRAGGING) + wasDragged = true; + } + }; + + // Set the drawer toggle as the DrawerListener + mDrawerLayout.setDrawerListener(mDrawerToggle); + + mActiveFolder = ""; + if (savedInstanceState != null) { + mActiveFolder = savedInstanceState.getString(ACTIVE_FOLDER); + } + FolderFragment f = FolderFragment.newInstance(mActiveFolder); + getSupportFragmentManager().beginTransaction() + .add(R.id.list_fragment, f).commit(); + + // Open nav drawer if the user has never opened it themselves + if (!mSharedPrefs.getBoolean(PREF_NAV_DRAWER_OPENED, false)) + mDrawerLayout.openDrawer(mFolderList); + } + + private class DrawerItemClickListener implements ListView.OnItemClickListener { + public void onItemClick(AdapterView parent, View view, int pos, long id) { + EmailFolder folder = mFolderAdapter.getItem(pos); + FolderFragment f = FolderFragment.newInstance(folder.getName()); + getSupportFragmentManager().beginTransaction() + .replace(R.id.list_fragment, f).commit(); + mDrawerLayout.closeDrawer(mFolderList); + } + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putString(ACTIVE_FOLDER, mActiveFolder); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu + getMenuInflater().inflate(R.menu.main, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // The action bar home/up action should open or close the drawer. + // ActionBarDrawerToggle will take care of this. + if(mDrawerToggle.onOptionsItemSelected(item)) { + return true; + } + + // Handle action buttons and overflow + return super.onOptionsItemSelected(item); + } + + @Override + public void setTitle(CharSequence title) { + mTitle = title; + getSupportActionBar().setTitle(mTitle); + } + + @Override + protected void onPostCreate(Bundle savedInstanceState) { + super.onPostCreate(savedInstanceState); + // Sync the toggle state after onRestoreInstanceState has occurred. + mDrawerToggle.syncState(); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + // Pass any configuration change to the drawer toggle + mDrawerToggle.onConfigurationChanged(newConfig); + } +}