org.getlantern.firetweet.fragment.CustomTabsFragment.java Source code

Java tutorial

Introduction

Here is the source code for org.getlantern.firetweet.fragment.CustomTabsFragment.java

Source

/*
 *             Firetweet - Twitter client for Android
 * 
 *  Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.getlantern.firetweet.fragment;

import android.app.Activity;
import android.app.LoaderManager.LoaderCallbacks;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.CursorLoader;
import android.content.Intent;
import android.content.Loader;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v4.content.res.ResourcesCompat;
import android.text.TextUtils;
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.MultiChoiceModeListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;

import com.mobeta.android.dslv.DragSortListView;
import com.mobeta.android.dslv.DragSortListView.DropListener;
import com.mobeta.android.dslv.SimpleDragSortCursorAdapter;

import org.getlantern.querybuilder.Columns.Column;
import org.getlantern.querybuilder.Expression;
import org.getlantern.querybuilder.RawItemArray;
import org.getlantern.firetweet.R;
import org.getlantern.firetweet.activity.SettingsActivity;
import org.getlantern.firetweet.activity.support.CustomTabEditorActivity;
import org.getlantern.firetweet.model.CustomTabConfiguration;
import org.getlantern.firetweet.model.CustomTabConfiguration.CustomTabConfigurationComparator;
import org.getlantern.firetweet.provider.FiretweetDataStore.Tabs;
import org.getlantern.firetweet.util.SharedPreferencesWrapper;
import org.getlantern.firetweet.util.ThemeUtils;
import org.getlantern.firetweet.util.Utils;
import org.getlantern.firetweet.view.holder.TwoLineWithIconViewHolder;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;

import static org.getlantern.firetweet.util.CustomTabUtils.getConfiguraionMap;
import static org.getlantern.firetweet.util.CustomTabUtils.getTabIconDrawable;
import static org.getlantern.firetweet.util.CustomTabUtils.getTabIconObject;
import static org.getlantern.firetweet.util.CustomTabUtils.getTabTypeName;
import static org.getlantern.firetweet.util.CustomTabUtils.isTabAdded;
import static org.getlantern.firetweet.util.CustomTabUtils.isTabTypeValid;
import static org.getlantern.firetweet.util.Utils.getAccountIds;

public class CustomTabsFragment extends BaseFragment
        implements LoaderCallbacks<Cursor>, MultiChoiceModeListener, OnItemClickListener {

    private ContentResolver mResolver;

    private CustomTabsAdapter mAdapter;

    private DragSortListView mListView;
    private View mEmptyView;
    private View mListContainer, mProgressContainer;
    private TextView mEmptyText;
    private ImageView mEmptyIcon;
    private SharedPreferencesWrapper mPreferences;

    @Override
    public boolean onActionItemClicked(final ActionMode mode, final MenuItem item) {
        switch (item.getItemId()) {
        case MENU_DELETE: {
            final long[] itemIds = mListView.getCheckedItemIds();
            final Expression where = Expression.in(new Column(Tabs._ID), new RawItemArray(itemIds));
            mResolver.delete(Tabs.CONTENT_URI, where.getSQL(), null);
            break;
        }
        }
        mode.finish();
        return true;
    }

    @Override
    public void onActivityCreated(final Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        mPreferences = SharedPreferencesWrapper.getInstance(getActivity(), SHARED_PREFERENCES_NAME,
                Context.MODE_PRIVATE);
        setHasOptionsMenu(true);
        mResolver = getContentResolver();
        final View view = getView();
        if (view == null)
            throw new AssertionError();
        final Context context = view.getContext();
        mAdapter = new CustomTabsAdapter(context);
        mListView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
        mListView.setMultiChoiceModeListener(this);
        mListView.setOnItemClickListener(this);
        mListView.setAdapter(mAdapter);
        mListView.setEmptyView(mEmptyView);
        mListView.setDropListener(new DropListener() {
            @Override
            public void drop(final int from, final int to) {
                mAdapter.drop(from, to);
                if (mListView.getChoiceMode() != AbsListView.CHOICE_MODE_NONE) {
                    mListView.moveCheckState(from, to);
                }
                saveTabPositions();
            }
        });
        mEmptyText.setText(R.string.no_tab);
        mEmptyIcon.setImageResource(R.drawable.ic_info_tab);
        getLoaderManager().initLoader(0, null, this);
        setListShown(false);
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        final Cursor c = mAdapter.getCursor();
        c.moveToPosition(mAdapter.getCursorPosition(position));
        final Intent intent = new Intent(INTENT_ACTION_EDIT_TAB);
        intent.setClass(getActivity(), CustomTabEditorActivity.class);
        intent.putExtra(EXTRA_ID, c.getLong(c.getColumnIndex(Tabs._ID)));
        intent.putExtra(EXTRA_TYPE, c.getString(c.getColumnIndex(Tabs.TYPE)));
        intent.putExtra(EXTRA_NAME, c.getString(c.getColumnIndex(Tabs.NAME)));
        intent.putExtra(EXTRA_ICON, c.getString(c.getColumnIndex(Tabs.ICON)));
        intent.putExtra(EXTRA_EXTRAS, c.getString(c.getColumnIndex(Tabs.EXTRAS)));
        startActivityForResult(intent, REQUEST_EDIT_TAB);
    }

    private void setListShown(boolean shown) {
        mListContainer.setVisibility(shown ? View.VISIBLE : View.GONE);
        mProgressContainer.setVisibility(shown ? View.GONE : View.VISIBLE);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mListView = (DragSortListView) view.findViewById(android.R.id.list);
        mEmptyView = view.findViewById(android.R.id.empty);
        mEmptyIcon = (ImageView) view.findViewById(R.id.empty_icon);
        mEmptyText = (TextView) view.findViewById(R.id.empty_text);
        mListContainer = view.findViewById(R.id.list_container);
        mProgressContainer = view.findViewById(R.id.progress_container);
    }

    @Override
    public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
        switch (requestCode) {
        case REQUEST_ADD_TAB: {
            if (resultCode == Activity.RESULT_OK) {
                final ContentValues values = new ContentValues();
                values.put(Tabs.NAME, data.getStringExtra(EXTRA_NAME));
                values.put(Tabs.ICON, data.getStringExtra(EXTRA_ICON));
                values.put(Tabs.TYPE, data.getStringExtra(EXTRA_TYPE));
                values.put(Tabs.ARGUMENTS, data.getStringExtra(EXTRA_ARGUMENTS));
                values.put(Tabs.EXTRAS, data.getStringExtra(EXTRA_EXTRAS));
                values.put(Tabs.POSITION, mAdapter.getCount());
                mResolver.insert(Tabs.CONTENT_URI, values);
                SettingsActivity.setShouldNotifyChange(getActivity());
            }
            break;
        }
        case REQUEST_EDIT_TAB: {
            if (resultCode == Activity.RESULT_OK && data.hasExtra(EXTRA_ID)) {
                final ContentValues values = new ContentValues();
                values.put(Tabs.NAME, data.getStringExtra(EXTRA_NAME));
                values.put(Tabs.ICON, data.getStringExtra(EXTRA_ICON));
                values.put(Tabs.EXTRAS, data.getStringExtra(EXTRA_EXTRAS));
                final String where = Expression.equals(Tabs._ID, data.getLongExtra(EXTRA_ID, -1)).getSQL();
                mResolver.update(Tabs.CONTENT_URI, values, where, null);
                SettingsActivity.setShouldNotifyChange(getActivity());
            }
            break;
        }
        }
        super.onActivityResult(requestCode, resultCode, data);
    }

    @Override
    public boolean onCreateActionMode(final ActionMode mode, final Menu menu) {
        mode.getMenuInflater().inflate(R.menu.action_multi_select_items, menu);
        return true;
    }

    @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);
    }

    @Override
    public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
            final Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_list_with_empty_view, container, false);
    }

    @Override
    public void onDestroyActionMode(final ActionMode mode) {

    }

    @Override
    public void onItemCheckedStateChanged(final ActionMode mode, final int position, final long id,
            final boolean checked) {
        updateTitle(mode);
    }

    @Override
    public void onLoaderReset(final Loader<Cursor> loader) {
        mAdapter.changeCursor(null);
    }

    @Override
    public void onLoadFinished(final Loader<Cursor> loader, final Cursor cursor) {
        mAdapter.changeCursor(cursor);
        setListShown(true);
    }

    @Override
    public boolean onOptionsItemSelected(final MenuItem item) {
        switch (item.getItemId()) {
        default: {
            final Intent intent = item.getIntent();
            if (intent == null)
                return false;
            startActivityForResult(intent, REQUEST_ADD_TAB);
            return true;
        }
        }
    }

    @Override
    public boolean onPrepareActionMode(final ActionMode mode, final Menu menu) {
        updateTitle(mode);
        return true;
    }

    @Override
    public void onPrepareOptionsMenu(final Menu menu) {
        final Resources res = getResources();
        final boolean hasOfficialKeyAccounts = Utils.hasAccountSignedWithOfficialKeys(getActivity());
        final boolean forcePrivateAPI = mPreferences.getBoolean(KEY_FORCE_USING_PRIVATE_APIS, false);
        final long[] accountIds = getAccountIds(getActivity());
        final MenuItem itemAdd = menu.findItem(R.id.add_submenu);
        if (itemAdd != null && itemAdd.hasSubMenu()) {
            final SubMenu subMenu = itemAdd.getSubMenu();
            subMenu.clear();
            final HashMap<String, CustomTabConfiguration> map = getConfiguraionMap();
            final List<Entry<String, CustomTabConfiguration>> tabs = new ArrayList<>(map.entrySet());
            Collections.sort(tabs, CustomTabConfigurationComparator.SINGLETON);
            for (final Entry<String, CustomTabConfiguration> entry : tabs) {
                final String type = entry.getKey();
                final CustomTabConfiguration conf = entry.getValue();

                final boolean isOfficiakKeyAccountRequired = TAB_TYPE_ACTIVITIES_ABOUT_ME.equals(type)
                        || TAB_TYPE_ACTIVITIES_BY_FRIENDS.equals(type);
                final boolean accountIdRequired = conf
                        .getAccountRequirement() == CustomTabConfiguration.ACCOUNT_REQUIRED;

                final Intent intent = new Intent(INTENT_ACTION_ADD_TAB);
                intent.setClass(getActivity(), CustomTabEditorActivity.class);
                intent.putExtra(EXTRA_TYPE, type);
                intent.putExtra(EXTRA_OFFICIAL_KEY_ONLY, isOfficiakKeyAccountRequired);

                final MenuItem subItem = subMenu.add(conf.getDefaultTitle());
                final boolean disabledByNoAccount = accountIdRequired && accountIds.length == 0;
                final boolean disabledByNoOfficialKey = !forcePrivateAPI && isOfficiakKeyAccountRequired
                        && !hasOfficialKeyAccounts;
                final boolean disabledByDuplicateTab = conf.isSingleTab() && isTabAdded(getActivity(), type);
                final boolean shouldDisable = disabledByDuplicateTab || disabledByNoOfficialKey
                        || disabledByNoAccount;
                subItem.setVisible(!shouldDisable);
                subItem.setEnabled(!shouldDisable);
                final Drawable icon = ResourcesCompat.getDrawable(res, conf.getDefaultIcon(), null);
                subItem.setIcon(icon);
                subItem.setIntent(intent);
            }
        }
        ThemeUtils.applyColorFilterToMenuIcon(getActivity(), menu);
    }

    @Override
    public void onStop() {
        super.onStop();
    }

    private void saveTabPositions() {
        final ArrayList<Integer> positions = mAdapter.getCursorPositions();
        final Cursor c = mAdapter.getCursor();
        if (positions != null && c != null && !c.isClosed()) {
            final int idIdx = c.getColumnIndex(Tabs._ID);
            for (int i = 0, j = positions.size(); i < j; i++) {
                c.moveToPosition(positions.get(i));
                final long id = c.getLong(idIdx);
                final ContentValues values = new ContentValues();
                values.put(Tabs.POSITION, i);
                final String where = Expression.equals(Tabs._ID, id).getSQL();
                mResolver.update(Tabs.CONTENT_URI, values, where, null);
            }
        }
        SettingsActivity.setShouldNotifyChange(getActivity());
    }

    private void updateTitle(final ActionMode mode) {
        if (mListView == null || mode == null || getActivity() == null)
            return;
        final int count = mListView.getCheckedItemCount();
        mode.setTitle(getResources().getQuantityString(R.plurals.Nitems_selected, count, count));
    }

    public static class CustomTabsAdapter extends SimpleDragSortCursorAdapter {

        private final int mIconColor;
        private CursorIndices mIndices;

        public CustomTabsAdapter(final Context context) {
            super(context, R.layout.list_item_custom_tab, null, new String[0], new int[0], 0);
            mIconColor = ThemeUtils.getThemeForegroundColor(context);
        }

        @Override
        public void bindView(final View view, final Context context, final Cursor cursor) {
            super.bindView(view, context, cursor);
            final TwoLineWithIconViewHolder holder = (TwoLineWithIconViewHolder) view.getTag();
            final String type = cursor.getString(mIndices.type);
            final String name = cursor.getString(mIndices.name);
            final String iconKey = cursor.getString(mIndices.icon);
            if (isTabTypeValid(type)) {
                final String typeName = getTabTypeName(context, type);
                holder.text1.setText(TextUtils.isEmpty(name) ? typeName : name);
                holder.text1.setPaintFlags(holder.text1.getPaintFlags() & ~Paint.STRIKE_THRU_TEXT_FLAG);
                holder.text2.setVisibility(View.VISIBLE);
                holder.text2.setText(typeName);
            } else {
                holder.text1.setText(name);
                holder.text1.setPaintFlags(holder.text1.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
                holder.text2.setText(R.string.invalid_tab);
            }
            final Drawable icon = getTabIconDrawable(context, getTabIconObject(iconKey));
            holder.icon.setVisibility(View.VISIBLE);
            if (icon != null) {
                holder.icon.setImageDrawable(icon);
            } else {
                holder.icon.setImageResource(R.drawable.ic_action_list);
            }
            holder.icon.setColorFilter(mIconColor, Mode.SRC_ATOP);
        }

        @Override
        public void changeCursor(final Cursor cursor) {
            if (cursor != null) {
                mIndices = new CursorIndices(cursor);
            }
            super.changeCursor(cursor);
        }

        @Override
        public View newView(final Context context, final Cursor cursor, final ViewGroup parent) {
            final View view = super.newView(context, cursor, parent);
            final Object tag = view.getTag();
            if (!(tag instanceof TwoLineWithIconViewHolder)) {
                final TwoLineWithIconViewHolder holder = new TwoLineWithIconViewHolder(view);
                view.setTag(holder);
            }
            return view;
        }

        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);
            }
        }

    }

}