package org.wordpress.android.ui.main; import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.app.DialogFragment; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.res.Configuration; import android.os.AsyncTask; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v4.view.MenuItemCompat; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.support.v7.view.ActionMode; import android.support.v7.widget.DefaultItemAnimator; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.SearchView; import org.wordpress.android.R; import org.wordpress.android.WordPress; import org.wordpress.android.models.AccountHelper; import org.wordpress.android.ui.ActivityId; import org.wordpress.android.ui.ActivityLauncher; import org.wordpress.android.ui.RequestCodes; import org.wordpress.android.ui.main.SitePickerAdapter.SiteList; import org.wordpress.android.ui.main.SitePickerAdapter.SiteRecord; import org.wordpress.android.ui.stats.datasets.StatsTable; import org.wordpress.android.util.CoreEvents; import org.wordpress.android.util.ToastUtils; import org.wordpress.android.util.WPActivityUtils; import org.xmlrpc.android.ApiHelper; import de.greenrobot.event.EventBus; public class SitePickerActivity extends AppCompatActivity implements SitePickerAdapter.OnSiteClickListener, SitePickerAdapter.OnSelectedCountChangedListener, SearchView.OnQueryTextListener { public static final String KEY_LOCAL_ID = "local_id"; private static final String KEY_IS_IN_SEARCH_MODE = "is_in_search_mode"; private static final String KEY_LAST_SEARCH = "last_search"; private SitePickerAdapter mAdapter; private RecyclerView mRecycleView; private ActionMode mActionMode; private MenuItem mMenuEdit; private MenuItem mMenuAdd; private MenuItem mMenuSearch; private SearchView mSearchView; private int mCurrentLocalId; private boolean mDidUserSelectSite; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.site_picker_activity); restoreSavedInstanceState(savedInstanceState); setupActionBar(); setupRecycleView(); } @Override public void onResume() { super.onResume(); ActivityId.trackLastActivity(ActivityId.SITE_PICKER); } @Override protected void onSaveInstanceState(Bundle outState) { outState.putInt(KEY_LOCAL_ID, mCurrentLocalId); outState.putBoolean(KEY_IS_IN_SEARCH_MODE, getAdapter().getIsInSearchMode()); outState.putString(KEY_LAST_SEARCH, getAdapter().getLastSearch()); super.onSaveInstanceState(outState); } @Override public void finish() { super.finish(); if (mDidUserSelectSite) { overridePendingTransition(R.anim.do_nothing, R.anim.activity_slide_out_to_left); } } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); getMenuInflater().inflate(R.menu.site_picker, menu); return true; } @Override public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); mMenuEdit = menu.findItem(R.id.menu_edit); mMenuAdd = menu.findItem(R.id.menu_add); mMenuSearch = menu.findItem(R.id.menu_search); updateMenuItemVisibility(); setupSearchView(); return true; } private void updateMenuItemVisibility() { if (mMenuAdd == null || mMenuEdit == null || mMenuSearch == null) return; if (getAdapter().getIsInSearchMode()) { mMenuEdit.setVisible(false); mMenuAdd.setVisible(false); } else { // don't allow editing visibility unless there are multiple wp.com blogs mMenuEdit.setVisible(WordPress.wpDB.getNumDotComBlogs() > 1); mMenuAdd.setVisible(true); } // no point showing search if there aren't multiple blogs mMenuSearch.setVisible(WordPress.wpDB.getNumBlogs() > 1); } @Override public boolean onOptionsItemSelected(final MenuItem item) { int itemId = item.getItemId(); if (itemId == android.R.id.home) { onBackPressed(); return true; } else if (itemId == R.id.menu_edit) { mRecycleView.setItemAnimator(new DefaultItemAnimator()); getAdapter().setEnableEditMode(true); startSupportActionMode(new ActionModeCallback()); return true; } else if (itemId == R.id.menu_search) { mSearchView.requestFocus(); showSoftKeyboard(); return true; } else if (itemId == R.id.menu_add) { addSite(this); return true; } return super.onOptionsItemSelected(item); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode) { case RequestCodes.ADD_ACCOUNT: case RequestCodes.CREATE_BLOG: if (resultCode != RESULT_CANCELED) { getAdapter().loadSites(); } break; } } @Override protected void onStop() { EventBus.getDefault().unregister(this); super.onStop(); } @Override protected void onStart() { super.onStart(); EventBus.getDefault().register(this); } @SuppressWarnings("unused") public void onEventMainThread(CoreEvents.BlogListChanged event) { if (!isFinishing()) { getAdapter().loadSites(); } } private void setupRecycleView() { mRecycleView = (RecyclerView) findViewById(R.id.recycler_view); mRecycleView.setLayoutManager(new LinearLayoutManager(this)); mRecycleView.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY); mRecycleView.setItemAnimator(null); mRecycleView.setAdapter(getAdapter()); } private void restoreSavedInstanceState(Bundle savedInstanceState) { boolean isInSearchMode = false; String lastSearch = ""; if (savedInstanceState != null) { mCurrentLocalId = savedInstanceState.getInt(KEY_LOCAL_ID); isInSearchMode = savedInstanceState.getBoolean(KEY_IS_IN_SEARCH_MODE); lastSearch = savedInstanceState.getString(KEY_LAST_SEARCH); } else if (getIntent() != null) { mCurrentLocalId = getIntent().getIntExtra(KEY_LOCAL_ID, 0); } setNewAdapter(lastSearch, isInSearchMode); } private void setupActionBar() { ActionBar actionBar = getSupportActionBar(); if (actionBar != null) { actionBar.setHomeAsUpIndicator(R.drawable.ic_close_white_24dp); actionBar.setHomeButtonEnabled(true); actionBar.setDisplayHomeAsUpEnabled(true); } } private void setIsInSearchModeAndSetNewAdapter(boolean isInSearchMode) { String lastSearch = getAdapter().getLastSearch(); setNewAdapter(lastSearch, isInSearchMode); } private SitePickerAdapter getAdapter() { if (mAdapter == null) { setNewAdapter("", false); } return mAdapter; } private void setNewAdapter(String lastSearch, boolean isInSearchMode) { mAdapter = new SitePickerAdapter(this, mCurrentLocalId, lastSearch, isInSearchMode); mAdapter.setOnSiteClickListener(this); mAdapter.setOnSelectedCountChangedListener(this); } private void saveHiddenSites() { WordPress.wpDB.getDatabase().beginTransaction(); try { // make all sites visible... WordPress.wpDB.setAllDotComBlogsVisibility(true); // ...then update ones marked hidden in the adapter, but don't hide the current site boolean skippedCurrentSite = false; String currentSiteName = null; SiteList hiddenSites = getAdapter().getHiddenSites(); for (SiteRecord site : hiddenSites) { if (site.localId == mCurrentLocalId) { skippedCurrentSite = true; currentSiteName = site.getBlogNameOrHomeURL(); } else { WordPress.wpDB.setDotComBlogsVisibility(site.localId, false); StatsTable.deleteStatsForBlog(this, site.localId); // Remove stats data for hidden sites } } // let user know the current site wasn't hidden if (skippedCurrentSite) { String cantHideCurrentSite = getString(R.string.site_picker_cant_hide_current_site); ToastUtils.showToast(this, String.format(cantHideCurrentSite, currentSiteName), ToastUtils.Duration.LONG); } WordPress.wpDB.getDatabase().setTransactionSuccessful(); } finally { WordPress.wpDB.getDatabase().endTransaction(); } } private void updateActionModeTitle() { if (mActionMode != null) { int numSelected = getAdapter().getNumSelected(); String cabSelected = getString(R.string.cab_selected); mActionMode.setTitle(String.format(cabSelected, numSelected)); } } private void setupSearchView() { mSearchView = (SearchView) mMenuSearch.getActionView(); mSearchView.setIconifiedByDefault(false); mSearchView.setOnQueryTextListener(this); MenuItemCompat.setOnActionExpandListener(mMenuSearch, new MenuItemCompat.OnActionExpandListener() { @Override public boolean onMenuItemActionExpand(MenuItem item) { enableSearchMode(); return true; } @Override public boolean onMenuItemActionCollapse(MenuItem item) { disableSearchMode(); return true; } }); setQueryIfInSearch(); } private void setQueryIfInSearch() { if (getAdapter().getIsInSearchMode()) { mMenuSearch.expandActionView(); mSearchView.setQuery(getAdapter().getLastSearch(), false); } } private void enableSearchMode() { setIsInSearchModeAndSetNewAdapter(true); mRecycleView.swapAdapter(getAdapter(), true); updateMenuItemVisibility(); } private void disableSearchMode() { hideSoftKeyboard(); setIsInSearchModeAndSetNewAdapter(false); mRecycleView.swapAdapter(getAdapter(), true); updateMenuItemVisibility(); } private void hideSoftKeyboard() { if (!hasHardwareKeyboard()) { WPActivityUtils.hideKeyboard(mSearchView); } } private void showSoftKeyboard() { if (!hasHardwareKeyboard()) { InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); inputMethodManager.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, InputMethodManager.HIDE_NOT_ALWAYS); } } private boolean hasHardwareKeyboard() { return (getResources().getConfiguration().keyboard != Configuration.KEYBOARD_NOKEYS); } @Override public void onSelectedCountChanged(int numSelected) { if (mActionMode != null) { updateActionModeTitle(); mActionMode.invalidate(); } } @Override public void onSiteClick(SiteRecord site) { if (mActionMode == null) { hideSoftKeyboard(); WordPress.setCurrentBlogAndSetVisible(site.localId); WordPress.wpDB.updateLastBlogId(site.localId); setResult(RESULT_OK); mDidUserSelectSite = true; new ApiHelper.RefreshBlogContentTask(WordPress.getCurrentBlog(), null).executeOnExecutor( AsyncTask.THREAD_POOL_EXECUTOR, false); finish(); } } @Override public boolean onQueryTextSubmit(String s) { hideSoftKeyboard(); return true; } @Override public boolean onQueryTextChange(String s) { getAdapter().setLastSearch(s); getAdapter().searchSites(s); return true; } private final class ActionModeCallback implements ActionMode.Callback { private boolean mHasChanges; @Override public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { mActionMode = actionMode; mHasChanges = false; updateActionModeTitle(); actionMode.getMenuInflater().inflate(R.menu.site_picker_action_mode, menu); return true; } @Override public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { MenuItem mnuShow = menu.findItem(R.id.menu_show); mnuShow.setEnabled(getAdapter().getNumHiddenSelected() > 0); MenuItem mnuHide = menu.findItem(R.id.menu_hide); mnuHide.setEnabled(getAdapter().getNumVisibleSelected() > 0); MenuItem mnuSelectAll = menu.findItem(R.id.menu_select_all); mnuSelectAll.setEnabled(getAdapter().getNumSelected() != getAdapter().getItemCount()); MenuItem mnuDeselectAll = menu.findItem(R.id.menu_deselect_all); mnuDeselectAll.setEnabled(getAdapter().getNumSelected() > 0); return true; } @Override public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) { int itemId = menuItem.getItemId(); if (itemId == R.id.menu_show) { getAdapter().setVisibilityForSelectedSites(true); mHasChanges = true; mActionMode.finish(); } else if (itemId == R.id.menu_hide) { getAdapter().setVisibilityForSelectedSites(false); mHasChanges = true; mActionMode.finish(); } else if (itemId == R.id.menu_select_all) { getAdapter().selectAll(); } else if (itemId == R.id.menu_deselect_all) { getAdapter().deselectAll(); } return true; } @Override public void onDestroyActionMode(ActionMode actionMode) { if (mHasChanges) { saveHiddenSites(); } getAdapter().setEnableEditMode(false); mActionMode = null; } } public static void addSite(Activity activity) { // if user is signed into wp.com use the dialog to enable choosing whether to // create a new wp.com blog or add a self-hosted one if (AccountHelper.isSignedInWordPressDotCom()) { DialogFragment dialog = new AddSiteDialog(); dialog.show(activity.getFragmentManager(), AddSiteDialog.ADD_SITE_DIALOG_TAG); } else { // user isn't signed into wp.com, so simply enable adding self-hosted ActivityLauncher.addSelfHostedSiteForResult(activity); } } /* * dialog which appears after user taps "Add site" - enables choosing whether to create * a new wp.com blog or add an existing self-hosted one */ public static class AddSiteDialog extends DialogFragment { static final String ADD_SITE_DIALOG_TAG = "add_site_dialog"; @NonNull @Override public Dialog onCreateDialog(Bundle savedInstanceState) { CharSequence[] items = {getString(R.string.site_picker_create_dotcom), getString(R.string.site_picker_add_self_hosted)}; AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setTitle(R.string.site_picker_add_site); builder.setItems(items, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { if (which == 0) { ActivityLauncher.newBlogForResult(getActivity()); } else { ActivityLauncher.addSelfHostedSiteForResult(getActivity()); } } }); return builder.create(); } } }