You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tasks/astrid/src/main/java/com/todoroo/astrid/activity/FilterListFragment.java

485 lines
18 KiB
Java

/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.activity;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo;
import android.widget.AdapterView;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemLongClickListener;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import android.widget.Toast;
import com.actionbarsherlock.app.SherlockListFragment;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuItem;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.service.ExceptionService;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.astrid.actfm.TagViewFragment;
import com.todoroo.astrid.adapter.FilterAdapter;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.FilterListItem;
import com.todoroo.astrid.api.FilterWithUpdate;
import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.tags.TagsPlugin;
import com.todoroo.astrid.utility.AstridPreferences;
import org.tasks.R;
/**
* Activity that displays a user's task lists and allows users
* to filter their task list.
*
* @author Tim Su <tim@todoroo.com>
*
*/
public class FilterListFragment extends SherlockListFragment {
public static final String TAG_FILTERLIST_FRAGMENT = "filterlist_fragment"; //$NON-NLS-1$
public static final String TOKEN_LAST_SELECTED = "lastSelected"; //$NON-NLS-1$
// -- extra codes
//public static final String SHOW_BACK_BUTTON = "show_back"; //$NON-NLS-1$
// --- menu codes
private static final int CONTEXT_MENU_SHORTCUT = R.string.FLA_context_shortcut;
private static final int CONTEXT_MENU_INTENT = Menu.FIRST + 4;
public static final int REQUEST_CUSTOM_INTENT = 10;
static final int REQUEST_VIEW_TASKS = 2;
public static final int REQUEST_NEW_BUTTON = 3;
public static final int REQUEST_NEW_LIST = 4;
// --- instance variables
@Autowired ExceptionService exceptionService;
protected FilterAdapter adapter = null;
private final RefreshReceiver refreshReceiver = new RefreshReceiver();
private OnFilterItemClickedListener mListener;
private View newListButton;
/* ======================================================================
* ======================================================= initialization
* ====================================================================== */
/** Container Activity must implement this interface and we ensure
* that it does during the onAttach() callback
*/
public interface OnFilterItemClickedListener {
public boolean onFilterItemClicked(FilterListItem item);
}
public FilterListFragment() {
DependencyInjectionService.getInstance().inject(this);
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Check that the container activity has implemented the callback interface
try {
mListener = (OnFilterItemClickedListener) activity;
adapter = instantiateAdapter();
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnFilterItemClickedListener"); //$NON-NLS-1$
}
}
protected FilterAdapter instantiateAdapter() {
return new FilterAdapter(getActivity(), null,
R.layout.filter_adapter_row, false);
}
/* (non-Javadoc)
* @see com.todoroo.astrid.fragment.ExpandableListFragment#onCreateView(android.view.LayoutInflater, android.view.ViewGroup, android.os.Bundle)
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
Activity activity = getActivity();
int layout = getLayout(activity);
ViewGroup parent = (ViewGroup) activity.getLayoutInflater().inflate(layout, container, false);
return parent;
}
protected int getLayout(Activity activity) {
if (AstridPreferences.useTabletLayout(activity)) {
adapter.filterStyle = R.style.TextAppearance_FLA_Filter_Tablet;
return R.layout.filter_list_activity_3pane;
} else {
return R.layout.filter_list_activity;
}
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// We have a menu item to show in action bar.
setHasOptionsMenu(true);
getActivity().setDefaultKeyMode(Activity.DEFAULT_KEYS_SEARCH_LOCAL);
//ImageView backButton = (ImageView) getView().findViewById(R.id.back);
newListButton = getView().findViewById(R.id.new_list_button);
if (newListButton != null) {
newListButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = TagsPlugin.newTagDialog(getActivity());
getActivity().startActivityForResult(intent, REQUEST_NEW_LIST);
if (!AstridPreferences.useTabletLayout(getActivity())) {
AndroidUtilities.callOverridePendingTransition(getActivity(), R.anim.slide_left_in, R.anim.slide_left_out);
}
}
});
}
setUpList();
}
/* ======================================================================
* ============================================================ lifecycle
* ====================================================================== */
@Override
public void onStart() {
super.onStart();
}
@Override
public void onStop() {
super.onStop();
}
@Override
public void onResume() {
super.onResume();
if(adapter != null) {
adapter.registerRecevier();
}
// also load sync actions
Activity activity = getActivity();
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_REQUEST_SYNC_ACTIONS);
activity.sendOrderedBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
if (activity instanceof TaskListActivity) {
((TaskListActivity) activity).setupPopoverWithFilterList(this);
}
activity.registerReceiver(refreshReceiver,
new IntentFilter(AstridApiConstants.BROADCAST_EVENT_REFRESH));
}
@Override
public void onPause() {
super.onPause();
if(adapter != null) {
adapter.unregisterRecevier();
}
try {
getActivity().unregisterReceiver(refreshReceiver);
} catch (IllegalArgumentException e) {
// Might not have fully initialized
}
}
/* ======================================================================
* ===================================================== populating lists
* ====================================================================== */
/** Sets up the coach list adapter */
protected void setUpList() {
adapter.setListView(getListView());
setListAdapter(adapter);
// Can't do context menus when list is in popup menu for some reason--workaround
if (((AstridActivity) getActivity()).fragmentLayout == AstridActivity.LAYOUT_SINGLE) {
getListView().setOnItemLongClickListener(new OnItemLongClickListener() {
@Override
public boolean onItemLongClick(AdapterView<?> parent, View view,
int position, long id) {
// Do stuff
final Filter filter = adapter.getItem(position);
final String[] labels = filter.contextMenuLabels;
final Intent[] intents = filter.contextMenuIntents;
ArrayAdapter<String> intentAdapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1);
intentAdapter.add(getString(R.string.FLA_context_shortcut));
for (String l : labels) {
intentAdapter.add(l);
}
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle(filter.title);
builder.setAdapter(intentAdapter, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == 0) {
showCreateShortcutDialog(getActivity(), ShortcutActivity.createIntent(filter), filter);
} else {
getActivity().startActivityForResult(intents[which - 1], REQUEST_CUSTOM_INTENT);
}
}
});
Dialog d = builder.create();
d.setOwnerActivity(getActivity());
d.show();
return true;
}
});
} else {
registerForContextMenu(getListView());
}
}
/* ======================================================================
* ============================================================== actions
* ====================================================================== */
@Override
public void onListItemClick(ListView parent, View v, int position, long id) {
Filter item = adapter.getItem(position);
mListener.onFilterItemClicked(item);
}
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
AdapterContextMenuInfo info = (AdapterContextMenuInfo) menuInfo;
Filter item = adapter.getItem(info.position);
android.view.MenuItem menuItem;
if(item instanceof Filter) {
Filter filter = (Filter) item;
menuItem = menu.add(0, CONTEXT_MENU_SHORTCUT, 0, R.string.FLA_context_shortcut);
menuItem.setIntent(ShortcutActivity.createIntent(filter));
}
for(int i = 0; i < item.contextMenuLabels.length; i++) {
if(item.contextMenuIntents.length <= i) {
break;
}
menuItem = menu.add(0, CONTEXT_MENU_INTENT, 0, item.contextMenuLabels[i]);
menuItem.setIntent(item.contextMenuIntents[i]);
}
if(menu.size() > 0) {
menu.setHeaderTitle(item.listingTitle);
}
}
/**
* Creates a shortcut on the user's home screen
*
* @param shortcutIntent
* @param label
*/
private static void createShortcut(Activity activity, Filter filter, Intent shortcutIntent, String label) {
if(label.length() == 0) {
return;
}
String defaultImageId = filter.listingTitle;
if (filter instanceof FilterWithUpdate) {
FilterWithUpdate fwu = (FilterWithUpdate) filter;
Bundle customExtras = fwu.customExtras;
if (customExtras != null && customExtras.containsKey(TagViewFragment.EXTRA_TAG_UUID)) {
defaultImageId = customExtras.getString(TagViewFragment.EXTRA_TAG_UUID);
}
}
Bitmap bitmap = superImposeListIcon(activity, filter.listingIcon, defaultImageId);
Intent createShortcutIntent = new Intent();
createShortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
createShortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, label);
createShortcutIntent.putExtra(Intent.EXTRA_SHORTCUT_ICON, bitmap);
createShortcutIntent.setAction("com.android.launcher.action.INSTALL_SHORTCUT"); //$NON-NLS-1$
activity.sendBroadcast(createShortcutIntent);
Toast.makeText(activity,
activity.getString(R.string.FLA_toast_onCreateShortcut, label), Toast.LENGTH_LONG).show();
}
public static Bitmap superImposeListIcon(Activity activity, Bitmap listingIcon, String uuid) {
Bitmap emblem = listingIcon;
if(emblem == null) {
emblem = ((BitmapDrawable) activity.getResources().getDrawable(
TagService.getDefaultImageIDForTag(uuid))).getBitmap();
}
// create icon by superimposing astrid w/ icon
DisplayMetrics metrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(metrics);
Bitmap bitmap = ((BitmapDrawable) activity.getResources().getDrawable(
R.drawable.icon)).getBitmap();
bitmap = bitmap.copy(bitmap.getConfig(), true);
Canvas canvas = new Canvas(bitmap);
int dimension = 22;
canvas.drawBitmap(emblem, new Rect(0, 0, emblem.getWidth(), emblem.getHeight()),
new Rect(bitmap.getWidth() - dimension, bitmap.getHeight() - dimension,
bitmap.getWidth(), bitmap.getHeight()), null);
return bitmap;
}
@Override
public boolean onContextItemSelected(MenuItem item) {
// called when context menu appears
return onOptionsItemSelected(item);
}
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
// handle my own menus
switch (item.getItemId()) {
case CONTEXT_MENU_SHORTCUT: {
AdapterContextMenuInfo info = (AdapterContextMenuInfo)item.getMenuInfo();
final Intent shortcutIntent = item.getIntent();
FilterListItem filter = ((FilterAdapter.ViewHolder)info.targetView.getTag()).item;
if(filter instanceof Filter) {
showCreateShortcutDialog(getActivity(), shortcutIntent, (Filter) filter);
}
return true;
}
case CONTEXT_MENU_INTENT: {
Intent intent = item.getIntent();
getActivity().startActivityForResult(intent, REQUEST_CUSTOM_INTENT);
return true;
}
default: {
TaskListFragment tasklist = (TaskListFragment) getActivity().getSupportFragmentManager().findFragmentByTag(TaskListFragment.TAG_TASKLIST_FRAGMENT);
if (tasklist != null && tasklist.isInLayout()) {
return tasklist.onOptionsItemSelected(item);
}
}
}
return false;
}
public static void showCreateShortcutDialog(final Activity activity, final Intent shortcutIntent,
final Filter filter) {
FrameLayout frameLayout = new FrameLayout(activity);
frameLayout.setPadding(10, 0, 10, 0);
final EditText editText = new EditText(activity);
if(filter.listingTitle == null) {
filter.listingTitle = ""; //$NON-NLS-1$
}
editText.setText(filter.listingTitle.
replaceAll("\\(\\d+\\)$", "").trim()); //$NON-NLS-1$ //$NON-NLS-2$
frameLayout.addView(editText, new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.FILL_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT));
final Runnable createShortcut = new Runnable() {
@Override
public void run() {
String label = editText.getText().toString();
createShortcut(activity, filter, shortcutIntent, label);
}
};
editText.setOnEditorActionListener(new OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
if(actionId == EditorInfo.IME_NULL) {
createShortcut.run();
return true;
}
return false;
}
});
new AlertDialog.Builder(activity)
.setTitle(R.string.FLA_shortcut_dialog_title)
.setMessage(R.string.FLA_shortcut_dialog)
.setView(frameLayout)
.setIcon(android.R.drawable.ic_dialog_info)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
createShortcut.run();
}
})
.setNegativeButton(android.R.string.cancel, null)
.show().setOwnerActivity(activity);
}
public void clear() {
adapter.clear();
}
public void refresh() {
adapter.clear();
adapter.getLists();
}
/**
* Receiver which receives refresh intents
*
* @author Tim Su <tim@todoroo.com>
*
*/
protected class RefreshReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if(intent == null || !AstridApiConstants.BROADCAST_EVENT_REFRESH.equals(intent.getAction())) {
return;
}
Activity activity = getActivity();
if (activity != null) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
refresh();
}
});
}
}
}
}