diff options
Diffstat (limited to 'WordPress/src/main/java/org/wordpress/android/ui/main/SitePickerAdapter.java')
-rw-r--r-- | WordPress/src/main/java/org/wordpress/android/ui/main/SitePickerAdapter.java | 508 |
1 files changed, 508 insertions, 0 deletions
diff --git a/WordPress/src/main/java/org/wordpress/android/ui/main/SitePickerAdapter.java b/WordPress/src/main/java/org/wordpress/android/ui/main/SitePickerAdapter.java new file mode 100644 index 000000000..7267d8d5e --- /dev/null +++ b/WordPress/src/main/java/org/wordpress/android/ui/main/SitePickerAdapter.java @@ -0,0 +1,508 @@ +package org.wordpress.android.ui.main; + +import android.content.Context; +import android.graphics.Typeface; +import android.graphics.drawable.ColorDrawable; +import android.graphics.drawable.Drawable; +import android.os.AsyncTask; +import android.support.v7.widget.RecyclerView; +import android.text.TextUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import org.wordpress.android.R; +import org.wordpress.android.WordPress; +import org.wordpress.android.models.AccountHelper; +import org.wordpress.android.util.AppLog; +import org.wordpress.android.util.BlogUtils; +import org.wordpress.android.util.GravatarUtils; +import org.wordpress.android.util.MapUtils; +import org.wordpress.android.util.StringUtils; +import org.wordpress.android.widgets.WPNetworkImageView; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Map; + +class SitePickerAdapter extends RecyclerView.Adapter<SitePickerAdapter.SiteViewHolder> { + + interface OnSiteClickListener { + void onSiteClick(SiteRecord site); + } + + interface OnSelectedCountChangedListener { + void onSelectedCountChanged(int numSelected); + } + + private final int mTextColorNormal; + private final int mTextColorHidden; + + private static int mBlavatarSz; + + private SiteList mSites = new SiteList(); + private final int mCurrentLocalId; + + private final Drawable mSelectedItemBackground; + + private final LayoutInflater mInflater; + private final HashSet<Integer> mSelectedPositions = new HashSet<>(); + + private boolean mIsMultiSelectEnabled; + private final boolean mIsInSearchMode; + private boolean mShowHiddenSites = false; + private boolean mShowSelfHostedSites = true; + private String mLastSearch; + private SiteList mAllSites; + + private OnSiteClickListener mSiteSelectedListener; + private OnSelectedCountChangedListener mSelectedCountListener; + + class SiteViewHolder extends RecyclerView.ViewHolder { + private final ViewGroup layoutContainer; + private final TextView txtTitle; + private final TextView txtDomain; + private final WPNetworkImageView imgBlavatar; + private final View divider; + private Boolean isSiteHidden; + + public SiteViewHolder(View view) { + super(view); + layoutContainer = (ViewGroup) view.findViewById(R.id.layout_container); + txtTitle = (TextView) view.findViewById(R.id.text_title); + txtDomain = (TextView) view.findViewById(R.id.text_domain); + imgBlavatar = (WPNetworkImageView) view.findViewById(R.id.image_blavatar); + divider = view.findViewById(R.id.divider); + isSiteHidden = null; + + itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + int clickedPosition = getAdapterPosition(); + if (isValidPosition(clickedPosition)) { + if (mIsMultiSelectEnabled) { + toggleSelection(clickedPosition); + } else if (mSiteSelectedListener != null) { + mSiteSelectedListener.onSiteClick(getItem(clickedPosition)); + } + } else { + AppLog.w(AppLog.T.MAIN, "site picker > invalid clicked position " + clickedPosition); + } + } + }); + } + } + + public SitePickerAdapter(Context context, int currentLocalBlogId, String lastSearch, boolean isInSearchMode) { + super(); + + setHasStableIds(true); + + mLastSearch = StringUtils.notNullStr(lastSearch); + mAllSites = new SiteList(); + mIsInSearchMode = isInSearchMode; + mCurrentLocalId = currentLocalBlogId; + mInflater = LayoutInflater.from(context); + + mBlavatarSz = context.getResources().getDimensionPixelSize(R.dimen.blavatar_sz); + mTextColorNormal = context.getResources().getColor(R.color.grey_dark); + mTextColorHidden = context.getResources().getColor(R.color.grey); + + mSelectedItemBackground = new ColorDrawable(context.getResources().getColor(R.color.translucent_grey_lighten_20)); + + loadSites(); + } + + @Override + public int getItemCount() { + return mSites.size(); + } + + @Override + public long getItemId(int position) { + return getItem(position).localId; + } + + private SiteRecord getItem(int position) { + return mSites.get(position); + } + + void setOnSelectedCountChangedListener(OnSelectedCountChangedListener listener) { + mSelectedCountListener = listener; + } + + public void setOnSiteClickListener(OnSiteClickListener listener) { + mSiteSelectedListener = listener; + } + + @Override + public SiteViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View itemView = mInflater.inflate(R.layout.site_picker_listitem, parent, false); + return new SiteViewHolder(itemView); + } + + @Override + public void onBindViewHolder(SiteViewHolder holder, int position) { + SiteRecord site = getItem(position); + + holder.txtTitle.setText(site.getBlogNameOrHomeURL()); + holder.txtDomain.setText(site.homeURL); + holder.imgBlavatar.setImageUrl(site.blavatarUrl, WPNetworkImageView.ImageType.BLAVATAR); + + if (site.localId == mCurrentLocalId || (mIsMultiSelectEnabled && isItemSelected(position))) { + holder.layoutContainer.setBackgroundDrawable(mSelectedItemBackground); + } else { + holder.layoutContainer.setBackgroundDrawable(null); + } + + // different styling for visible/hidden sites + if (holder.isSiteHidden == null || holder.isSiteHidden != site.isHidden) { + holder.isSiteHidden = site.isHidden; + holder.txtTitle.setTextColor(site.isHidden ? mTextColorHidden : mTextColorNormal); + holder.txtTitle.setTypeface(holder.txtTitle.getTypeface(), site.isHidden ? Typeface.NORMAL : Typeface.BOLD); + holder.imgBlavatar.setAlpha(site.isHidden ? 0.5f : 1f); + } + + // hide the divider for the last item + boolean isLastItem = (position == getItemCount() - 1); + holder.divider.setVisibility(isLastItem ? View.INVISIBLE : View.VISIBLE); + } + + public String getLastSearch() { + return mLastSearch; + } + + public void setLastSearch(String lastSearch) { + mLastSearch = lastSearch; + } + + public boolean getIsInSearchMode() { + return mIsInSearchMode; + } + + public void searchSites(String searchText) { + mLastSearch = searchText; + mSites = filteredSitesByText(mAllSites); + + notifyDataSetChanged(); + } + + private boolean isValidPosition(int position) { + return (position >= 0 && position < mSites.size()); + } + + /* + * called when the user chooses to edit the visibility of wp.com blogs + */ + void setEnableEditMode(boolean enable) { + if (mIsMultiSelectEnabled == enable) return; + + if (enable) { + mShowHiddenSites = true; + mShowSelfHostedSites = false; + } else { + mShowHiddenSites = false; + mShowSelfHostedSites = true; + } + + mIsMultiSelectEnabled = enable; + mSelectedPositions.clear(); + + loadSites(); + } + + int getNumSelected() { + return mSelectedPositions.size(); + } + + int getNumHiddenSelected() { + int numHidden = 0; + for (Integer i: mSelectedPositions) { + if (mSites.get(i).isHidden) { + numHidden++; + } + } + return numHidden; + } + + int getNumVisibleSelected() { + int numVisible = 0; + for (Integer i: mSelectedPositions) { + if (!mSites.get(i).isHidden) { + numVisible++; + } + } + return numVisible; + } + + private void toggleSelection(int position) { + setItemSelected(position, !isItemSelected(position)); + } + + private boolean isItemSelected(int position) { + return mSelectedPositions.contains(position); + } + + private void setItemSelected(int position, boolean isSelected) { + if (isItemSelected(position) == isSelected) { + return; + } + + if (isSelected) { + mSelectedPositions.add(position); + } else { + mSelectedPositions.remove(position); + } + notifyItemChanged(position); + + if (mSelectedCountListener != null) { + mSelectedCountListener.onSelectedCountChanged(getNumSelected()); + } + } + + void selectAll() { + if (mSelectedPositions.size() == mSites.size()) return; + + mSelectedPositions.clear(); + for (int i = 0; i < mSites.size(); i++) { + mSelectedPositions.add(i); + } + notifyDataSetChanged(); + + if (mSelectedCountListener != null) { + mSelectedCountListener.onSelectedCountChanged(getNumSelected()); + } + } + + void deselectAll() { + if (mSelectedPositions.size() == 0) return; + + mSelectedPositions.clear(); + notifyDataSetChanged(); + + if (mSelectedCountListener != null) { + mSelectedCountListener.onSelectedCountChanged(getNumSelected()); + } + } + + private SiteList getSelectedSites() { + SiteList sites = new SiteList(); + if (!mIsMultiSelectEnabled) { + return sites; + } + + for (Integer position : mSelectedPositions) { + if (isValidPosition(position)) + sites.add(mSites.get(position)); + } + + return sites; + } + + SiteList getHiddenSites() { + SiteList hiddenSites = new SiteList(); + for (SiteRecord site: mSites) { + if (site.isHidden) { + hiddenSites.add(site); + } + } + + return hiddenSites; + } + + void setVisibilityForSelectedSites(boolean makeVisible) { + SiteList sites = getSelectedSites(); + if (sites != null && sites.size() > 0) { + for (SiteRecord site: sites) { + int index = mSites.indexOfSite(site); + if (index > -1) { + mSites.get(index).isHidden = !makeVisible; + } + } + } + } + + void loadSites() { + if (mIsTaskRunning) { + AppLog.w(AppLog.T.UTILS, "site picker > already loading sites"); + } else { + new LoadSitesTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + } + + private SiteList filteredSitesByTextIfInSearchMode(SiteList sites) { + if (!mIsInSearchMode) { + return sites; + } else { + return filteredSitesByText(sites); + } + } + + private SiteList filteredSitesByText(SiteList sites) { + SiteList filteredSiteList = new SiteList(); + + for (int i = 0; i < sites.size(); i++) { + SiteRecord record = sites.get(i); + String siteNameLowerCase = record.blogName.toLowerCase(); + String hostNameLowerCase = record.homeURL.toLowerCase(); + + if (siteNameLowerCase.contains(mLastSearch.toLowerCase()) || hostNameLowerCase.contains(mLastSearch.toLowerCase())) { + filteredSiteList.add(record); + } + } + + return filteredSiteList; + } + + /* + * AsyncTask which loads sites from database and populates the adapter + */ + private boolean mIsTaskRunning; + private class LoadSitesTask extends AsyncTask<Void, Void, Void> { + @Override + protected void onPreExecute() { + super.onPreExecute(); + mIsTaskRunning = true; + } + + @Override + protected void onCancelled() { + super.onCancelled(); + mIsTaskRunning = false; + } + + @Override + protected Void doInBackground(Void... params) { + List<Map<String, Object>> blogs; + String[] extraFields = {"isHidden", "dotcomFlag", "homeURL"}; + + if (mIsInSearchMode) { + blogs = WordPress.wpDB.getBlogsBy(null, extraFields); + } else { + blogs = getBlogsForCurrentView(extraFields); + } + + SiteList sites = new SiteList(blogs); + + // sort by blog/host + final long primaryBlogId = AccountHelper.getDefaultAccount().getPrimaryBlogId(); + Collections.sort(sites, new Comparator<SiteRecord>() { + public int compare(SiteRecord site1, SiteRecord site2) { + if (primaryBlogId > 0) { + if (site1.blogId == primaryBlogId) { + return -1; + } else if (site2.blogId == primaryBlogId) { + return 1; + } + } + return site1.getBlogNameOrHomeURL().compareToIgnoreCase(site2.getBlogNameOrHomeURL()); + } + }); + + if (mSites == null || !mSites.isSameList(sites)) { + mAllSites = (SiteList) sites.clone(); + mSites = filteredSitesByTextIfInSearchMode(sites); + } + + return null; + } + + @Override + protected void onPostExecute(Void results) { + notifyDataSetChanged(); + mIsTaskRunning = false; + } + + private List<Map<String, Object>> getBlogsForCurrentView(String[] extraFields) { + if (mShowHiddenSites) { + if (mShowSelfHostedSites) { + // all self-hosted blogs and all wp.com blogs + return WordPress.wpDB.getBlogsBy(null, extraFields); + } else { + // only wp.com blogs + return WordPress.wpDB.getBlogsBy("dotcomFlag=1", extraFields); + } + } else { + if (mShowSelfHostedSites) { + // all self-hosted blogs plus visible wp.com blogs + return WordPress.wpDB.getBlogsBy("dotcomFlag=0 OR (isHidden=0 AND dotcomFlag=1) ", extraFields); + } else { + // only visible wp.com blogs + return WordPress.wpDB.getBlogsBy("isHidden=0 AND dotcomFlag=1", extraFields); + } + } + } + } + + /** + * SiteRecord is a simplified version of the full account (blog) record + */ + static class SiteRecord { + final int localId; + final int blogId; + final String blogName; + final String homeURL; + final String url; + final String blavatarUrl; + final boolean isDotCom; + boolean isHidden; + + SiteRecord(Map<String, Object> account) { + localId = MapUtils.getMapInt(account, "id"); + blogId = MapUtils.getMapInt(account, "blogId"); + blogName = BlogUtils.getBlogNameOrHomeURLFromAccountMap(account); + homeURL = BlogUtils.getHomeURLOrHostNameFromAccountMap(account); + url = MapUtils.getMapStr(account, "url"); + blavatarUrl = GravatarUtils.blavatarFromUrl(url, mBlavatarSz); + isDotCom = MapUtils.getMapBool(account, "dotcomFlag"); + isHidden = MapUtils.getMapBool(account, "isHidden"); + } + + String getBlogNameOrHomeURL() { + if (TextUtils.isEmpty(blogName)) { + return homeURL; + } + return blogName; + } + } + + static class SiteList extends ArrayList<SiteRecord> { + SiteList() { } + SiteList(List<Map<String, Object>> accounts) { + if (accounts != null) { + for (Map<String, Object> account : accounts) { + add(new SiteRecord(account)); + } + } + } + + boolean isSameList(SiteList sites) { + if (sites == null || sites.size() != this.size()) { + return false; + } + int i; + for (SiteRecord site: sites) { + i = indexOfSite(site); + if (i == -1 || this.get(i).isHidden != site.isHidden) { + return false; + } + } + return true; + } + + int indexOfSite(SiteRecord site) { + if (site != null && site.blogId > 0) { + for (int i = 0; i < size(); i++) { + if (site.blogId == this.get(i).blogId) { + return i; + } + } + } + return -1; + } + } +} |