Make a folder list fragment. Hook into Viki's app.
Also, hook up listeners for changing account in the
account spinner dropdown.
Change-Id: I0e6bbabc525c141fa581f49e6265c26bc767b8cf
diff --git a/res/layout/folder_list.xml b/res/layout/folder_list.xml
new file mode 100644
index 0000000..5b9ecc7
--- /dev/null
+++ b/res/layout/folder_list.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2012 Google Inc.
+ Licensed to The Android Open Source Project.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
+
+ <ListView
+ android:id="@android:id/list"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:cacheColorHint="@android:color/transparent"
+ android:drawSelectorOnTop="false"
+ android:fadingEdge="none" />
+
+ <TextView android:id="@+id/empty_view"
+ android:visibility="gone"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/folders_activity_instructions"/>
+
+</FrameLayout>
diff --git a/src/com/android/mail/AccountSpinnerAdapter.java b/src/com/android/mail/AccountSpinnerAdapter.java
index 7ad3e9c..800f293 100644
--- a/src/com/android/mail/AccountSpinnerAdapter.java
+++ b/src/com/android/mail/AccountSpinnerAdapter.java
@@ -30,6 +30,7 @@
import android.widget.SpinnerAdapter;
import android.widget.TextView;
+import com.android.mail.providers.Account;
import com.android.mail.providers.AccountCacheProvider;
import com.android.mail.providers.UIProvider;
import com.android.mail.utils.LogUtils;
@@ -99,9 +100,9 @@
TextView unread_count;
}
- private static final int TYPE_ACCOUNT = 0;
- private static final int TYPE_HEADER = 1;
- private static final int TYPE_FOLDER = 2;
+ public static final int TYPE_ACCOUNT = 0;
+ public static final int TYPE_HEADER = 1;
+ public static final int TYPE_FOLDER = 2;
private int getType(int position) {
// First the accounts
@@ -177,12 +178,12 @@
switch (getType(position)) {
case TYPE_ACCOUNT:
// The default Inbox for the given account
- accountName = getAccount(position);
+ accountName = getAccountLabel(position);
folderName = "Inbox";
break;
case TYPE_HEADER:
// We can never select the header, and we want the default view to be the Inbox.
- accountName = getAccount(0);
+ accountName = getAccountLabel(0);
folderName = "Inbox";
break;
default:
@@ -279,7 +280,7 @@
header.account.setText(mCurrentAccount);
return convertView;
case TYPE_ACCOUNT:
- textLabel = getAccount(position);
+ textLabel = getAccountLabel(position);
break;
case TYPE_FOLDER:
final int offset = position - numAccounts - 1;
@@ -316,12 +317,22 @@
* @param position
* @return
*/
- private String getAccount(int position) {
+ private String getAccountLabel(int position) {
mAccountCursor.moveToPosition(position);
final int accountNameCol = mAccountCursor.getColumnIndex(UIProvider.AccountColumns.NAME);
return mAccountCursor.getString(accountNameCol);
}
+ /**
+ * Returns the account given position in the spinner.
+ * @param position
+ * @return
+ */
+ private Account getAccount(int position) {
+ mAccountCursor.moveToPosition(position);
+ return new Account(mAccountCursor);
+ }
+
@Override
public boolean isEnabled(int position) {
diff --git a/src/com/android/mail/ui/AbstractActivityController.java b/src/com/android/mail/ui/AbstractActivityController.java
index dcee0ea..cae5cf0 100644
--- a/src/com/android/mail/ui/AbstractActivityController.java
+++ b/src/com/android/mail/ui/AbstractActivityController.java
@@ -33,6 +33,7 @@
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
+import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.Window;
@@ -196,9 +197,17 @@
protected abstract boolean isConversationListVisible();
@Override
- public boolean navigateToAccount(String account) {
- // TODO(viki): Auto-generated method stub
- return false;
+ public boolean navigateToAccount(Account account) {
+ if (!account.equals(mAccount)) {
+ mAccount = account;
+
+ final Intent intent = mActivity.getIntent();
+ // TODO(viki): Show the list context from Intent
+ mConvListContext = ConversationListContext.forIntent(mContext, mAccount, intent);
+ showConversationList(mConvListContext);
+ mViewMode.enterConversationListMode();
+ }
+ return true;
}
@Override
@@ -272,8 +281,9 @@
@Override
public boolean onCreateOptionsMenu(Menu menu) {
- // TODO(viki): Auto-generated method stub
- return false;
+ MenuInflater inflater = mActivity.getMenuInflater();
+ inflater.inflate(R.menu.conversation_list_menu, menu);
+ return true;
}
@Override
@@ -296,7 +306,12 @@
@Override
public boolean onOptionsItemSelected(MenuItem item) {
- // TODO(viki): Auto-generated method stub
+ int id = item.getItemId();
+ switch (id) {
+ case R.id.show_all_folders:
+ showFolderList();
+ break;
+ }
return false;
}
@@ -459,12 +474,6 @@
}
@Override
- public void showFolderList() {
- // TODO(viki): Auto-generated method stub
-
- }
-
- @Override
public void startActionBarStatusCursorLoader(String account) {
// TODO(viki): Auto-generated method stub
diff --git a/src/com/android/mail/ui/ActionbarActivity.java b/src/com/android/mail/ui/ActionbarActivity.java
index 261724b..9d9b6a2 100644
--- a/src/com/android/mail/ui/ActionbarActivity.java
+++ b/src/com/android/mail/ui/ActionbarActivity.java
@@ -19,6 +19,7 @@
import com.android.mail.ConversationListContext;
import com.android.mail.R;
+import com.android.mail.providers.Account;
import com.android.mail.ui.ActionBarView.Mode;
import com.android.mail.ui.MailActionBar.Callback;
@@ -127,7 +128,7 @@
}
@Override
- public boolean navigateToAccount(String account) {
+ public boolean navigateToAccount(Account account) {
// TODO(viki): Auto-generated method stub
return false;
}
diff --git a/src/com/android/mail/ui/ActivityController.java b/src/com/android/mail/ui/ActivityController.java
index 9cfd749..95e1b1f 100644
--- a/src/com/android/mail/ui/ActivityController.java
+++ b/src/com/android/mail/ui/ActivityController.java
@@ -212,4 +212,9 @@
* @param listContext context providing information on what conversation list to display.
*/
void showConversationList(ConversationListContext listContext);
+
+ /**
+ * Show the folder list associated with the currently selected account.
+ */
+ void showFolderList();
}
diff --git a/src/com/android/mail/ui/ControllableActivity.java b/src/com/android/mail/ui/ControllableActivity.java
index 56b086f..34acefa 100644
--- a/src/com/android/mail/ui/ControllableActivity.java
+++ b/src/com/android/mail/ui/ControllableActivity.java
@@ -66,4 +66,6 @@
* @return
*/
StarHandler getStarHandler();
+
+ void attachFolderList(FolderListFragment folderListFragment);
}
diff --git a/src/com/android/mail/ui/FolderListFragment.java b/src/com/android/mail/ui/FolderListFragment.java
new file mode 100644
index 0000000..c0f47fb
--- /dev/null
+++ b/src/com/android/mail/ui/FolderListFragment.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ * Licensed to The Android Open Source Project.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.mail.ui;
+
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.app.Activity;
+import android.app.Fragment;
+import android.app.FragmentTransaction;
+import android.app.ListFragment;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Parcelable;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.MarginLayoutParams;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemLongClickListener;
+import android.widget.ListView;
+import android.widget.SimpleCursorAdapter;
+import android.widget.TextView;
+
+import com.android.mail.R;
+import com.android.mail.providers.Folder;
+import com.android.mail.providers.UIProvider;
+import com.android.mail.utils.LogUtils;
+
+/**
+ * The conversation list UI component.
+ */
+public final class FolderListFragment extends ListFragment {
+ private static final String LOG_TAG = new LogUtils().getLogTag();
+
+ private ControllableActivity mActivity;
+
+ // Control state.
+ private Cursor mFolderListCursor;
+
+ // The internal view objects.
+ private ListView mListView;
+
+ private ContentResolver mResolver;
+
+ private String mFolderListUri;
+ /**
+ * Hidden constructor.
+ */
+ private FolderListFragment(String uri) {
+ super();
+ mFolderListUri = uri;
+ }
+
+ /**
+ * Creates a new instance of {@link ConversationListFragment}, initialized to display
+ * conversation list context.
+ */
+ public static FolderListFragment newInstance(String uri) {
+ FolderListFragment fragment = new FolderListFragment(uri);
+ return fragment;
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ // Strictly speaking, we get back an android.app.Activity from getActivity. However, the
+ // only activity creating a ConversationListContext is a MailActivity which is of type
+ // ControllableActivity, so this cast should be safe. If this cast fails, some other
+ // activity is creating ConversationListFragments. This activity must be of type
+ // ControllableActivity.
+ final Activity activity = getActivity();
+ if (! (activity instanceof ControllableActivity)){
+ LogUtils.wtf(LOG_TAG, "FolderListFragment expects only a ControllableActivity to" +
+ "create it. Cannot proceed.");
+ }
+ mActivity = (ControllableActivity) activity;
+ mActivity.attachFolderList(this);
+ mResolver = mActivity.getContentResolver();
+
+ if (mActivity.isFinishing()) {
+ // Activity is finishing, just bail.
+ return;
+ }
+
+ // Show list and start loading list.
+ showList();
+ }
+
+ @Override
+ public void onCreate(Bundle savedState) {
+ LogUtils.v(LOG_TAG, "onCreate in FolderListFragment(this=%s)", this);
+ super.onCreate(savedState);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater,
+ ViewGroup container, Bundle savedInstanceState) {
+ LogUtils.v(LOG_TAG, "onCreateView in FolderListFragment(this=%s)", this);
+ View rootView = inflater.inflate(R.layout.folder_list, null);
+ mListView = (ListView) rootView.findViewById(android.R.id.list);
+ mListView.setHeaderDividersEnabled(false);
+ mListView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
+
+ // Note - we manually save/restore the listview state.
+ mListView.setSaveEnabled(false);
+
+ return rootView;
+ }
+
+ @Override
+ public void onDestroyView() {
+ // Clear the adapter.
+ mListView.setAdapter(null);
+
+ mActivity.attachFolderList(null);
+
+ super.onDestroyView();
+ }
+
+ @Override
+ public void onListItemClick(ListView l, View v, int position, long id) {
+ viewFolder(position);
+ }
+
+ private void viewFolder(int position) {
+ mFolderListCursor.moveToPosition(position);
+ Folder selected = new Folder(mFolderListCursor);
+ if (selected.hasChildren) {
+ // Replace this fragment with a new FolderListFragment
+ // showing this folder's children.
+ FragmentTransaction fragmentTransaction = mActivity.getFragmentManager()
+ .beginTransaction();
+ fragmentTransaction.addToBackStack(null);
+ final boolean accountChanged = false;
+ // TODO(viki): This account transition looks strange in two pane
+ // mode. Revisit as the app
+ // is coming together and improve the look and feel.
+ final int transition = accountChanged ? FragmentTransaction.TRANSIT_FRAGMENT_FADE
+ : FragmentTransaction.TRANSIT_FRAGMENT_OPEN;
+ fragmentTransaction.setTransition(transition);
+
+ Fragment folderListFragment = FolderListFragment
+ .newInstance(selected.childFoldersListUri);
+ fragmentTransaction.add(R.id.content_pane, folderListFragment);
+
+ fragmentTransaction.commitAllowingStateLoss();
+
+ } else {
+ // Go to the conversation list for this folder.
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ }
+
+ /**
+ * Handles a request to show a new conversation list, either from a search query or for viewing
+ * a label. This will initiate a data load, and hence must be called on the UI thread.
+ */
+ private void showList() {
+ mListView.setEmptyView(null);
+
+ mFolderListCursor = mResolver.query(Uri.parse(mFolderListUri),
+ UIProvider.FOLDERS_PROJECTION, null, null, null);
+ mListView.setAdapter(new FolderListAdapter(mActivity.getActivityContext(),
+ R.layout.folder_item, mFolderListCursor, null, null));
+ }
+
+ private class FolderListAdapter extends SimpleCursorAdapter {
+
+ public FolderListAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
+ super(context, layout, c, new String[0], new int[0], 0);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ FolderItemView folderItemView;
+ if (convertView != null) {
+ folderItemView = (FolderItemView) convertView;
+ } else {
+ folderItemView = (FolderItemView) LayoutInflater.from(
+ mActivity.getActivityContext()).inflate(R.layout.folder_item, null);
+ }
+ getCursor().moveToPosition(position);
+ folderItemView.bind(new Folder(getCursor()), null);
+ return folderItemView;
+ }
+ }
+}
diff --git a/src/com/android/mail/ui/MailActionBar.java b/src/com/android/mail/ui/MailActionBar.java
index cb73b79..0277379 100644
--- a/src/com/android/mail/ui/MailActionBar.java
+++ b/src/com/android/mail/ui/MailActionBar.java
@@ -34,6 +34,7 @@
import com.android.mail.AccountRecentLabelSpinner;
import com.android.mail.AccountSpinnerAdapter;
import com.android.mail.ConversationListContext;
+import com.android.mail.providers.Account;
/**
* View to manage the various states of the Gmail Action Bar
@@ -73,7 +74,7 @@
*
* @return whether the account can be switched successfully.
*/
- boolean navigateToAccount(final String account);
+ boolean navigateToAccount(final Account account);
void navigateToFolder(final String folderCanonicalName);
@@ -185,6 +186,12 @@
@Override
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
// Don't do anything. Toast on the action.
+ int type = mSpinner.getItemViewType(itemPosition);
+ switch (type) {
+ case AccountSpinnerAdapter.TYPE_ACCOUNT:
+ mCallback.navigateToAccount((Account) mSpinner.getItem(itemPosition));
+ break;
+ }
Toast.makeText(getContext(), "Selected item " + itemPosition, Toast.LENGTH_SHORT).show();
return false;
}
diff --git a/src/com/android/mail/ui/MailActivity.java b/src/com/android/mail/ui/MailActivity.java
index 58abceb..75bf0e2 100644
--- a/src/com/android/mail/ui/MailActivity.java
+++ b/src/com/android/mail/ui/MailActivity.java
@@ -219,4 +219,9 @@
public StarHandler getStarHandler() {
return mController;
}
+
+ @Override
+ public void attachFolderList(FolderListFragment folderListFragment) {
+ // TODO Auto-generated method stub
+ }
}
diff --git a/src/com/android/mail/ui/OnePaneController.java b/src/com/android/mail/ui/OnePaneController.java
index 6ee2b90..c71c819 100644
--- a/src/com/android/mail/ui/OnePaneController.java
+++ b/src/com/android/mail/ui/OnePaneController.java
@@ -87,6 +87,25 @@
}
@Override
+ public void showFolderList() {
+ FragmentTransaction fragmentTransaction = mActivity.getFragmentManager().beginTransaction();
+ fragmentTransaction.addToBackStack(null);
+ final boolean accountChanged = false;
+ // TODO(viki): This account transition looks strange in two pane mode. Revisit as the app
+ // is coming together and improve the look and feel.
+ final int transition = accountChanged ? FragmentTransaction.TRANSIT_FRAGMENT_FADE :
+ FragmentTransaction.TRANSIT_FRAGMENT_OPEN;
+ fragmentTransaction.setTransition(transition);
+
+ Fragment folderListFragment = FolderListFragment.newInstance(
+ mAccount.folderListUri);
+ fragmentTransaction.replace(R.id.content_pane, folderListFragment);
+
+ fragmentTransaction.commitAllowingStateLoss();
+ resetActionBarIcon();
+ }
+
+ @Override
public void showConversationList(ConversationListContext listContext) {
FragmentTransaction fragmentTransaction = mActivity.getFragmentManager().beginTransaction();
fragmentTransaction.addToBackStack(null);
diff --git a/src/com/android/mail/ui/TwoPaneController.java b/src/com/android/mail/ui/TwoPaneController.java
index 40068e4..c8fa201 100644
--- a/src/com/android/mail/ui/TwoPaneController.java
+++ b/src/com/android/mail/ui/TwoPaneController.java
@@ -74,6 +74,11 @@
}
@Override
+ public void showFolderList() {
+ // TODO: auto-generated method stub.
+ }
+
+ @Override
public boolean onCreate(Bundle savedState) {
mActivity.setContentView(R.layout.two_pane_activity);