Java tutorial
/* * Twidere - 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.mariotaku.twidere.fragment.support; import android.animation.Animator; import android.animation.Animator.AnimatorListener; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.app.Activity; import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.content.res.Resources; import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Matrix; import android.graphics.PorterDuff.Mode; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.FragmentActivity; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.support.v4.content.res.ResourcesCompat; import android.support.v4.util.LongSparseArray; import android.support.v4.util.Pair; import android.support.v4.view.MenuItemCompat; import android.support.v7.internal.view.SupportMenuInflater; import android.support.v7.widget.ActionMenuView; import android.support.v7.widget.ActionMenuView.OnMenuItemClickListener; import android.support.v7.widget.FixedLinearLayoutManager; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView.Adapter; import android.support.v7.widget.RecyclerView.ViewHolder; import android.view.ContextThemeWrapper; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.animation.DecelerateInterpolator; import android.widget.AdapterView; import android.widget.ImageView; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.TextView; import com.commonsware.cwac.merge.MergeAdapter; import com.nostra13.universalimageloader.core.assist.FailReason; import com.nostra13.universalimageloader.core.listener.ImageLoadingListener; import org.mariotaku.querybuilder.Expression; import org.mariotaku.twidere.R; import org.mariotaku.twidere.activity.SettingsActivity; import org.mariotaku.twidere.activity.iface.IThemedActivity; import org.mariotaku.twidere.activity.support.ComposeActivity; import org.mariotaku.twidere.activity.support.HomeActivity; import org.mariotaku.twidere.activity.support.QuickSearchBarActivity; import org.mariotaku.twidere.adapter.ArrayAdapter; import org.mariotaku.twidere.app.TwidereApplication; import org.mariotaku.twidere.constant.SharedPreferenceConstants; import org.mariotaku.twidere.menu.support.AccountToggleProvider; import org.mariotaku.twidere.model.ParcelableAccount; import org.mariotaku.twidere.provider.TwidereDataStore.Accounts; import org.mariotaku.twidere.util.CompareUtils; import org.mariotaku.twidere.util.KeyboardShortcutsHandler; import org.mariotaku.twidere.util.KeyboardShortcutsHandler.KeyboardShortcutCallback; import org.mariotaku.twidere.util.ListViewUtils; import org.mariotaku.twidere.util.MediaLoaderWrapper; import org.mariotaku.twidere.util.SharedPreferencesWrapper; import org.mariotaku.twidere.util.ThemeUtils; import org.mariotaku.twidere.util.TransitionUtils; import org.mariotaku.twidere.util.UserColorNameManager; import org.mariotaku.twidere.util.Utils; import org.mariotaku.twidere.util.content.SupportFragmentReloadCursorObserver; import org.mariotaku.twidere.view.ShapedImageView; import java.util.ArrayList; import java.util.Collections; import java.util.List; import static org.mariotaku.twidere.util.Utils.openUserFavorites; import static org.mariotaku.twidere.util.Utils.openUserLists; import static org.mariotaku.twidere.util.Utils.openUserProfile; public class AccountsDashboardFragment extends BaseSupportFragment implements LoaderCallbacks<Cursor>, OnSharedPreferenceChangeListener, ImageLoadingListener, OnClickListener, KeyboardShortcutCallback, AdapterView.OnItemClickListener { private final SupportFragmentReloadCursorObserver mReloadContentObserver = new SupportFragmentReloadCursorObserver( this, 0, this); private ContentResolver mResolver; private SharedPreferences mPreferences; private MergeAdapter mAdapter; private AccountSelectorAdapter mAccountsAdapter; private AccountOptionsAdapter mAccountOptionsAdapter; private AppMenuAdapter mAppMenuAdapter; private ListView mListView; private View mAccountSelectorView; private RecyclerView mAccountsSelector; private ImageView mAccountProfileBannerView; private ImageView mFloatingProfileImageSnapshotView; private ShapedImageView mAccountProfileImageView; private TextView mAccountProfileNameView, mAccountProfileScreenNameView; private ActionMenuView mAccountsToggleMenu; private View mAccountProfileContainer; private View mNoAccountContainer; private Context mThemedContext; private MediaLoaderWrapper mImageLoader; private AccountToggleProvider mAccountActionProvider; private boolean mSwitchAccountAnimationPlaying; public long[] getActivatedAccountIds() { if (mAccountActionProvider != null) { return mAccountActionProvider.getActivatedAccountIds(); } return Utils.getActivatedAccountIds(getActivity()); } @Override public boolean handleKeyboardShortcutSingle(@NonNull final KeyboardShortcutsHandler handler, final int keyCode, @NonNull final KeyEvent event) { return false; } @Override public boolean handleKeyboardShortcutRepeat(@NonNull final KeyboardShortcutsHandler handler, final int keyCode, final int repeatCount, @NonNull final KeyEvent event) { final String action = handler.getKeyAction(CONTEXT_TAG_NAVIGATION, keyCode, event); if (action == null) return false; final int offset; switch (action) { case ACTION_NAVIGATION_PREVIOUS: { offset = -1; break; } case ACTION_NAVIGATION_NEXT: { offset = 1; break; } default: { return false; } } final int firstVisiblePosition = ListViewUtils.getFirstFullyVisiblePosition(mListView); final int selectedItem = mListView.getSelectedItemPosition(); final int count = mListView.getCount(); int resultPosition; if (!mListView.isFocused() || selectedItem == ListView.INVALID_POSITION) { resultPosition = firstVisiblePosition; } else { resultPosition = selectedItem + offset; while (resultPosition >= 0 && resultPosition < count && !mAdapter.isEnabled(resultPosition)) { resultPosition += offset; } } final View focusedChild = mListView.getFocusedChild(); if (focusedChild == null) { mListView.requestChildFocus(mListView.getChildAt(0), null); } if (resultPosition >= 0 && resultPosition < count) { mListView.setSelection(resultPosition); } return true; } @Override public void onActivityResult(final int requestCode, final int resultCode, final Intent data) { switch (requestCode) { case REQUEST_SETTINGS: { if (data == null) return; final FragmentActivity activity = getActivity(); if (data.getBooleanExtra(EXTRA_CHANGED, false) && activity instanceof IThemedActivity) { ((IThemedActivity) activity).restart(); } return; } } super.onActivityResult(requestCode, resultCode, data); } @Override public void onResume() { super.onResume(); updateDefaultAccountState(); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.profile_container: { final ParcelableAccount account = mAccountsAdapter.getSelectedAccount(); if (account == null) return; final FragmentActivity activity = getActivity(); final Bundle activityOption = Utils.makeSceneTransitionOption(activity, new Pair<View, String>(mAccountProfileImageView, UserFragment.TRANSITION_NAME_PROFILE_IMAGE)); openUserProfile(activity, account.account_id, account.account_id, account.screen_name, activityOption); break; } } } @Override public Loader<Cursor> onCreateLoader(final int id, final Bundle args) { return new CursorLoader(getActivity(), Accounts.CONTENT_URI, Accounts.COLUMNS, null, null, Accounts.SORT_POSITION); } @Override public void onLoadFinished(final Loader<Cursor> loader, final Cursor data) { final Menu menu = mAccountsToggleMenu.getMenu(); mAccountActionProvider = (AccountToggleProvider) MenuItemCompat .getActionProvider(menu.findItem(MENU_SELECT_ACCOUNT)); final ParcelableAccount[] accounts = ParcelableAccount.getAccounts(data); if (accounts.length > 0) { mNoAccountContainer.setVisibility(View.GONE); mAccountProfileContainer.setVisibility(View.VISIBLE); } else { mNoAccountContainer.setVisibility(View.VISIBLE); mAccountProfileContainer.setVisibility(View.INVISIBLE); } long defaultId = -1; for (ParcelableAccount account : accounts) { if (account.is_activated) { defaultId = account.account_id; break; } } mAccountsAdapter.setAccounts(accounts); mAccountsAdapter.setSelectedAccountId(mPreferences.getLong(KEY_DEFAULT_ACCOUNT_ID, defaultId)); mAccountOptionsAdapter.setSelectedAccount(mAccountsAdapter.getSelectedAccount()); if (mAccountActionProvider != null) { mAccountActionProvider.setExclusive(false); mAccountActionProvider.setAccounts(accounts); } initAccountActionsAdapter(accounts); updateAccountOptionsSeparatorLabel(null); updateDefaultAccountState(); } @Override public void onLoaderReset(final Loader<Cursor> loader) { } @Override public void onItemClick(final AdapterView<?> parent, final View v, final int position, final long id) { final ListAdapter adapter = mAdapter.getAdapter(position); final Object item = mAdapter.getItem(position); if (adapter instanceof AccountOptionsAdapter) { final ParcelableAccount account = mAccountsAdapter.getSelectedAccount(); if (account == null || !(item instanceof OptionItem)) return; final OptionItem option = (OptionItem) item; switch (option.id) { case MENU_SEARCH: { final Intent intent = new Intent(getActivity(), QuickSearchBarActivity.class); intent.putExtra(EXTRA_ACCOUNT_ID, account.account_id); startActivity(intent); closeAccountsDrawer(); break; } case MENU_COMPOSE: { final Intent composeIntent = new Intent(INTENT_ACTION_COMPOSE); composeIntent.setClass(getActivity(), ComposeActivity.class); composeIntent.putExtra(EXTRA_ACCOUNT_IDS, new long[] { account.account_id }); startActivity(composeIntent); break; } case MENU_FAVORITES: { openUserFavorites(getActivity(), account.account_id, account.account_id, account.screen_name); break; } case MENU_LISTS: { openUserLists(getActivity(), account.account_id, account.account_id, account.screen_name); break; } case MENU_EDIT: { Utils.openProfileEditor(getActivity(), account.account_id); break; } } } else if (adapter instanceof AppMenuAdapter) { if (!(item instanceof OptionItem)) return; final OptionItem option = (OptionItem) item; switch (option.id) { case MENU_ACCOUNTS: { Utils.openAccountsManager(getActivity()); break; } case MENU_DRAFTS: { Utils.openDrafts(getActivity()); break; } case MENU_FILTERS: { Utils.openFilters(getActivity()); break; } case MENU_SETTINGS: { final Intent intent = new Intent(getActivity(), SettingsActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT); startActivityForResult(intent, REQUEST_SETTINGS); break; } } closeAccountsDrawer(); } } @Override public void onLoadingStarted(String imageUri, View view) { } @Override public void onLoadingFailed(String imageUri, View view, FailReason failReason) { } @Override public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) { view.setTag(imageUri); } @Override public void onLoadingCancelled(String imageUri, View view) { } @Override public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, final String key) { if (KEY_DEFAULT_ACCOUNT_ID.equals(key)) { updateDefaultAccountState(); } } public void setStatusBarHeight(int height) { mAccountProfileContainer.setPadding(0, height, 0, 0); } @Override protected void fitSystemWindows(Rect insets) { // No-op } @Override public void onActivityCreated(final Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE); mResolver = getContentResolver(); final View view = getView(); if (view == null) throw new AssertionError(); final Context context = view.getContext(); final TwidereApplication application = TwidereApplication.getInstance(context); mImageLoader = application.getMediaLoaderWrapper(); mListView.setItemsCanFocus(true); mAdapter = new MergeAdapter(); final LayoutInflater inflater = getLayoutInflater(savedInstanceState); mAccountsAdapter = new AccountSelectorAdapter(context, inflater, this); mAccountOptionsAdapter = new AccountOptionsAdapter(context); mAppMenuAdapter = new AppMenuAdapter(context); mAccountSelectorView = inflater.inflate(R.layout.header_drawer_account_selector, mListView, false); mAccountsSelector = (RecyclerView) mAccountSelectorView.findViewById(R.id.other_accounts_list); final LinearLayoutManager layoutManager = new FixedLinearLayoutManager(context); layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL); layoutManager.setStackFromEnd(true); mAccountsSelector.setLayoutManager(layoutManager); mAccountsSelector.setAdapter(mAccountsAdapter); mAccountsSelector.setItemAnimator(null); mAccountProfileContainer = mAccountSelectorView.findViewById(R.id.profile_container); mNoAccountContainer = mAccountSelectorView.findViewById(R.id.no_account_container); mAccountProfileImageView = (ShapedImageView) mAccountSelectorView.findViewById(R.id.profile_image); mAccountProfileBannerView = (ImageView) mAccountSelectorView.findViewById(R.id.account_profile_banner); mFloatingProfileImageSnapshotView = (ImageView) mAccountSelectorView .findViewById(R.id.floating_profile_image_snapshot); mAccountProfileNameView = (TextView) mAccountSelectorView.findViewById(R.id.name); mAccountProfileScreenNameView = (TextView) mAccountSelectorView.findViewById(R.id.screen_name); mAccountsToggleMenu = (ActionMenuView) mAccountSelectorView.findViewById(R.id.toggle_menu); final SupportMenuInflater menuInflater = new SupportMenuInflater(context); menuInflater.inflate(R.menu.action_dashboard_timeline_toggle, mAccountsToggleMenu.getMenu()); mAccountsToggleMenu.setOnMenuItemClickListener(new OnMenuItemClickListener() { @Override public boolean onMenuItemClick(MenuItem item) { if (item.getGroupId() != AccountToggleProvider.MENU_GROUP) return false; final ParcelableAccount[] accounts = mAccountActionProvider.getAccounts(); final ParcelableAccount account = accounts[item.getOrder()]; final ContentValues values = new ContentValues(); final boolean newActivated = !account.is_activated; mAccountActionProvider.setAccountActivated(account.account_id, newActivated); values.put(Accounts.IS_ACTIVATED, newActivated); final String where = Expression.equals(Accounts.ACCOUNT_ID, account.account_id).getSQL(); mResolver.update(Accounts.CONTENT_URI, values, where, null); return true; } }); mAccountProfileContainer.setOnClickListener(this); mAdapter.addView(mAccountSelectorView, true); mAdapter.addAdapter(mAccountOptionsAdapter); mAdapter.addView(inflater.inflate(R.layout.layout_divider_drawer, mListView, false), false); mAdapter.addAdapter(mAppMenuAdapter); mListView.setAdapter(mAdapter); mListView.setOnItemClickListener(this); mPreferences.registerOnSharedPreferenceChangeListener(this); getLoaderManager().initLoader(0, null, this); } @Override public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_accounts_dashboard, container, false); } @Override public void onBaseViewCreated(View view, Bundle savedInstanceState) { super.onBaseViewCreated(view, savedInstanceState); mListView = (ListView) view.findViewById(android.R.id.list); } @Override public void onStart() { super.onStart(); final ContentResolver resolver = getContentResolver(); resolver.registerContentObserver(Accounts.CONTENT_URI, true, mReloadContentObserver); getLoaderManager().restartLoader(0, null, this); } @Override public void onStop() { final ContentResolver resolver = getContentResolver(); resolver.unregisterContentObserver(mReloadContentObserver); super.onStop(); } void initAccountActionsAdapter(ParcelableAccount[] accounts) { mAccountOptionsAdapter.clear(); mAccountOptionsAdapter .add(new OptionItem(android.R.string.search_go, R.drawable.ic_action_search, MENU_SEARCH)); if (accounts.length > 1) { // mAccountOptionsAdapter.add(new OptionItem(R.string.compose, R.drawable.ic_action_status_compose, MENU_COMPOSE)); } mAccountOptionsAdapter.add(new OptionItem(R.string.favorites, R.drawable.ic_action_star, MENU_FAVORITES)); mAccountOptionsAdapter.add(new OptionItem(R.string.lists, R.drawable.ic_action_list, MENU_LISTS)); } private void closeAccountsDrawer() { final Activity activity = getActivity(); if (activity instanceof HomeActivity) { ((HomeActivity) activity).closeAccountsDrawer(); } } private void getLocationOnScreen(View view, RectF rectF) { final int[] location = new int[2]; view.getLocationOnScreen(location); rectF.set(location[0], location[1], location[0] + view.getWidth(), location[1] + view.getHeight()); } @Override public Context getThemedContext() { if (mThemedContext != null) return mThemedContext; final Context context = getActivity(); final int themeResource = ThemeUtils.getDrawerThemeResource(context); return mThemedContext = new ContextThemeWrapper(context, themeResource); } private void onAccountSelected(AccountProfileImageViewHolder holder, final ParcelableAccount account) { if (mSwitchAccountAnimationPlaying) return; final ImageView snapshotView = mFloatingProfileImageSnapshotView; final ShapedImageView profileImageView = mAccountProfileImageView; final ShapedImageView clickedImageView = holder.getIconView(); // Reset snapshot view position snapshotView.setPivotX(0); snapshotView.setPivotY(0); snapshotView.setTranslationX(0); snapshotView.setTranslationY(0); final Matrix matrix = new Matrix(); final RectF sourceBounds = new RectF(), destBounds = new RectF(), snapshotBounds = new RectF(); getLocationOnScreen(clickedImageView, sourceBounds); getLocationOnScreen(profileImageView, destBounds); getLocationOnScreen(snapshotView, snapshotBounds); final float finalScale = destBounds.width() / sourceBounds.width(); final Bitmap snapshotBitmap = TransitionUtils.createViewBitmap(clickedImageView, matrix, new RectF(0, 0, sourceBounds.width(), sourceBounds.height())); final ViewGroup.LayoutParams lp = snapshotView.getLayoutParams(); lp.width = clickedImageView.getWidth(); lp.height = clickedImageView.getHeight(); snapshotView.setLayoutParams(lp); // Copied from MaterialNavigationDrawer: https://github.com/madcyph3r/AdvancedMaterialDrawer/ AnimatorSet set = new AnimatorSet(); set.play(ObjectAnimator.ofFloat(snapshotView, View.TRANSLATION_X, sourceBounds.left - snapshotBounds.left, destBounds.left - snapshotBounds.left)) .with(ObjectAnimator.ofFloat(snapshotView, View.TRANSLATION_Y, sourceBounds.top - snapshotBounds.top, destBounds.top - snapshotBounds.top)) .with(ObjectAnimator.ofFloat(snapshotView, View.SCALE_X, 1, finalScale)) .with(ObjectAnimator.ofFloat(snapshotView, View.SCALE_Y, 1, finalScale)) .with(ObjectAnimator.ofFloat(profileImageView, View.ALPHA, 1, 0)) .with(ObjectAnimator.ofFloat(clickedImageView, View.SCALE_X, 0, 1)) .with(ObjectAnimator.ofFloat(clickedImageView, View.SCALE_Y, 0, 1)); final long animationTransition = 400; set.setDuration(animationTransition); set.setInterpolator(new DecelerateInterpolator()); set.addListener(new AnimatorListener() { private Drawable clickedDrawable; private int[] clickedColors; @Override public void onAnimationStart(Animator animation) { snapshotView.setVisibility(View.VISIBLE); snapshotView.setImageBitmap(snapshotBitmap); final Drawable profileDrawable = profileImageView.getDrawable(); clickedDrawable = clickedImageView.getDrawable(); clickedColors = clickedImageView.getBorderColors(); final ParcelableAccount oldSelectedAccount = mAccountsAdapter.getSelectedAccount(); mImageLoader.displayDashboardProfileImage(clickedImageView, oldSelectedAccount.profile_image_url, profileDrawable); // mImageLoader.displayDashboardProfileImage(profileImageView, // account.profile_image_url, clickedDrawable); clickedImageView.setBorderColors(profileImageView.getBorderColors()); mSwitchAccountAnimationPlaying = true; } @Override public void onAnimationEnd(Animator animation) { finishAnimation(); } @Override public void onAnimationCancel(Animator animation) { finishAnimation(); } @Override public void onAnimationRepeat(Animator animation) { } private void finishAnimation() { final Editor editor = mPreferences.edit(); editor.putLong(KEY_DEFAULT_ACCOUNT_ID, account.account_id); editor.apply(); mAccountsAdapter.setSelectedAccountId(account.account_id); mAccountOptionsAdapter.setSelectedAccount(account); updateAccountOptionsSeparatorLabel(clickedDrawable); snapshotView.setVisibility(View.INVISIBLE); snapshotView.setImageDrawable(null); profileImageView.setImageDrawable(clickedDrawable); profileImageView.setBorderColors(clickedColors); profileImageView.setAlpha(1f); clickedImageView.setScaleX(1); clickedImageView.setScaleY(1); clickedImageView.setAlpha(1f); mSwitchAccountAnimationPlaying = false; } }); set.start(); } private void updateAccountOptionsSeparatorLabel(Drawable profileImageSnapshot) { final ParcelableAccount account = mAccountsAdapter.getSelectedAccount(); if (account == null) { return; } mAccountProfileNameView.setText(account.name); mAccountProfileScreenNameView.setText("@" + account.screen_name); mImageLoader.displayDashboardProfileImage(mAccountProfileImageView, account.profile_image_url, profileImageSnapshot); mAccountProfileImageView.setBorderColors(account.color); final int bannerWidth = mAccountProfileBannerView.getWidth(); final Resources res = getResources(); final int defWidth = res.getDisplayMetrics().widthPixels; final int width = bannerWidth > 0 ? bannerWidth : defWidth; final String bannerUrl = Utils.getBestBannerUrl(account.profile_banner_url, width); final ImageView bannerView = mAccountProfileBannerView; if (bannerView.getDrawable() == null || !CompareUtils.objectEquals(bannerUrl, bannerView.getTag())) { mImageLoader.displayProfileBanner(mAccountProfileBannerView, bannerUrl, this); } else { mImageLoader.cancelDisplayTask(mAccountProfileBannerView); } } private void updateDefaultAccountState() { } private static final class AccountOptionsAdapter extends OptionItemsAdapter { private final boolean mNameFirst; private final UserColorNameManager mUserColorNameManager; private ParcelableAccount mSelectedAccount; public AccountOptionsAdapter(final Context context) { super(context); mUserColorNameManager = UserColorNameManager.getInstance(context); mNameFirst = SharedPreferencesWrapper.getInstance(context, SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE, SharedPreferenceConstants.class).getBoolean(KEY_NAME_FIRST); } public void setSelectedAccount(ParcelableAccount account) { mSelectedAccount = account; notifyDataSetChanged(); } @Override protected String getTitle(int position, OptionItem option) { final ParcelableAccount account = mSelectedAccount; if (account != null && option.id == MENU_COMPOSE) { final Context context = getContext(); final String displayName = mUserColorNameManager.getDisplayName(-1, account.name, account.screen_name, mNameFirst, false); return context.getString(R.string.tweet_from_name, displayName); } return super.getTitle(position, option); } } static class AccountProfileImageViewHolder extends ViewHolder implements OnClickListener { private final AccountSelectorAdapter adapter; private final ShapedImageView icon; public AccountProfileImageViewHolder(AccountSelectorAdapter adapter, View itemView) { super(itemView); this.adapter = adapter; itemView.setOnClickListener(this); icon = (ShapedImageView) itemView.findViewById(android.R.id.icon); } public ShapedImageView getIconView() { return icon; } @Override public void onClick(View v) { adapter.dispatchItemSelected(this); } } private static class AccountSelectorAdapter extends Adapter<AccountProfileImageViewHolder> { private final LayoutInflater mInflater; private final MediaLoaderWrapper mImageLoader; private final AccountsDashboardFragment mFragment; private final LongSparseArray<Long> positionMap = new LongSparseArray<>(); private ParcelableAccount[] mInternalAccounts; AccountSelectorAdapter(Context context, LayoutInflater inflater, AccountsDashboardFragment fragment) { mInflater = inflater; mImageLoader = TwidereApplication.getInstance(context).getMediaLoaderWrapper(); mFragment = fragment; setHasStableIds(true); } public ParcelableAccount getAdapterAccount(int adapterPosition) { if (mInternalAccounts == null || mInternalAccounts.length < 1) { return null; } return mInternalAccounts[adapterPosition + 1]; } @Nullable public ParcelableAccount getSelectedAccount() { if (mInternalAccounts == null || mInternalAccounts.length == 0) { return null; } return mInternalAccounts[0]; } public long getSelectedAccountId() { final ParcelableAccount selectedAccount = getSelectedAccount(); if (selectedAccount == null) return -1; return selectedAccount.account_id; } public void setSelectedAccountId(long accountId) { final ParcelableAccount selectedAccount = getSelectedAccount(); if (selectedAccount == null) return; swap(accountId, selectedAccount.account_id); } @Override public AccountProfileImageViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { final View view = mInflater.inflate(R.layout.adapter_item_dashboard_account, parent, false); return new AccountProfileImageViewHolder(this, view); } @Override public void onBindViewHolder(AccountProfileImageViewHolder holder, int position) { // holder.itemView.setAlpha(c.getInt(mIndices.is_activated) == 1 ? 1 : 0.5f); final ParcelableAccount account = getAdapterAccount(position); mImageLoader.cancelDisplayTask(holder.icon); // holder.icon.setImageDrawable(null); mImageLoader.displayDashboardProfileImage(holder.icon, account.profile_image_url, null); holder.icon.setBorderColor(account.color); } @Override public long getItemId(int position) { return getAdapterAccount(position).account_id; } @Override public int getItemCount() { if (mInternalAccounts == null || mInternalAccounts.length == 0) return 0; return mInternalAccounts.length - 1; } public void setAccounts(ParcelableAccount[] accounts) { if (accounts != null) { final ParcelableAccount[] previousAccounts = mInternalAccounts; mInternalAccounts = new ParcelableAccount[accounts.length]; int tempIdx = 0; final List<ParcelableAccount> tempList = new ArrayList<>(); Collections.addAll(tempList, accounts); if (previousAccounts != null) { for (ParcelableAccount previousAccount : previousAccounts) { final int idx = indexOfAccount(tempList, previousAccount.account_id); if (idx >= 0) { mInternalAccounts[tempIdx++] = tempList.remove(idx); } } } for (ParcelableAccount account : tempList) { mInternalAccounts[tempIdx++] = account; } } else { mInternalAccounts = null; } notifyDataSetChanged(); } private void dispatchItemSelected(AccountProfileImageViewHolder holder) { mFragment.onAccountSelected(holder, getAdapterAccount(holder.getAdapterPosition())); } private static int indexOfAccount(List<ParcelableAccount> accounts, long accountId) { for (int i = 0, j = accounts.size(); i < j; i++) { if (accounts.get(i).account_id == accountId) return i; } return -1; } private void swap(long fromId, long toId) { int fromIdx = -1, toIdx = -1; for (int i = 0, j = mInternalAccounts.length; i < j; i++) { final ParcelableAccount account = mInternalAccounts[i]; if (account.account_id == fromId) { fromIdx = i; } if (account.account_id == toId) { toIdx = i; } } if (fromIdx < 0 || toIdx < 0) return; final ParcelableAccount temp = mInternalAccounts[toIdx]; mInternalAccounts[toIdx] = mInternalAccounts[fromIdx]; mInternalAccounts[fromIdx] = temp; notifyDataSetChanged(); } } private static final class AppMenuAdapter extends OptionItemsAdapter { public AppMenuAdapter(final Context context) { super(context); add(new OptionItem(R.string.accounts, R.drawable.ic_action_accounts, MENU_ACCOUNTS)); add(new OptionItem(R.string.drafts, R.drawable.ic_action_draft, MENU_DRAFTS)); add(new OptionItem(R.string.filters, R.drawable.ic_action_speaker_muted, MENU_FILTERS)); add(new OptionItem(R.string.settings, R.drawable.ic_action_settings, MENU_SETTINGS)); } } private static class OptionItem { private final int name, icon, id; OptionItem(final int name, final int icon, final int id) { this.name = name; this.icon = icon; this.id = id; } @Override public boolean equals(final Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof OptionItem)) return false; final OptionItem other = (OptionItem) obj; if (icon != other.icon) return false; if (id != other.id) return false; if (name != other.name) return false; return true; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + icon; result = prime * result + id; result = prime * result + name; return result; } @Override public String toString() { return "AccountOption{name=" + name + ", icon=" + icon + ", id=" + id + "}"; } } private static abstract class OptionItemsAdapter extends ArrayAdapter<OptionItem> { private final int mActionIconColor; public OptionItemsAdapter(final Context context) { super(context, R.layout.list_item_dashboard_menu); mActionIconColor = ThemeUtils.getThemeForegroundColor(context); } @Override public View getView(final int position, final View convertView, final ViewGroup parent) { final View view = super.getView(position, convertView, parent); final OptionItem option = getItem(position); final TextView text1 = (TextView) view.findViewById(android.R.id.text1); final ImageView icon = (ImageView) view.findViewById(android.R.id.icon); text1.setText(getTitle(position, option)); icon.setImageDrawable(ResourcesCompat.getDrawable(icon.getResources(), option.icon, null)); icon.setColorFilter(mActionIconColor, Mode.SRC_ATOP); return view; } protected String getTitle(int position, OptionItem option) { return getContext().getString(option.name); } } }