package com.dwdesign.tweetings.fragment; import static com.dwdesign.tweetings.util.Utils.getTabIconDrawable; import static com.dwdesign.tweetings.util.Utils.getTabIconObject; import static com.dwdesign.tweetings.util.Utils.getTabTypeName; import com.dwdesign.popupmenu.PopupMenu; import com.dwdesign.popupmenu.PopupMenu.OnMenuItemClickListener; import com.dwdesign.tweetings.R; import com.dwdesign.tweetings.adapter.SeparatedListAdapter; import com.dwdesign.tweetings.fragment.CustomTabsFragment.CustomTabsAdapter.CustomTabSpec; import com.dwdesign.tweetings.fragment.CustomTabsFragment.DefaultTabsAdapter.DefaultTabSpec; import com.dwdesign.tweetings.fragment.CustomTabsFragment.TabsAdapterInterface.TabSpec; import com.dwdesign.tweetings.model.Panes; import com.dwdesign.tweetings.provider.TweetStore.Tabs; import android.annotation.TargetApi; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.database.CharArrayBuffer; import android.database.ContentObserver; import android.database.Cursor; import android.database.DataSetObserver; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.support.v4.widget.SimpleCursorAdapter; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.ArrayAdapter; import android.widget.CheckBox; import android.widget.ImageView; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.TextView; public class CustomTabsFragment extends BaseListFragment implements LoaderCallbacks<Cursor>, OnItemLongClickListener, OnMenuItemClickListener, OnItemClickListener, Panes.Right { private ContentResolver mResolver; private SharedPreferences mPreferences; private ListView mListView; private PopupMenu mPopupMenu; private SeparatedListAdapter<TabsAdapterInterface> mAdapter; private DefaultTabsAdapter mDefaultTabsAdapter; private CustomTabsAdapter mCustomTabsAdapter; private CustomTabSpec mSelectedTab; private final BroadcastReceiver mStateReceiver = new BroadcastReceiver() { @Override public void onReceive(final Context context, final Intent intent) { final String action = intent.getAction(); if (BROADCAST_TABS_UPDATED.equals(action)) { mSelectedTab = null; getLoaderManager().restartLoader(0, null, CustomTabsFragment.this); } } }; @Override public void onActivityCreated(final Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setHasOptionsMenu(true); mResolver = getContentResolver(); mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); final Context context = getActivity(); mAdapter = new SeparatedListAdapter<TabsAdapterInterface>(context); mCustomTabsAdapter = new CustomTabsAdapter(context); mDefaultTabsAdapter = new DefaultTabsAdapter(context); mAdapter.addSection(getString(R.string.default_tabs), mDefaultTabsAdapter); mAdapter.addSection(getString(R.string.custom_tabs), mCustomTabsAdapter); setListAdapter(mAdapter); mListView = getListView(); mListView.setOnItemClickListener(this); mListView.setOnItemLongClickListener(this); getLoaderManager().initLoader(0, null, this); } @Override public void onActivityResult(final int requestCode, final int resultCode, final Intent intent) { switch (requestCode) { case REQUEST_ADD_TAB: { if (resultCode == Activity.RESULT_OK) { final Bundle extras = intent.getExtras(); if (extras == null) { break; } final ContentValues values = new ContentValues(); values.put(Tabs.ARGUMENTS, extras.getString(INTENT_KEY_ARGUMENTS)); values.put(Tabs.NAME, extras.getString(INTENT_KEY_NAME)); values.put(Tabs.POSITION, mCustomTabsAdapter.getCount()); values.put(Tabs.TYPE, extras.getString(INTENT_KEY_TYPE)); values.put(Tabs.ICON, extras.getString(INTENT_KEY_ICON)); mResolver.insert(Tabs.CONTENT_URI, values); getLoaderManager().restartLoader(0, null, this); } break; } case REQUEST_EDIT_TAB: { if (resultCode == Activity.RESULT_OK && mSelectedTab != null) { final Bundle extras = intent.getExtras(); if (extras == null) { break; } final ContentValues values = new ContentValues(); values.put(Tabs.ARGUMENTS, extras.getString(INTENT_KEY_ARGUMENTS)); values.put(Tabs.NAME, extras.getString(INTENT_KEY_NAME)); values.put(Tabs.TYPE, extras.getString(INTENT_KEY_TYPE)); values.put(Tabs.ICON, extras.getString(INTENT_KEY_ICON)); mResolver.update(Tabs.CONTENT_URI, values, Tabs._ID + " = " + mSelectedTab.getId(), null); getLoaderManager().restartLoader(0, null, this); } break; } } super.onActivityResult(requestCode, resultCode, intent); } @Override public Loader<Cursor> onCreateLoader(final int id, final Bundle args) { return new CursorLoader(getActivity(), Tabs.CONTENT_URI, Tabs.COLUMNS, null, null, Tabs.DEFAULT_SORT_ORDER); } @Override public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) { inflater.inflate(R.menu.menu_custom_tabs, menu); super.onCreateOptionsMenu(menu, inflater); } @Override public void onItemClick(final AdapterView<?> parent, final View view, final int position, final long id) { mSelectedTab = null; final Object obj = mAdapter.getItem(position); if (!(obj instanceof TabsAdapterInterface.TabSpec)) return; final TabsAdapterInterface.TabSpec tab = (TabSpec) obj; // mSelectedId = mCursor.getLong(_id_idx); if (tab instanceof CustomTabsAdapter.CustomTabSpec) { final Intent intent = new Intent(INTENT_ACTION_EDIT_CUSTOM_TAB); final Bundle extras = new Bundle(); mSelectedTab = (CustomTabSpec) tab; extras.putString(INTENT_KEY_ICON, tab.getIcon()); extras.putString(INTENT_KEY_NAME, tab.getName()); extras.putString(INTENT_KEY_TYPE, tab.getType()); extras.putString(INTENT_KEY_ARGUMENTS, tab.getArguments()); intent.setPackage(getActivity().getPackageName()); intent.putExtras(extras); startActivityForResult(intent, REQUEST_EDIT_TAB); } else if (tab instanceof DefaultTabsAdapter.DefaultTabSpec) { final DefaultTabsAdapter.DefaultTabSpec def_tab = (DefaultTabSpec) tab; final SharedPreferences.Editor editor = mPreferences.edit(); editor.putBoolean(def_tab.getPreferenceKey(), !def_tab.isEnabled()); editor.commit(); mAdapter.notifyDataSetChanged(); } } @Override public boolean onItemLongClick(final AdapterView<?> parent, final View view, final int position, final long id) { final Object obj = mAdapter.getItem(position); if (!(obj instanceof CustomTabsAdapter.CustomTabSpec)) return false; mSelectedTab = (CustomTabsAdapter.CustomTabSpec) obj; if (mPopupMenu != null) { mPopupMenu.dismiss(); } mPopupMenu = PopupMenu.getInstance(getActivity(), view); mPopupMenu.inflate(R.menu.action_custom_tab); final Menu menu = mPopupMenu.getMenu(); final MenuItem upItem = menu.findItem(MENU_UP); if (upItem != null) { upItem.setVisible(mSelectedTab.getPosition() != 0); } final MenuItem downItem = menu.findItem(MENU_DOWN); if (downItem != null) { final int count = mCustomTabsAdapter.getCount(); downItem.setVisible(count > 1 && mSelectedTab.getPosition() != count - 1); } mPopupMenu.setOnMenuItemClickListener(this); mPopupMenu.show(); return true; } @Override public void onLoaderReset(final Loader<Cursor> loader) { mCustomTabsAdapter.changeCursor(null); } @Override public void onLoadFinished(final Loader<Cursor> loader, final Cursor cursor) { mCustomTabsAdapter.changeCursor(cursor); mAdapter.notifyDataSetChanged(); } @Override public boolean onMenuItemClick(final MenuItem item) { if (mSelectedTab == null || mSelectedTab.isClosed()) return false; final int mSelectedPos = mSelectedTab.getPosition(); switch (item.getItemId()) { case MENU_UP: { if (mSelectedPos > 0 && mSelectedPos < mCustomTabsAdapter.getCount()) { final long selected_id = mSelectedTab.getId(); mSelectedTab.moveToPrevious(); final long previous_id = mSelectedTab.getId(); final ContentValues values = new ContentValues(); values.put(Tabs.POSITION, mSelectedPos - 1); mResolver.update(Tabs.CONTENT_URI, values, Tabs._ID + " = " + selected_id, null); values.put(Tabs.POSITION, mSelectedPos); mResolver.update(Tabs.CONTENT_URI, values, Tabs._ID + " = " + previous_id, null); } break; } case MENU_DOWN: { if (mSelectedPos >= 0 && mSelectedPos < mCustomTabsAdapter.getCount() - 1) { mSelectedTab.moveToPosition(mSelectedPos); final long selected_id = mSelectedTab.getId(); mSelectedTab.moveToNext(); final long next_id = mSelectedTab.getId(); final ContentValues values = new ContentValues(); values.put(Tabs.POSITION, mSelectedPos + 1); mResolver.update(Tabs.CONTENT_URI, values, Tabs._ID + " = " + selected_id, null); values.put(Tabs.POSITION, mSelectedPos); mResolver.update(Tabs.CONTENT_URI, values, Tabs._ID + " = " + next_id, null); } break; } case MENU_EDIT: { mSelectedTab.moveToPosition(mSelectedPos); final Intent intent = new Intent(INTENT_ACTION_EDIT_CUSTOM_TAB); final Bundle extras = new Bundle(); extras.putString(INTENT_KEY_ICON, mSelectedTab.getIcon()); extras.putString(INTENT_KEY_NAME, mSelectedTab.getName()); extras.putString(INTENT_KEY_TYPE, mSelectedTab.getType()); extras.putString(INTENT_KEY_ARGUMENTS, mSelectedTab.getArguments()); intent.setPackage(getActivity().getPackageName()); intent.putExtras(extras); startActivityForResult(intent, REQUEST_EDIT_TAB); break; } case MENU_DELETE: { mResolver.delete(Tabs.CONTENT_URI, Tabs._ID + " = " + mSelectedTab.getId(), null); break; } } return false; } @Override public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { case MENU_ADD: { final Intent intent = new Intent(INTENT_ACTION_NEW_CUSTOM_TAB); final Bundle extras = new Bundle(); extras.putInt(INTENT_KEY_POSITION, mCustomTabsAdapter.getCount()); intent.setPackage(getActivity().getPackageName()); intent.putExtras(extras); startActivityForResult(intent, REQUEST_ADD_TAB); break; } } return super.onOptionsItemSelected(item); } @Override public void onStart() { super.onStart(); final IntentFilter filter = new IntentFilter(BROADCAST_TABS_UPDATED); registerReceiver(mStateReceiver, filter); } @Override public void onStop() { if (mPopupMenu != null) { mPopupMenu.dismiss(); } unregisterReceiver(mStateReceiver); super.onStop(); } public static class CustomTabsAdapter extends SimpleCursorAdapter implements TabsAdapterInterface { private CursorIndices mIndices; public CustomTabsAdapter(final Context context) { super(context, R.layout.two_line_with_icon_list_item, null, new String[] { Tabs.NAME }, new int[] { android.R.id.text1 }, 0); } @Override public void bindView(final View view, final Context context, final Cursor cursor) { super.bindView(view, context, cursor); final TextView text2 = (TextView) view.findViewById(android.R.id.text2); final ImageView icon = (ImageView) view.findViewById(android.R.id.icon); final TabSpec item = getTab(cursor.getPosition()); text2.setText(getTabTypeName(context, item.getType())); icon.setBackgroundResource(R.drawable.gallery_selected_default); icon.setImageDrawable(getTabIconDrawable(mContext, getTabIconObject(item.getIcon()))); view.findViewById(R.id.checkbox).setVisibility(View.GONE); } @Override public void changeCursor(final Cursor cursor) { super.changeCursor(cursor); if (cursor != null) { mIndices = new CursorIndices(cursor); } } @Override public TabSpec getItem(final int position) { return new CustomTabSpec((Cursor) super.getItem(position), mIndices); } @Override public TabSpec getTab(final int position) { return getItem(position); } static class CursorIndices { final int _id, name, icon, type, arguments; CursorIndices(final Cursor mCursor) { _id = mCursor.getColumnIndex(Tabs._ID); icon = mCursor.getColumnIndex(Tabs.ICON); name = mCursor.getColumnIndex(Tabs.NAME); type = mCursor.getColumnIndex(Tabs.TYPE); arguments = mCursor.getColumnIndex(Tabs.ARGUMENTS); } } static class CustomTabSpec implements Cursor, TabsAdapterInterface.TabSpec { final Cursor cursor; final CursorIndices indices; CustomTabSpec(final Cursor cursor, final CursorIndices indices) { this.cursor = cursor; this.indices = indices; } @Override public void close() { cursor.close(); } @Override public void copyStringToBuffer(final int columnIndex, final CharArrayBuffer buffer) { cursor.copyStringToBuffer(columnIndex, buffer); } @Override public void deactivate() { cursor.deactivate(); } @Override public String getArguments() { return cursor.getString(indices.arguments); } @Override public byte[] getBlob(final int columnIndex) { return cursor.getBlob(columnIndex); } @Override public int getColumnCount() { return cursor.getColumnCount(); } @Override public int getColumnIndex(final String columnName) { return cursor.getColumnIndex(columnName); } @Override public int getColumnIndexOrThrow(final String columnName) throws IllegalArgumentException { return cursor.getColumnIndexOrThrow(columnName); } @Override public String getColumnName(final int columnIndex) { return cursor.getColumnName(columnIndex); } @Override public String[] getColumnNames() { return cursor.getColumnNames(); } @Override public int getCount() { return cursor.getCount(); } @Override public double getDouble(final int columnIndex) { return cursor.getDouble(columnIndex); } @Override public Bundle getExtras() { return cursor.getExtras(); } @Override public float getFloat(final int columnIndex) { return cursor.getFloat(columnIndex); } @Override public String getIcon() { return cursor.getString(indices.icon); } public long getId() { return cursor.getLong(indices._id); } @Override public int getInt(final int columnIndex) { return cursor.getInt(columnIndex); } @Override public long getLong(final int columnIndex) { return cursor.getLong(columnIndex); } @Override public String getName() { return cursor.getString(indices.name); } @Override public int getPosition() { return cursor.getPosition(); } @Override public short getShort(final int columnIndex) { return cursor.getShort(columnIndex); } @Override public String getString(final int columnIndex) { return cursor.getString(columnIndex); } @Override public String getType() { return cursor.getString(indices.type); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) @Override public int getType(final int columnIndex) { return cursor.getType(columnIndex); } @Override public boolean getWantsAllOnMoveCalls() { return cursor.getWantsAllOnMoveCalls(); } @Override public boolean isAfterLast() { return cursor.isAfterLast(); } @Override public boolean isBeforeFirst() { return cursor.isBeforeFirst(); } @Override public boolean isClosed() { return cursor.isClosed(); } @Override public boolean isDefault() { return false; } @Override public boolean isFirst() { return cursor.isFirst(); } @Override public boolean isLast() { return cursor.isLast(); } @Override public boolean isNull(final int columnIndex) { return cursor.isNull(columnIndex); } @Override public boolean move(final int offset) { return cursor.move(offset); } @Override public boolean moveToFirst() { return cursor.moveToFirst(); } @Override public boolean moveToLast() { return cursor.moveToLast(); } @Override public boolean moveToNext() { return cursor.moveToNext(); } @Override public boolean moveToPosition(final int position) { return cursor.moveToPosition(position); } @Override public boolean moveToPrevious() { return cursor.moveToPrevious(); } @Override public void registerContentObserver(final ContentObserver observer) { cursor.registerContentObserver(observer); } @Override public void registerDataSetObserver(final DataSetObserver observer) { cursor.registerDataSetObserver(observer); } @Override @Deprecated public boolean requery() { return cursor.requery(); } @Override public Bundle respond(final Bundle extras) { return cursor.respond(extras); } @Override public void setNotificationUri(final ContentResolver cr, final Uri uri) { cursor.setNotificationUri(cr, uri); } @Override public String toString() { return getName(); } @Override public void unregisterContentObserver(final ContentObserver observer) { cursor.unregisterContentObserver(observer); } @Override public void unregisterDataSetObserver(final DataSetObserver observer) { cursor.unregisterDataSetObserver(observer); } } } public static class DefaultTabsAdapter extends ArrayAdapter<DefaultTabsAdapter.DefaultTabSpec> implements TabsAdapterInterface { final SharedPreferences prefs; final Context context; public DefaultTabsAdapter(final Context context) { super(context, R.layout.two_line_with_icon_list_item, android.R.id.text1); this.context = context; prefs = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); reload(); } @Override public DefaultTabSpec getTab(final int position) { return getItem(position); } @Override public View getView(final int position, final View convertView, final ViewGroup parent) { final View view = super.getView(position, convertView, parent); final ImageView icon = (ImageView) view.findViewById(android.R.id.icon); final CheckBox checkbox = (CheckBox) view.findViewById(R.id.checkbox); final DefaultTabSpec item = getTab(position); icon.setBackgroundResource(R.drawable.gallery_selected_default); icon.setImageDrawable(getTabIconDrawable(context, getTabIconObject(item.getIcon()))); view.findViewById(android.R.id.text2).setVisibility(View.GONE); checkbox.setChecked(item.isEnabled()); return view; } void reload() { add(new DefaultTabSpec(prefs, context.getString(R.string.home), "home", PREFERENCE_KEY_SHOW_HOME_TAB)); add(new DefaultTabSpec(prefs, context.getString(R.string.mentions), "mention", PREFERENCE_KEY_SHOW_MENTIONS_TAB)); add(new DefaultTabSpec(prefs, context.getString(R.string.direct_messages), "message", PREFERENCE_KEY_SHOW_MESSAGES_TAB)); add(new DefaultTabSpec(prefs, context.getString(R.string.search), "search", PREFERENCE_KEY_SHOW_SEARCH_TAB)); add(new DefaultTabSpec(prefs, context.getString(R.string.lists), "lists", PREFERENCE_KEY_SHOW_LISTS_TAB)); add(new DefaultTabSpec(prefs, context.getString(R.string.accounts), "accounts", PREFERENCE_KEY_SHOW_ACCOUNTS_TAB)); } static class DefaultTabSpec implements TabsAdapterInterface.TabSpec { final SharedPreferences prefs; final String name, icon, prefs_key; DefaultTabSpec(final SharedPreferences prefs, final String name, final String icon, final String prefs_key) { this.name = name; this.icon = icon; this.prefs_key = prefs_key; this.prefs = prefs; } @Override public String getArguments() { return null; } @Override public String getIcon() { return icon; } @Override public String getName() { return name; } public String getPreferenceKey() { return prefs_key; } @Override public String getType() { return null; } @Override public boolean isDefault() { return true; } public boolean isEnabled() { return prefs.getBoolean(prefs_key, true); } @Override public String toString() { return name; } } } static interface TabsAdapterInterface extends ListAdapter { TabSpec getTab(int position); static interface TabSpec { String getArguments(); String getIcon(); String getName(); String getType(); boolean isDefault(); } } }