redesigned account selector
This commit is contained in:
parent
72aaf3a887
commit
8ad206a9c8
|
@ -25,6 +25,7 @@ import android.graphics.Color;
|
|||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import org.mariotaku.querybuilder.Columns.Column;
|
||||
import org.mariotaku.querybuilder.Expression;
|
||||
|
@ -144,24 +145,37 @@ public class ParcelableAccount implements Parcelable {
|
|||
return list.toArray(new ParcelableAccount[list.size()]);
|
||||
}
|
||||
|
||||
public static ParcelableAccount[] getAccounts(final Context context, final long[] accountIds) {
|
||||
@NonNull
|
||||
public static ParcelableAccount[] getAccounts(@Nullable final Context context, @Nullable final long[] accountIds) {
|
||||
if (context == null) return new ParcelableAccount[0];
|
||||
final String where = accountIds != null ? Expression.in(new Column(Accounts.ACCOUNT_ID),
|
||||
new RawItemArray(accountIds)).getSQL() : null;
|
||||
final Cursor cur = ContentResolverUtils.query(context.getContentResolver(), Accounts.CONTENT_URI,
|
||||
Accounts.COLUMNS_NO_CREDENTIALS, where, null, null);
|
||||
if (cur == null) return new ParcelableAccount[0];
|
||||
return getAccounts(cur, new Indices(cur));
|
||||
}
|
||||
|
||||
|
||||
@NonNull
|
||||
public static ParcelableAccount[] getAccounts(@Nullable final Cursor cursor) {
|
||||
if (cursor == null) return new ParcelableAccount[0];
|
||||
return getAccounts(cursor, new Indices(cursor));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static ParcelableAccount[] getAccounts(@Nullable final Cursor cursor,@Nullable final Indices indices) {
|
||||
if (cursor == null || indices == null) return new ParcelableAccount[0];
|
||||
try {
|
||||
final Indices idx = new Indices(cur);
|
||||
cur.moveToFirst();
|
||||
final ParcelableAccount[] names = new ParcelableAccount[cur.getCount()];
|
||||
while (!cur.isAfterLast()) {
|
||||
names[cur.getPosition()] = new ParcelableAccount(cur, idx);
|
||||
cur.moveToNext();
|
||||
cursor.moveToFirst();
|
||||
final ParcelableAccount[] names = new ParcelableAccount[cursor.getCount()];
|
||||
while (!cursor.isAfterLast()) {
|
||||
names[cursor.getPosition()] = new ParcelableAccount(cursor, indices);
|
||||
cursor.moveToNext();
|
||||
}
|
||||
return names;
|
||||
} finally {
|
||||
cur.close();
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
|
||||
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;
|
||||
|
@ -29,13 +33,18 @@ 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.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;
|
||||
|
@ -52,6 +61,7 @@ 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.CompoundButton;
|
||||
import android.widget.CompoundButton.OnCheckedChangeListener;
|
||||
import android.widget.ImageView;
|
||||
|
@ -78,17 +88,19 @@ import org.mariotaku.twidere.adapter.ArrayAdapter;
|
|||
import org.mariotaku.twidere.app.TwidereApplication;
|
||||
import org.mariotaku.twidere.menu.SupportAccountActionProvider;
|
||||
import org.mariotaku.twidere.model.ParcelableAccount;
|
||||
import org.mariotaku.twidere.model.ParcelableAccount.Indices;
|
||||
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
|
||||
import org.mariotaku.twidere.util.CompareUtils;
|
||||
import org.mariotaku.twidere.util.ImageLoaderWrapper;
|
||||
import org.mariotaku.twidere.util.ThemeUtils;
|
||||
import org.mariotaku.twidere.util.TransitionUtils;
|
||||
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.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.mariotaku.twidere.util.Utils.openUserFavorites;
|
||||
|
@ -114,6 +126,7 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
|
|||
private View mAccountSelectorView;
|
||||
private RecyclerView mAccountsSelector;
|
||||
private ImageView mAccountProfileBannerView;
|
||||
private ImageView mFloatingProfileImageSnapshotView;
|
||||
private ShapedImageView mAccountProfileImageView;
|
||||
private TextView mAccountProfileNameView, mAccountProfileScreenNameView;
|
||||
private ActionMenuView mAccountsToggleMenu;
|
||||
|
@ -122,6 +135,7 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
|
|||
private Context mThemedContext;
|
||||
private ImageLoaderWrapper mImageLoader;
|
||||
private SupportAccountActionProvider mAccountActionProvider;
|
||||
private boolean mSwitchAccountAnimationPlaying;
|
||||
|
||||
@Override
|
||||
public void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
|
||||
|
@ -180,38 +194,30 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
|
|||
final Menu menu = mAccountsToggleMenu.getMenu();
|
||||
mAccountActionProvider = (SupportAccountActionProvider) MenuItemCompat.getActionProvider(menu.findItem(MENU_SELECT_ACCOUNT));
|
||||
mAccountActionProvider.setExclusive(false);
|
||||
final ArrayList<ParcelableAccount> accounts = new ArrayList<>();
|
||||
final ParcelableAccount[] accounts = ParcelableAccount.getAccounts(data);
|
||||
final Set<Long> activatedIds = new HashSet<>();
|
||||
if (data != null) {
|
||||
data.moveToFirst();
|
||||
final Indices indices = new Indices(data);
|
||||
long defaultId = -1;
|
||||
while (!data.isAfterLast()) {
|
||||
final ParcelableAccount account = new ParcelableAccount(data, indices);
|
||||
accounts.add(account);
|
||||
if (account.is_activated) {
|
||||
if (defaultId < 0) {
|
||||
defaultId = account.account_id;
|
||||
}
|
||||
activatedIds.add(account.account_id);
|
||||
long defaultId = -1;
|
||||
for (ParcelableAccount account : accounts) {
|
||||
if (account.is_activated) {
|
||||
if (defaultId < 0) {
|
||||
defaultId = account.account_id;
|
||||
}
|
||||
data.moveToNext();
|
||||
}
|
||||
if (mAccountsAdapter.getSelectedAccountId() <= 0) {
|
||||
mAccountsAdapter.setSelectedAccountId(mPreferences.getLong(KEY_DEFAULT_ACCOUNT_ID, defaultId));
|
||||
activatedIds.add(account.account_id);
|
||||
}
|
||||
}
|
||||
mAccountActionProvider.setAccounts(accounts.toArray(new ParcelableAccount[accounts.size()]));
|
||||
mAccountsAdapter.setAccounts(accounts);
|
||||
if (mAccountsAdapter.getSelectedAccountId() <= 0) {
|
||||
mAccountsAdapter.setSelectedAccountId(mPreferences.getLong(KEY_DEFAULT_ACCOUNT_ID, defaultId));
|
||||
}
|
||||
mAccountActionProvider.setAccounts(accounts);
|
||||
mAccountActionProvider.setSelectedAccountIds(ArrayUtils.toPrimitive(activatedIds.toArray(new Long[activatedIds.size()])));
|
||||
|
||||
mAccountsAdapter.changeCursor(data);
|
||||
updateAccountOptionsSeparatorLabel();
|
||||
updateAccountOptionsSeparatorLabel(null);
|
||||
updateDefaultAccountState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(final Loader<Cursor> loader) {
|
||||
mAccountsAdapter.changeCursor(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -345,9 +351,11 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
|
|||
layoutManager.setStackFromEnd(true);
|
||||
mAccountsSelector.setLayoutManager(layoutManager);
|
||||
mAccountsSelector.setAdapter(mAccountsAdapter);
|
||||
mAccountsSelector.setItemAnimator(null);
|
||||
mAccountProfileContainer = mAccountSelectorView.findViewById(R.id.profile_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);
|
||||
|
@ -412,19 +420,102 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
|
|||
return mThemedContext = new ContextThemeWrapper(context, themeResource);
|
||||
}
|
||||
|
||||
private void onAccountSelected(ParcelableAccount account) {
|
||||
mAccountsAdapter.setSelectedAccountId(account.account_id);
|
||||
updateAccountOptionsSeparatorLabel();
|
||||
private void onAccountSelected(AccountProfileImageViewHolder holder, final ParcelableAccount account) {
|
||||
if (mSwitchAccountAnimationPlaying) return;
|
||||
final ImageView snapshotView = mFloatingProfileImageSnapshotView;
|
||||
final ShapedImageView profileImageView = mAccountProfileImageView;
|
||||
final ShapedImageView clickedImageView = holder.getIconView();
|
||||
final Matrix matrix = new Matrix();
|
||||
final Rect tempRect = new Rect();
|
||||
clickedImageView.getGlobalVisibleRect(tempRect);
|
||||
final RectF sourceBounds = new RectF(tempRect);
|
||||
profileImageView.getGlobalVisibleRect(tempRect);
|
||||
final RectF destBounds = new RectF(tempRect);
|
||||
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();
|
||||
snapshotView.setPivotX(0);
|
||||
snapshotView.setPivotY(0);
|
||||
snapshotView.setX(sourceBounds.left);
|
||||
snapshotView.setY(sourceBounds.top);
|
||||
set.play(ObjectAnimator.ofFloat(snapshotView, View.X, sourceBounds.left, destBounds.left))
|
||||
.with(ObjectAnimator.ofFloat(snapshotView, View.Y, sourceBounds.top, destBounds.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();
|
||||
}
|
||||
|
||||
private void finishAnimation() {
|
||||
mAccountsAdapter.setSelectedAccountId(account.account_id);
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
finishAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
|
||||
}
|
||||
});
|
||||
set.start();
|
||||
}
|
||||
|
||||
private void updateAccountOptionsSeparatorLabel() {
|
||||
private void updateAccountOptionsSeparatorLabel(Drawable profileImageSnapshot) {
|
||||
final ParcelableAccount account = mAccountsAdapter.getSelectedAccount();
|
||||
if (account == null) {
|
||||
return;
|
||||
}
|
||||
mAccountProfileNameView.setText(account.name);
|
||||
mAccountProfileScreenNameView.setText("@" + account.screen_name);
|
||||
mImageLoader.displayProfileImage(mAccountProfileImageView, account.profile_image_url);
|
||||
mImageLoader.displayDashboardProfileImage(mAccountProfileImageView,
|
||||
account.profile_image_url, profileImageSnapshot);
|
||||
mAccountProfileImageView.setBorderColors(account.color);
|
||||
final int bannerWidth = mAccountProfileBannerView.getWidth();
|
||||
final Resources res = getResources();
|
||||
|
@ -483,9 +574,13 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
|
|||
icon = (ShapedImageView) itemView.findViewById(android.R.id.icon);
|
||||
}
|
||||
|
||||
public ShapedImageView getIconView() {
|
||||
return icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
adapter.dispatchItemSelected(getPosition());
|
||||
adapter.dispatchItemSelected(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -494,62 +589,95 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
|
|||
private final LayoutInflater mInflater;
|
||||
private final ImageLoaderWrapper mImageLoader;
|
||||
private final AccountsDashboardFragment mFragment;
|
||||
private Cursor mCursor;
|
||||
private Indices mIndices;
|
||||
private long mSelectedAccountId;
|
||||
private int mSelectedAccountIndex;
|
||||
private ParcelableAccount[] mAccounts;
|
||||
private ParcelableAccount[] mInternalAccounts;
|
||||
|
||||
AccountSelectorAdapter(Context context, AccountsDashboardFragment fragment) {
|
||||
mInflater = LayoutInflater.from(context);
|
||||
mImageLoader = TwidereApplication.getInstance(context).getImageLoaderWrapper();
|
||||
mFragment = fragment;
|
||||
setHasStableIds(true);
|
||||
}
|
||||
|
||||
public void changeCursor(Cursor cursor) {
|
||||
mCursor = cursor;
|
||||
if (cursor != null) {
|
||||
mIndices = new Indices(cursor);
|
||||
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;
|
||||
}
|
||||
|
||||
public void setAccounts(ParcelableAccount[] accounts) {
|
||||
mAccounts = accounts;
|
||||
if (accounts != null) {
|
||||
final ParcelableAccount[] previousAccounts = mInternalAccounts;
|
||||
mInternalAccounts = new ParcelableAccount[accounts.length];
|
||||
int tempIdx = 0;
|
||||
final List<ParcelableAccount> tempList = Arrays.asList(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;
|
||||
}
|
||||
updateSelectedAccountIndex();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void updateSelectedAccountIndex() {
|
||||
final Cursor c = mCursor;
|
||||
final Indices i = mIndices;
|
||||
mSelectedAccountIndex = -1;
|
||||
if (c != null && i != null && c.moveToFirst()) {
|
||||
while (!c.isAfterLast()) {
|
||||
if (c.getLong(mIndices.account_id) == mSelectedAccountId) {
|
||||
mSelectedAccountIndex = c.getPosition();
|
||||
break;
|
||||
}
|
||||
c.moveToNext();
|
||||
|
||||
public ParcelableAccount getAdapterAccount(int adapterPosition) {
|
||||
if (mInternalAccounts == null || mInternalAccounts.length < 1) {
|
||||
return null;
|
||||
}
|
||||
return mInternalAccounts[adapterPosition + 1];
|
||||
}
|
||||
|
||||
private final LongSparseArray<Long> positionMap = new LongSparseArray<>();
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
public ParcelableAccount getSelectedAccount() {
|
||||
final Cursor c = mCursor;
|
||||
final Indices i = mIndices;
|
||||
if (c != null && i != null && c.moveToFirst()) {
|
||||
while (!c.isAfterLast()) {
|
||||
if (c.getLong(mIndices.account_id) == mSelectedAccountId)
|
||||
return new ParcelableAccount(c, mIndices);
|
||||
c.moveToNext();
|
||||
}
|
||||
if (mInternalAccounts == null || mInternalAccounts.length < 0) {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
return mInternalAccounts[0];
|
||||
}
|
||||
|
||||
public long getSelectedAccountId() {
|
||||
return mSelectedAccountId;
|
||||
return getSelectedAccount().account_id;
|
||||
}
|
||||
|
||||
public void setSelectedAccountId(long accountId) {
|
||||
mSelectedAccountId = accountId;
|
||||
updateSelectedAccountIndex();
|
||||
notifyDataSetChanged();
|
||||
final ParcelableAccount selectedAccount = getSelectedAccount();
|
||||
if (selectedAccount == null) return;
|
||||
swap(accountId, selectedAccount.account_id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return getAdapterAccount(position).account_id;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -560,31 +688,22 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
|
|||
|
||||
@Override
|
||||
public void onBindViewHolder(AccountProfileImageViewHolder holder, int position) {
|
||||
final Cursor c = mCursor;
|
||||
if (mSelectedAccountIndex != -1 && position >= mSelectedAccountIndex) {
|
||||
c.moveToPosition(position + 1);
|
||||
} else {
|
||||
c.moveToPosition(position);
|
||||
}
|
||||
holder.itemView.setAlpha(c.getInt(mIndices.is_activated) == 1 ? 1 : 0.5f);
|
||||
mImageLoader.displayProfileImage(holder.icon, c.getString(mIndices.profile_image_url));
|
||||
holder.icon.setBorderColor(c.getInt(mIndices.color));
|
||||
// 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 int getItemCount() {
|
||||
if (mCursor == null) return 0;
|
||||
return Math.max(mCursor.getCount() - 1, 0);
|
||||
if (mInternalAccounts == null || mInternalAccounts.length == 0) return 0;
|
||||
return mInternalAccounts.length - 1;
|
||||
}
|
||||
|
||||
private void dispatchItemSelected(int position) {
|
||||
final Cursor c = mCursor;
|
||||
if (mSelectedAccountIndex != -1 && position >= mSelectedAccountIndex) {
|
||||
c.moveToPosition(position + 1);
|
||||
} else {
|
||||
c.moveToPosition(position);
|
||||
}
|
||||
mFragment.onAccountSelected(new ParcelableAccount(c, mIndices));
|
||||
private void dispatchItemSelected(AccountProfileImageViewHolder holder) {
|
||||
mFragment.onAccountSelected(holder, getAdapterAccount(holder.getAdapterPosition()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -643,7 +762,7 @@ public class AccountsDashboardFragment extends BaseSupportListFragment implement
|
|||
final TextView text1 = (TextView) view.findViewById(android.R.id.text1);
|
||||
final ImageView icon = (ImageView) view.findViewById(android.R.id.icon);
|
||||
text1.setText(option.name);
|
||||
icon.setImageDrawable(icon.getResources().getDrawable(option.icon));
|
||||
icon.setImageDrawable(ResourcesCompat.getDrawable(icon.getResources(), option.icon, null));
|
||||
icon.setColorFilter(mActionIconColor, Mode.SRC_ATOP);
|
||||
return view;
|
||||
}
|
||||
|
|
|
@ -20,9 +20,11 @@
|
|||
package org.mariotaku.twidere.util;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.nostra13.universalimageloader.core.DisplayImageOptions;
|
||||
import com.nostra13.universalimageloader.core.DisplayImageOptions.Builder;
|
||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||
import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer;
|
||||
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
|
||||
|
@ -38,6 +40,7 @@ public class ImageLoaderWrapper implements Constants {
|
|||
|
||||
private final ImageLoader mImageLoader;
|
||||
private final DisplayImageOptions mProfileImageDisplayOptions;
|
||||
private final DisplayImageOptions mDashboardProfileImageDisplayOptions;
|
||||
private final DisplayImageOptions mOvalProfileImageDisplayOptions;
|
||||
private final DisplayImageOptions mImageDisplayOptions, mBannerDisplayOptions;
|
||||
|
||||
|
@ -72,11 +75,17 @@ public class ImageLoaderWrapper implements Constants {
|
|||
bannerOptsBuilder.cacheOnDisk(true);
|
||||
bannerOptsBuilder.bitmapConfig(Bitmap.Config.RGB_565);
|
||||
bannerOptsBuilder.displayer(new FadeInBitmapDisplayer(200, true, true, true));
|
||||
final DisplayImageOptions.Builder dashboardProfileOptsBuilder = new DisplayImageOptions.Builder();
|
||||
// dashboardProfileOptsBuilder.showImageOnLoading(android.R.color.transparent);
|
||||
dashboardProfileOptsBuilder.cacheInMemory(true);
|
||||
dashboardProfileOptsBuilder.cacheOnDisk(true);
|
||||
dashboardProfileOptsBuilder.bitmapConfig(Bitmap.Config.RGB_565);
|
||||
|
||||
mProfileImageDisplayOptions = profileOptsBuilder.build();
|
||||
mOvalProfileImageDisplayOptions = ovalProfileOptsBuilder.build();
|
||||
mImageDisplayOptions = imageOptsBuilder.build();
|
||||
mBannerDisplayOptions = bannerOptsBuilder.build();
|
||||
mDashboardProfileImageDisplayOptions = dashboardProfileOptsBuilder.build();
|
||||
}
|
||||
|
||||
public void clearFileCache() {
|
||||
|
@ -120,6 +129,18 @@ public class ImageLoaderWrapper implements Constants {
|
|||
mImageLoader.displayImage(url, view, mProfileImageDisplayOptions);
|
||||
}
|
||||
|
||||
public void displayDashboardProfileImage(final ImageView view, final String url, Drawable drawableOnLoading) {
|
||||
if (drawableOnLoading != null) {
|
||||
final Builder builder = new Builder();
|
||||
builder.cloneFrom(mDashboardProfileImageDisplayOptions);
|
||||
builder.showImageOnLoading(drawableOnLoading);
|
||||
builder.showImageOnFail(drawableOnLoading);
|
||||
mImageLoader.displayImage(url, view, builder.build());
|
||||
return;
|
||||
}
|
||||
mImageLoader.displayImage(url, view, mDashboardProfileImageDisplayOptions);
|
||||
}
|
||||
|
||||
|
||||
public void displayImage(final ImageView view, final String url, DisplayImageOptions options) {
|
||||
mImageLoader.displayImage(url, view, options);
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Twidere - Twitter client for Android
|
||||
*
|
||||
* Copyright (C) 2012-2015 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.util;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.TypeEvaluator;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* Static utility methods for Transitions.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class TransitionUtils {
|
||||
private static int MAX_IMAGE_SIZE = (1024 * 1024);
|
||||
|
||||
static Animator mergeAnimators(Animator animator1, Animator animator2) {
|
||||
if (animator1 == null) {
|
||||
return animator2;
|
||||
} else if (animator2 == null) {
|
||||
return animator1;
|
||||
} else {
|
||||
AnimatorSet animatorSet = new AnimatorSet();
|
||||
animatorSet.playTogether(animator1, animator2);
|
||||
return animatorSet;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a copy of bitmap of given drawable, return null if intrinsic size is zero
|
||||
*/
|
||||
public static Bitmap createDrawableBitmap(Drawable drawable) {
|
||||
int width = drawable.getIntrinsicWidth();
|
||||
int height = drawable.getIntrinsicHeight();
|
||||
if (width <= 0 || height <= 0) {
|
||||
return null;
|
||||
}
|
||||
float scale = Math.min(1f, ((float) MAX_IMAGE_SIZE) / (width * height));
|
||||
if (drawable instanceof BitmapDrawable && scale == 1f) {
|
||||
// return same bitmap if scale down not needed
|
||||
return ((BitmapDrawable) drawable).getBitmap();
|
||||
}
|
||||
int bitmapWidth = (int) (width * scale);
|
||||
int bitmapHeight = (int) (height * scale);
|
||||
Bitmap bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
Rect existingBounds = drawable.getBounds();
|
||||
int left = existingBounds.left;
|
||||
int top = existingBounds.top;
|
||||
int right = existingBounds.right;
|
||||
int bottom = existingBounds.bottom;
|
||||
drawable.setBounds(0, 0, bitmapWidth, bitmapHeight);
|
||||
drawable.draw(canvas);
|
||||
drawable.setBounds(left, top, right, bottom);
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Bitmap of the given view, using the Matrix matrix to transform to the local
|
||||
* coordinates. <code>matrix</code> will be modified during the bitmap creation.
|
||||
* <p/>
|
||||
* <p>If the bitmap is large, it will be scaled uniformly down to at most 1MB size.</p>
|
||||
*
|
||||
* @param view The view to create a bitmap for.
|
||||
* @param matrix The matrix converting the view local coordinates to the coordinates that
|
||||
* the bitmap will be displayed in. <code>matrix</code> will be modified before
|
||||
* returning.
|
||||
* @param bounds The bounds of the bitmap in the destination coordinate system (where the
|
||||
* view should be presented. Typically, this is matrix.mapRect(viewBounds);
|
||||
* @return A bitmap of the given view or null if bounds has no width or height.
|
||||
*/
|
||||
public static Bitmap createViewBitmap(View view, Matrix matrix, RectF bounds) {
|
||||
Bitmap bitmap = null;
|
||||
int bitmapWidth = Math.round(bounds.width());
|
||||
int bitmapHeight = Math.round(bounds.height());
|
||||
if (bitmapWidth > 0 && bitmapHeight > 0) {
|
||||
float scale = Math.min(1f, ((float) MAX_IMAGE_SIZE) / (bitmapWidth * bitmapHeight));
|
||||
bitmapWidth *= scale;
|
||||
bitmapHeight *= scale;
|
||||
matrix.postTranslate(-bounds.left, -bounds.top);
|
||||
matrix.postScale(scale, scale);
|
||||
bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
canvas.concat(matrix);
|
||||
view.draw(canvas);
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
public static class MatrixEvaluator implements TypeEvaluator<Matrix> {
|
||||
|
||||
float[] mTempStartValues = new float[9];
|
||||
|
||||
float[] mTempEndValues = new float[9];
|
||||
|
||||
Matrix mTempMatrix = new Matrix();
|
||||
|
||||
@Override
|
||||
public Matrix evaluate(float fraction, Matrix startValue, Matrix endValue) {
|
||||
startValue.getValues(mTempStartValues);
|
||||
endValue.getValues(mTempEndValues);
|
||||
for (int i = 0; i < 9; i++) {
|
||||
float diff = mTempEndValues[i] - mTempStartValues[i];
|
||||
mTempEndValues[i] = mTempStartValues[i] + (fraction * diff);
|
||||
}
|
||||
mTempMatrix.setValues(mTempEndValues);
|
||||
return mTempMatrix;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -228,6 +228,10 @@ public class ShapedImageView extends ImageView {
|
|||
|
||||
}
|
||||
|
||||
public int[] getBorderColors() {
|
||||
return mBorderColors;
|
||||
}
|
||||
|
||||
@ShapeStyle
|
||||
public int getStyle() {
|
||||
return mStyle;
|
||||
|
|
|
@ -23,7 +23,9 @@
|
|||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
tools:layout_height="160dp"
|
||||
tools:layout_width="280dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/account_profile_banner"
|
||||
|
@ -33,7 +35,8 @@
|
|||
android:layout_alignTop="@id/profile_container"
|
||||
android:alpha="0.5"
|
||||
android:contentDescription="@string/profile_banner"
|
||||
android:scaleType="centerCrop"/>
|
||||
android:scaleType="centerCrop"
|
||||
tools:src="@drawable/nyan_stars_background"/>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/profile_container"
|
||||
|
@ -58,7 +61,7 @@
|
|||
android:layout_marginTop="@dimen/element_spacing_mlarge"
|
||||
app:sivBorder="true"
|
||||
app:sivBorderWidth="2dp"
|
||||
tools:src="@drawable/profile_image_nyan_sakamoto"/>
|
||||
tools:src="@mipmap/ic_launcher"/>
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/other_accounts_list"
|
||||
|
@ -76,7 +79,8 @@
|
|||
android:layout_alignParentBottom="true"
|
||||
android:layout_below="@id/profile_image"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
android:orientation="horizontal"
|
||||
android:baselineAligned="false">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
|
@ -117,6 +121,14 @@
|
|||
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/floating_profile_image_snapshot"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:scaleType="fitCenter"
|
||||
android:visibility="invisible"
|
||||
tools:ignore="ContentDescription"/>
|
||||
</FrameLayout>
|
||||
|
||||
</RelativeLayout>
|
Loading…
Reference in New Issue