diff --git a/src/i2p/bote/BoteHelper.java b/src/i2p/bote/BoteHelper.java index d9a4eb6..f099cd8 100644 --- a/src/i2p/bote/BoteHelper.java +++ b/src/i2p/bote/BoteHelper.java @@ -4,9 +4,16 @@ import java.util.List; import android.content.Context; +import i2p.bote.email.AddressDisplayFilter; +import i2p.bote.email.Email; +import i2p.bote.email.EmailAttribute; +import i2p.bote.email.Identities; +import i2p.bote.fileencryption.PasswordException; import i2p.bote.folder.EmailFolder; public class BoteHelper { + private static AddressDisplayFilter ADDRESS_DISPLAY_FILTER; + public static EmailFolder getMailFolder(String folderName) { List folders = I2PBote.getInstance().getEmailFolders(); for (EmailFolder folder : folders) { @@ -37,4 +44,15 @@ public class BoteHelper { else return name; } + + public static List getEmails(EmailFolder folder, EmailAttribute sortColumn, boolean descending) throws PasswordException { + return folder.getElements(getAddressDisplayFilter(), sortColumn, descending); + } + + private static AddressDisplayFilter getAddressDisplayFilter() throws PasswordException { + Identities identities = I2PBote.getInstance().getIdentities(); + if (ADDRESS_DISPLAY_FILTER == null) + ADDRESS_DISPLAY_FILTER = new AddressDisplayFilter(identities, I2PBote.getInstance().getAddressBook()); + return ADDRESS_DISPLAY_FILTER; + } } diff --git a/src/i2p/bote/EmailListAdapter.java b/src/i2p/bote/EmailListAdapter.java new file mode 100644 index 0000000..00df749 --- /dev/null +++ b/src/i2p/bote/EmailListAdapter.java @@ -0,0 +1,47 @@ +package i2p.bote; + +import java.util.List; + +import javax.mail.MessagingException; + +import i2p.bote.email.Email; +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 EmailListAdapter extends ArrayAdapter { + private final LayoutInflater mInflater; + + public EmailListAdapter(Context context) { + super(context, android.R.layout.simple_list_item_2); + mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + } + + public void setData(List emails) { + clear(); + if (emails != null) { + for (Email email : emails) { + add(email); + } + } + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View v = mInflater.inflate(R.layout.listitem_email, parent, false); + Email email = getItem(position); + + TextView name = (TextView) v.findViewById(R.id.email_subject); + try { + name.setText(email.getSubject()); + } catch (MessagingException e) { + name.setText("ERROR: " + e.getMessage()); + } + + return v; + } +} diff --git a/src/i2p/bote/EmailListLoader.java b/src/i2p/bote/EmailListLoader.java new file mode 100644 index 0000000..43f43a5 --- /dev/null +++ b/src/i2p/bote/EmailListLoader.java @@ -0,0 +1,155 @@ +package i2p.bote; + +import i2p.bote.email.Email; +import i2p.bote.fileencryption.PasswordException; +import i2p.bote.folder.EmailFolder; +import i2p.bote.folder.FolderListener; + +import java.util.List; + +import android.content.Context; +import android.support.v4.content.AsyncTaskLoader; + +public class EmailListLoader extends AsyncTaskLoader> implements + FolderListener { + private EmailFolder mFolder; + private List mData; + + public EmailListLoader(Context context, EmailFolder folder) { + super(context); + mFolder = folder; + } + + @Override + public List loadInBackground() { + try { + return BoteHelper.getEmails(mFolder, null, false); + } catch (PasswordException pe) { + // TODO: Handle this error properly (get user to log in) + return null; + } + } + + /** + * Called when there is new data to deliver to the client. The + * super class will take care of delivering it; the implementation + * here just adds a little more logic. + */ + @Override + public void deliverResult(List data) { + if (isReset()) { + // An async query came in while the loader is stopped. We + // don't need the result. + if (data != null) { + releaseResources(data); + } + } + + // Hold a reference to the old data so it doesn't get garbage collected. + // We must protect it until the new data has been delivered. + List oldData = mData; + mData = data; + + if (isStarted()) { + // If the Loader is currently started, we can immediately + // deliver its results. + super.deliverResult(data); + } + + // Invalidate the old data as we don't need it any more. + if (oldData != null && oldData != data) { + releaseResources(oldData); + } + } + + /** + * Handles a request to start the Loader. + */ + @Override + protected void onStartLoading() { + if (mData != null) { + // Deliver any previously loaded data immediately. + deliverResult(mData); + } + + // Start watching for changes in the folder + mFolder.addFolderListener(this); + + if (takeContentChanged() || mData == null) { + // When the observer detects a change, it should call onContentChanged() + // on the Loader, which will cause the next call to takeContentChanged() + // to return true. If this is ever the case (or if the current data is + // null), we force a new load. + forceLoad(); + } + } + + /** + * Handles a request to stop the Loader. + */ + @Override + protected void onStopLoading() { + // The Loader is in a stopped state, so we should attempt to cancel the + // current load (if there is one). + cancelLoad(); + + // Note that we leave the observer as is. Loaders in a stopped state + // should still monitor the data source for changes so that the Loader + // will know to force a new load if it is ever started again. + } + + /** + * Handles a request to completely reset the Loader. + */ + @Override + protected void onReset() { + super.onReset(); + + // Ensure the loader has been stopped. + onStopLoading(); + + // At this point we can release the resources associated with 'mData'. + if (mData != null) { + releaseResources(mData); + mData = null; + } + + // Stop monitoring for changes. + mFolder.removeFolderListener(this); + } + + /** + * Handles a request to cancel a load. + */ + @Override + public void onCanceled(List data) { + // Attempt to cancel the current asynchronous load. + super.onCanceled(data); + + // The load has been canceled, so we should release the resources + // associated with 'data'. + releaseResources(data); + } + + /** + * Helper function to take care of releasing resources associated + * with an actively loaded data set. + */ + private void releaseResources(List data) { + // For a simple List, there is nothing to do. For something like a Cursor, we + // would close it in this method. All resources associated with the Loader + // should be released here. + } + + // FolderListener + + @Override + public void elementAdded() { + onContentChanged(); + } + + @Override + public void elementRemoved() { + onContentChanged(); + } +} diff --git a/src/i2p/bote/FolderFragment.java b/src/i2p/bote/FolderFragment.java index aab30d0..3f16a91 100644 --- a/src/i2p/bote/FolderFragment.java +++ b/src/i2p/bote/FolderFragment.java @@ -1,12 +1,23 @@ package i2p.bote; +import java.util.List; + +import i2p.bote.email.Email; import i2p.bote.folder.EmailFolder; import android.os.Bundle; import android.support.v4.app.ListFragment; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.Loader; -public class FolderFragment extends ListFragment { +public class FolderFragment extends ListFragment implements + LoaderManager.LoaderCallbacks> { public static final String FOLDER_NAME = "folder_name"; + private static final int EMAIL_LIST_LOADER = 1; + + private EmailListAdapter mAdapter; + private EmailFolder mFolder; + public static FolderFragment newInstance(String folderName) { FolderFragment f = new FolderFragment(); Bundle args = new Bundle(); @@ -16,10 +27,37 @@ public class FolderFragment extends ListFragment { } @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + mAdapter = new EmailListAdapter(getActivity()); String folderName = getArguments().getString(FOLDER_NAME); - EmailFolder folder = BoteHelper.getMailFolder(folderName); + mFolder = BoteHelper.getMailFolder(folderName); + + setListAdapter(mAdapter); + + setListShown(false); + if (mFolder != null) + getLoaderManager().initLoader(EMAIL_LIST_LOADER, null, this); + } + + // LoaderManager.LoaderCallbacks> + + public Loader> onCreateLoader(int id, Bundle args) { + return new EmailListLoader(getActivity(), mFolder); + } + + public void onLoadFinished(Loader> loader, + List data) { + mAdapter.setData(data); + + if (isResumed()) { + setListShown(true); + } else { + setListShownNoAnimation(true); + } + } + + public void onLoaderReset(Loader> loader) { + mAdapter.setData(null); } }