added round rect profile image (not completed yet)

bug fixes
use crc32 checksum of official keys to check official API availability
This commit is contained in:
Mariotaku Lee 2014-12-15 19:21:15 +08:00
parent 97b8487c56
commit a54790312a
51 changed files with 672 additions and 478 deletions

View File

@ -621,7 +621,6 @@ public class HomeActivity extends BaseSupportActivity implements OnClickListener
protected void onResume() {
super.onResume();
sendBroadcast(new Intent(BROADCAST_HOME_ACTIVITY_ONRESUME));
mViewPager.setEnabled(!mPreferences.getBoolean(KEY_DISABLE_TAB_SWIPE, false));
invalidateOptionsMenu();
updateActionsButtonStyle();
updateActionsButton();
@ -661,13 +660,6 @@ public class HomeActivity extends BaseSupportActivity implements OnClickListener
super.onStop();
}
protected void setPagingEnabled(final boolean enabled) {
if (mTabIndicator != null && mViewPager != null) {
mViewPager.setEnabled(!mPreferences.getBoolean(KEY_DISABLE_TAB_SWIPE, false));
mTabIndicator.setEnabled(enabled);
}
}
@Override
protected boolean shouldSetWindowBackground() {
return false;

View File

@ -48,13 +48,13 @@ import static org.mariotaku.twidere.util.Utils.configBaseCardAdapter;
import static org.mariotaku.twidere.util.Utils.getAccountColor;
import static org.mariotaku.twidere.util.Utils.openUserProfile;
public class DirectMessageConversationEntriesAdapter extends BaseCursorAdapter implements IBaseCardAdapter,
public class DirectMessageEntriesAdapter extends BaseCursorAdapter implements IBaseCardAdapter,
OnClickListener {
private final ImageLoaderWrapper mImageLoader;
private final MultiSelectManager mMultiSelectManager;
public DirectMessageConversationEntriesAdapter(final Context context) {
public DirectMessageEntriesAdapter(final Context context) {
super(context, R.layout.list_item_message_entry, null, new String[0], new int[0], 0);
final TwidereApplication app = TwidereApplication.getInstance(context);
mMultiSelectManager = app.getMultiSelectManager();
@ -88,6 +88,7 @@ public class DirectMessageConversationEntriesAdapter extends BaseCursorAdapter i
final String nick = getUserNickname(context, conversationId);
holder.name.setText(TextUtils.isEmpty(nick) ? name : isNicknameOnly() ? nick : context.getString(
R.string.name_with_nickname, name, nick));
holder.screen_name.setText("@" + screenName);
holder.text.setText(toPlainText(cursor.getString(IDX_TEXT)));
holder.time.setTime(timestamp);
holder.setIsOutgoing(isOutgoing);

View File

@ -0,0 +1,168 @@
/*
* 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.adapter;
import android.content.Context;
import android.database.Cursor;
import android.text.Html;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ImageView.ScaleType;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.iface.IDirectMessagesAdapter;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.model.ParcelableDirectMessage;
import org.mariotaku.twidere.util.ImageLoaderWrapper;
import org.mariotaku.twidere.util.ImageLoadingHandler;
import org.mariotaku.twidere.util.MultiSelectManager;
import org.mariotaku.twidere.view.holder.DirectMessageConversationViewHolder;
import java.util.Locale;
import static org.mariotaku.twidere.util.Utils.configBaseCardAdapter;
import static org.mariotaku.twidere.util.Utils.findDirectMessageInDatabases;
import static org.mariotaku.twidere.util.Utils.formatToLongTimeString;
import static org.mariotaku.twidere.util.Utils.openImage;
public class DirectMessagesListAdapter extends BaseCursorAdapter implements IDirectMessagesAdapter,
OnClickListener {
private ScaleType mImagePreviewScaleType;
private final ImageLoaderWrapper mImageLoader;
private final Context mContext;
private final MultiSelectManager mMultiSelectManager;
private final ImageLoadingHandler mImageLoadingHandler;
private ParcelableDirectMessage.CursorIndices mIndices;
public DirectMessagesListAdapter(final Context context) {
super(context, R.layout.card_item_message_conversation, null, new String[0], new int[0], 0);
mContext = context;
final TwidereApplication app = TwidereApplication.getInstance(context);
mMultiSelectManager = app.getMultiSelectManager();
mImageLoader = app.getImageLoaderWrapper();
mImageLoadingHandler = new ImageLoadingHandler(R.id.media_preview_progress);
configBaseCardAdapter(context, this);
}
@Override
public void bindView(final View view, final Context context, final Cursor cursor) {
final int position = cursor.getPosition();
final DirectMessageConversationViewHolder holder = (DirectMessageConversationViewHolder) view.getTag();
final String firstMedia = cursor.getString(mIndices.first_media);
final long accountId = cursor.getLong(mIndices.account_id);
final long timestamp = cursor.getLong(mIndices.message_timestamp);
final boolean is_outgoing = cursor.getInt(mIndices.is_outgoing) == 1;
holder.setOutgoing(is_outgoing);
holder.setTextSize(getTextSize());
holder.text.setText(Html.fromHtml(cursor.getString(mIndices.text)));
getLinkify().applyAllLinks(holder.text, accountId, false);
holder.text.setMovementMethod(null);
holder.time.setText(formatToLongTimeString(mContext, timestamp));
if (firstMedia == null) {
mImageLoader.cancelDisplayTask(holder.media_preview);
holder.media_preview_container.setVisibility(View.GONE);
} else {
mImageLoader.cancelDisplayTask(holder.media_preview);
holder.media_preview_container.setVisibility(View.VISIBLE);
if (mImagePreviewScaleType != null) {
holder.media_preview.setScaleType(mImagePreviewScaleType);
}
if (!firstMedia.equals(mImageLoadingHandler.getLoadingUri(holder.media_preview))) {
holder.media_preview.setBackgroundResource(0);
mImageLoader.displayPreviewImageWithCredentials(holder.media_preview, firstMedia,
accountId, mImageLoadingHandler);
}
holder.media_preview.setTag(position);
}
super.bindView(view, context, cursor);
}
@Override
public ParcelableDirectMessage findItem(final long id) {
for (int i = 0, count = getCount(); i < count; i++) {
if (getItemId(i) == id) return getDirectMessage(i);
}
return null;
}
public ParcelableDirectMessage getDirectMessage(final int position) {
final Cursor c = getCursor();
if (c == null || c.isClosed()) return null;
c.moveToPosition(position);
final long account_id = c.getLong(mIndices.account_id);
final long message_id = c.getLong(mIndices.message_id);
return findDirectMessageInDatabases(mContext, account_id, message_id);
}
@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 DirectMessageConversationViewHolder)) {
final DirectMessageConversationViewHolder holder = new DirectMessageConversationViewHolder(view);
holder.media_preview.setOnClickListener(this);
view.setTag(holder);
}
return view;
}
@Override
public void onClick(final View view) {
if (mMultiSelectManager.isActive()) return;
final Object tag = view.getTag();
final int position = tag instanceof Integer ? (Integer) tag : -1;
if (position == -1) return;
switch (view.getId()) {
case R.id.media_preview: {
final ParcelableDirectMessage message = getDirectMessage(position);
if (message == null || message.first_media == null) return;
openImage(mContext, message.account_id, message.first_media, false);
}
}
}
@Override
public void setDisplayImagePreview(final boolean display) {
// Images in DM are always enabled
}
@Override
public void setImagePreviewScaleType(final String scaleTypeString) {
final ScaleType scaleType = ScaleType.valueOf(scaleTypeString.toUpperCase(Locale.US));
mImagePreviewScaleType = scaleType;
}
@Override
public Cursor swapCursor(final Cursor cursor) {
if (cursor != null) {
mIndices = new ParcelableDirectMessage.CursorIndices(cursor);
} else {
mIndices = null;
}
return super.swapCursor(cursor);
}
}

View File

@ -229,8 +229,6 @@ public interface SharedPreferenceConstants {
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = true)
public static final String KEY_PRELOAD_WIFI_ONLY = "preload_wifi_only";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = true)
public static final String KEY_DISABLE_TAB_SWIPE = "disable_tab_swipe";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = true)
public static final String KEY_LINK_TO_QUOTED_TWEET = "link_to_quoted_tweet";
@Preference(type = BOOLEAN)
public static final String KEY_BACKGROUND_TOAST_NOTIFICATION = "background_toast_notification";
@ -270,8 +268,6 @@ public interface SharedPreferenceConstants {
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false)
public static final String KEY_COMPACT_CARDS = "compact_cards";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false)
public static final String KEY_LONG_CLICK_TO_OPEN_MENU = "long_click_to_open_menu";
@Preference(type = BOOLEAN, hasDefault = true, defaultBoolean = false)
public static final String KEY_FORCE_USING_PRIVATE_APIS = "force_using_private_apis";
@Preference(type = STRING, hasDefault = true, defaultString = "140")
public static final String KEY_STATUS_TEXT_LIMIT = "status_text_limit";

View File

@ -41,7 +41,7 @@ import org.mariotaku.querybuilder.Columns.Column;
import org.mariotaku.querybuilder.Expression;
import org.mariotaku.querybuilder.RawItemArray;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.DirectMessageConversationEntriesAdapter;
import org.mariotaku.twidere.adapter.DirectMessageEntriesAdapter;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.provider.TweetStore.Accounts;
import org.mariotaku.twidere.provider.TweetStore.DirectMessages;
@ -74,7 +74,7 @@ public class DirectMessagesFragment extends BasePullToRefreshListFragment implem
private boolean mLoadMoreAutomatically;
private DirectMessageConversationEntriesAdapter mAdapter;
private DirectMessageEntriesAdapter mAdapter;
private int mFirstVisibleItem;
private final LongSparseArray<Set<Long>> mUnreadCountsToRemove = new LongSparseArray<>();
@ -84,8 +84,8 @@ public class DirectMessagesFragment extends BasePullToRefreshListFragment implem
private RemoveUnreadCountsTask mRemoveUnreadCountsTask;
@Override
public DirectMessageConversationEntriesAdapter getListAdapter() {
return (DirectMessageConversationEntriesAdapter) super.getListAdapter();
public DirectMessageEntriesAdapter getListAdapter() {
return (DirectMessageEntriesAdapter) super.getListAdapter();
}
public final LongSparseArray<Set<Long>> getUnreadCountsToRemove() {
@ -97,7 +97,7 @@ public class DirectMessagesFragment extends BasePullToRefreshListFragment implem
mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
super.onActivityCreated(savedInstanceState);
mMultiSelectManager = getMultiSelectManager();
mAdapter = new DirectMessageConversationEntriesAdapter(getActivity());
mAdapter = new DirectMessageEntriesAdapter(getActivity());
setListAdapter(mAdapter);
mListView = getListView();
mListView.setDivider(null);
@ -337,7 +337,7 @@ public class DirectMessagesFragment extends BasePullToRefreshListFragment implem
static class RemoveUnreadCountsTask extends TwidereAsyncTask<Void, Void, Void> {
private final Set<Integer> read_positions;
private final DirectMessageConversationEntriesAdapter adapter;
private final DirectMessageEntriesAdapter adapter;
private final DirectMessagesFragment fragment;
RemoveUnreadCountsTask(final Set<Integer> read_positions, final DirectMessagesFragment fragment) {

View File

@ -83,7 +83,7 @@ import org.mariotaku.twidere.util.OnLinkClickHandler;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.TwidereLinkify;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.CircularImageView;
import org.mariotaku.twidere.view.ProfileImageView;
import org.mariotaku.twidere.view.StatusTextView;
import org.mariotaku.twidere.view.TwidereMenuBar;
import org.mariotaku.twidere.view.holder.LoadIndicatorViewHolder;
@ -657,7 +657,7 @@ public class StatusFragment extends BaseSupportFragment
private final TwidereMenuBar menuBar;
private final TextView nameView, screenNameView;
private final StatusTextView textView;
private final CircularImageView profileImageView;
private final ProfileImageView profileImageView;
private final ImageView profileTypeView;
private final TextView timeSourceView;
private final TextView replyRetweetStatusView;
@ -679,7 +679,7 @@ public class StatusFragment extends BaseSupportFragment
nameView = (TextView) itemView.findViewById(R.id.name);
screenNameView = (TextView) itemView.findViewById(R.id.screen_name);
textView = (StatusTextView) itemView.findViewById(R.id.text);
profileImageView = (CircularImageView) itemView.findViewById(R.id.profile_image);
profileImageView = (ProfileImageView) itemView.findViewById(R.id.profile_image);
profileTypeView = (ImageView) itemView.findViewById(R.id.profile_type);
timeSourceView = (TextView) itemView.findViewById(R.id.time_source);
replyRetweetStatusView = (TextView) itemView.findViewById(R.id.reply_retweet_status);

View File

@ -22,8 +22,6 @@ public class StatusMenuDialogFragment extends MenuDialogFragment {
final Bundle args = getArguments();
final ParcelableStatus status = args.getParcelable(EXTRA_STATUS);
setMenuForStatus(getThemedContext(), menu, status);
final boolean longclickToOpenMenu = prefs.getBoolean(KEY_LONG_CLICK_TO_OPEN_MENU, false);
Utils.setMenuItemAvailability(menu, MENU_MULTI_SELECT, longclickToOpenMenu);
}
}

View File

@ -94,7 +94,6 @@ import org.mariotaku.twidere.loader.support.ParcelableUserLoader;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.ParcelableUserList;
import org.mariotaku.twidere.model.SingleResponse;
import org.mariotaku.twidere.provider.TweetStore.Accounts;
import org.mariotaku.twidere.provider.TweetStore.CachedUsers;
import org.mariotaku.twidere.provider.TweetStore.Filters;
import org.mariotaku.twidere.text.TextAlphaSpan;
@ -111,10 +110,10 @@ import org.mariotaku.twidere.util.menu.TwidereMenuInfo;
import org.mariotaku.twidere.util.message.FriendshipUpdatedEvent;
import org.mariotaku.twidere.util.message.ProfileUpdatedEvent;
import org.mariotaku.twidere.util.message.TaskStateChangedEvent;
import org.mariotaku.twidere.view.CircularImageView;
import org.mariotaku.twidere.view.HeaderDrawerLayout;
import org.mariotaku.twidere.view.HeaderDrawerLayout.DrawerCallback;
import org.mariotaku.twidere.view.ProfileBannerImageView;
import org.mariotaku.twidere.view.ProfileImageView;
import org.mariotaku.twidere.view.TabPagerIndicator;
import org.mariotaku.twidere.view.TintedStatusFrameLayout;
import org.mariotaku.twidere.view.iface.IColorLabelView;
@ -143,7 +142,6 @@ import static org.mariotaku.twidere.util.Utils.getLocalizedNumber;
import static org.mariotaku.twidere.util.Utils.getOriginalTwitterProfileImage;
import static org.mariotaku.twidere.util.Utils.getTwitterInstance;
import static org.mariotaku.twidere.util.Utils.getUserTypeIconRes;
import static org.mariotaku.twidere.util.Utils.isMyAccount;
import static org.mariotaku.twidere.util.Utils.openImage;
import static org.mariotaku.twidere.util.Utils.openStatus;
import static org.mariotaku.twidere.util.Utils.openTweetSearch;
@ -168,7 +166,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
private ImageLoaderWrapper mProfileImageLoader;
private CircularImageView mProfileImageView;
private ProfileImageView mProfileImageView;
private ImageView mProfileTypeView;
private ProfileBannerImageView mProfileBannerView;
private TextView mNameView, mScreenNameView, mDescriptionView, mLocationView, mURLView, mCreatedAtView,
@ -214,11 +212,13 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
}
private void updateRefreshState() {
final ParcelableUser user = mUser;
if (user == null) return;
final AsyncTwitterWrapper twitter = getTwitterWrapper();
final boolean is_creating_friendship = twitter != null
&& twitter.isCreatingFriendship(mUser.account_id, mUser.id);
&& twitter.isCreatingFriendship(user.account_id, user.id);
final boolean is_destroying_friendship = twitter != null
&& twitter.isDestroyingFriendship(mUser.account_id, mUser.id);
&& twitter.isDestroyingFriendship(user.account_id, user.id);
setProgressBarIndeterminateVisibility(is_creating_friendship || is_destroying_friendship);
invalidateOptionsMenu();
}
@ -361,7 +361,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
mProgressContainer.setVisibility(View.GONE);
mUser = user;
final int userColor = getUserColor(activity, user.id, true);
mProfileImageView.setBorderColor(userColor);
mProfileImageView.setBorderColor(userColor != 0 ? userColor : Color.WHITE);
mProfileNameContainer.drawEnd(getAccountColor(activity, user.account_id));
final String nick = getUserNickname(activity, user.id, true);
mNameView
@ -408,16 +408,6 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
final int defWidth = res.getDisplayMetrics().widthPixels;
final int width = mBannerWidth > 0 ? mBannerWidth : defWidth;
mProfileImageLoader.displayProfileBanner(mProfileBannerView, user.profile_banner_url, width);
if (isMyAccount(activity, user.id)) {
final ContentResolver resolver = getContentResolver();
final ContentValues values = new ContentValues();
values.put(Accounts.NAME, user.name);
values.put(Accounts.SCREEN_NAME, user.screen_name);
values.put(Accounts.PROFILE_IMAGE_URL, user.profile_image_url);
values.put(Accounts.PROFILE_BANNER_URL, user.profile_banner_url);
final String where = Accounts.ACCOUNT_ID + " = " + user.id;
resolver.update(Accounts.CONTENT_URI, values, where, null);
}
mUuckyFooter.setVisibility(isUucky(user.id, user.screen_name, user) ? View.VISIBLE : View.GONE);
final Relationship relationship = mRelationship;
if (relationship == null || relationship.getTargetUserId() != user.id) {
@ -518,11 +508,6 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
final LoaderManager lm = getLoaderManager();
lm.destroyLoader(LOADER_ID_USER);
lm.destroyLoader(LOADER_ID_FRIENDSHIP);
if (!isMyAccount(getActivity(), accountId)) {
mCardContent.setVisibility(View.GONE);
mErrorRetryContainer.setVisibility(View.GONE);
return;
}
final Bundle args = new Bundle();
args.putLong(EXTRA_ACCOUNT_ID, accountId);
args.putLong(EXTRA_USER_ID, userId);
@ -537,7 +522,6 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
if (accountId == -1 || userId == -1 && screenName == null) {
mCardContent.setVisibility(View.GONE);
mErrorRetryContainer.setVisibility(View.GONE);
return;
}
}
@ -853,7 +837,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
mFriendsContainer = headerView.findViewById(R.id.friends_container);
mFriendsCount = (TextView) headerView.findViewById(R.id.friends_count);
mProfileNameContainer = (IColorLabelView) headerView.findViewById(R.id.profile_name_container);
mProfileImageView = (CircularImageView) headerView.findViewById(R.id.profile_image);
mProfileImageView = (ProfileImageView) headerView.findViewById(R.id.profile_image);
mProfileTypeView = (ImageView) headerView.findViewById(R.id.profile_type);
mDescriptionContainer = headerView.findViewById(R.id.description_container);
mLocationContainer = headerView.findViewById(R.id.location_container);

View File

@ -28,8 +28,6 @@ public class UserListMenuDialogFragment extends MenuDialogFragment {
extensionsExtras.putParcelable(EXTRA_USER_LIST, user);
extensionsIntent.putExtras(extensionsExtras);
addIntentToMenu(getThemedContext(), menu, extensionsIntent);
final boolean longClickToOpenMenu = prefs.getBoolean(KEY_LONG_CLICK_TO_OPEN_MENU, false);
Utils.setMenuItemAvailability(menu, MENU_MULTI_SELECT, longClickToOpenMenu);
}
protected void onPrepareItemMenu(final Menu menu, final ParcelableUserList userList) {

View File

@ -26,8 +26,6 @@ public class UserMenuDialogFragment extends MenuDialogFragment {
extensionsExtras.putParcelable(EXTRA_USER, user);
extensionsIntent.putExtras(extensionsExtras);
addIntentToMenu(getThemedContext(), menu, extensionsIntent);
final boolean longclickToOpenMenu = prefs.getBoolean(KEY_LONG_CLICK_TO_OPEN_MENU, false);
Utils.setMenuItemAvailability(menu, MENU_MULTI_SELECT, longclickToOpenMenu);
}
protected void onPrepareItemMenu(final Menu menu, final ParcelableUser user) {

View File

@ -30,6 +30,7 @@ import org.mariotaku.querybuilder.Expression;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.model.ParcelableUser;
import org.mariotaku.twidere.model.SingleResponse;
import org.mariotaku.twidere.provider.TweetStore.Accounts;
import org.mariotaku.twidere.provider.TweetStore.CachedUsers;
import org.mariotaku.twidere.util.TwitterWrapper;
@ -39,32 +40,33 @@ import twitter4j.User;
import static org.mariotaku.twidere.util.ContentValuesCreator.makeCachedUserContentValues;
import static org.mariotaku.twidere.util.Utils.getTwitterInstance;
import static org.mariotaku.twidere.util.Utils.isMyAccount;
public final class ParcelableUserLoader extends AsyncTaskLoader<SingleResponse<ParcelableUser>> implements Constants {
private final ContentResolver resolver;
private final boolean omit_intent_extra, load_from_cache;
private final Bundle extras;
private final long account_id, user_id;
private final String screen_name;
private final boolean mOmitIntentExtra, mLoadFromCache;
private final Bundle mExtras;
private final long mAccountId, mUserId;
private final String mScreenName;
public ParcelableUserLoader(final Context context, final long account_id, final long user_id,
final String screen_name, final Bundle extras, final boolean omit_intent_extra,
final boolean load_from_cache) {
public ParcelableUserLoader(final Context context, final long accountId, final long userId,
final String screenName, final Bundle extras, final boolean omitIntentExtra,
final boolean loadFromCache) {
super(context);
resolver = context.getContentResolver();
this.omit_intent_extra = omit_intent_extra;
this.load_from_cache = load_from_cache;
this.extras = extras;
this.account_id = account_id;
this.user_id = user_id;
this.screen_name = screen_name;
this.mOmitIntentExtra = omitIntentExtra;
this.mLoadFromCache = loadFromCache;
this.mExtras = extras;
this.mAccountId = accountId;
this.mUserId = userId;
this.mScreenName = screenName;
}
@Override
public SingleResponse<ParcelableUser> loadInBackground() {
if (!omit_intent_extra && extras != null) {
final ParcelableUser user = extras.getParcelable(EXTRA_USER);
final Context context = getContext();
final ContentResolver resolver = context.getContentResolver();
if (!mOmitIntentExtra && mExtras != null) {
final ParcelableUser user = mExtras.getParcelable(EXTRA_USER);
if (user != null) {
final ContentValues values = ParcelableUser.makeCachedUserContentValues(user);
resolver.delete(CachedUsers.CONTENT_URI, CachedUsers.USER_ID + " = " + user.id, null);
@ -72,30 +74,41 @@ public final class ParcelableUserLoader extends AsyncTaskLoader<SingleResponse<P
return SingleResponse.getInstance(user);
}
}
final Twitter twitter = getTwitterInstance(getContext(), account_id, true);
final Twitter twitter = getTwitterInstance(context, mAccountId, true);
if (twitter == null) return SingleResponse.getInstance();
if (load_from_cache) {
final String where = CachedUsers.USER_ID + " = " + user_id + " OR " + CachedUsers.SCREEN_NAME + " = '"
+ screen_name + "'";
if (mLoadFromCache) {
final String where = CachedUsers.USER_ID + " = " + mUserId + " OR " + CachedUsers.SCREEN_NAME + " = '"
+ mScreenName + "'";
final Cursor cur = resolver.query(CachedUsers.CONTENT_URI, CachedUsers.COLUMNS, where, null, null);
final int count = cur.getCount();
try {
if (count > 0) {
cur.moveToFirst();
return new SingleResponse<>(new ParcelableUser(cur, account_id), null);
return SingleResponse.getInstance(new ParcelableUser(cur, mAccountId));
}
} finally {
cur.close();
}
}
try {
final User user = TwitterWrapper.tryShowUser(twitter, user_id, screen_name);
final User user = TwitterWrapper.tryShowUser(twitter, mUserId, mScreenName);
if (user == null) return SingleResponse.getInstance();
final ContentValues values = makeCachedUserContentValues(user);
final String where = Expression.equals(CachedUsers.USER_ID, user.getId()).getSQL();
resolver.delete(CachedUsers.CONTENT_URI, where, null);
resolver.insert(CachedUsers.CONTENT_URI, values);
return SingleResponse.getInstance(new ParcelableUser(user, account_id));
final ContentValues cachedUserValues = makeCachedUserContentValues(user);
final long userId = user.getId();
final String cachedUserWhere = Expression.equals(CachedUsers.USER_ID, userId).getSQL();
resolver.delete(CachedUsers.CONTENT_URI, cachedUserWhere, null);
resolver.insert(CachedUsers.CONTENT_URI, cachedUserValues);
final ParcelableUser result = new ParcelableUser(user, mAccountId);
if (isMyAccount(context, userId)) {
final ContentValues accountValues = new ContentValues();
accountValues.put(Accounts.NAME, result.name);
accountValues.put(Accounts.SCREEN_NAME, result.screen_name);
accountValues.put(Accounts.PROFILE_IMAGE_URL, result.profile_image_url);
accountValues.put(Accounts.PROFILE_BANNER_URL, result.profile_banner_url);
final String accountWhere = Expression.equals(Accounts.ACCOUNT_ID, userId).getSQL();
resolver.update(Accounts.CONTENT_URI, accountValues, accountWhere, null);
}
return SingleResponse.getInstance(result);
} catch (final TwitterException e) {
return SingleResponse.getInstance(e);
}

View File

@ -1,88 +0,0 @@
/*
* 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.model;
import static android.text.TextUtils.isEmpty;
import android.content.Context;
import android.content.res.Resources;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.util.ArrayUtils;
public class ConsumerKeySecret {
public final String name, consumer_key, consumer_secret;
private ConsumerKeySecret(final String consumer_key, final String consumer_secret) {
this("API", consumer_key, consumer_secret);
}
private ConsumerKeySecret(final String name, final String consumer_key, final String consumer_secret) {
this.name = name;
this.consumer_key = consumer_secret;
this.consumer_secret = consumer_secret;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (!(obj instanceof ConsumerKeySecret)) return false;
final ConsumerKeySecret other = (ConsumerKeySecret) obj;
if (consumer_key == null) {
if (other.consumer_key != null) return false;
} else if (!consumer_key.equals(other.consumer_key)) return false;
if (consumer_secret == null) {
if (other.consumer_secret != null) return false;
} else if (!consumer_secret.equals(other.consumer_secret)) return false;
return true;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (consumer_key == null ? 0 : consumer_key.hashCode());
result = prime * result + (consumer_secret == null ? 0 : consumer_secret.hashCode());
return result;
}
public static ConsumerKeySecret[] getAllOffcialKeys(final Context context) {
if (context == null) return new ConsumerKeySecret[0];
final Resources res = context.getResources();
final String[] entries = res.getStringArray(R.array.entries_official_consumer_key_secret);
final String[] values = res.getStringArray(R.array.values_official_consumer_key_secret);
final int length = entries.length;
final ConsumerKeySecret[] keys = new ConsumerKeySecret[length];
for (int i = 0; i < length; i++) {
final String[] key_secret = values[i].split(";");
final String consumer_key = key_secret[0], consumer_secret = key_secret[1];
keys[i] = new ConsumerKeySecret(entries[i], consumer_key, consumer_secret);
}
return keys;
}
public static boolean isOfficial(final Context context, final String consumer_key, final String consumer_secret) {
if (context == null || isEmpty(consumer_key) || isEmpty(consumer_secret)) return false;
final ConsumerKeySecret[] keys = getAllOffcialKeys(context);
return ArrayUtils.contains(keys, new ConsumerKeySecret(consumer_key, consumer_secret));
}
}

View File

@ -679,6 +679,7 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
final Context context = getContext();
final Resources resources = context.getResources();
final NotificationCompat.Builder notifBuilder = new NotificationCompat.Builder(context);
notifBuilder.setCategory(NotificationCompat.CATEGORY_SOCIAL);
final ParcelableDirectMessage firstItem = messages.get(0);
final int messagesCount = messages.size();
final Intent deleteIntent = new Intent(BROADCAST_NOTIFICATION_DELETED);

View File

@ -204,6 +204,7 @@ import java.net.Proxy;
import java.net.SocketAddress;
import java.net.URL;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
@ -213,6 +214,8 @@ import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.CRC32;
import java.util.zip.Checksum;
import javax.net.ssl.SSLException;
@ -2577,16 +2580,19 @@ public final class Utils implements Constants, TwitterConstants {
final Cursor cur = ContentResolverUtils.query(context.getContentResolver(), Accounts.CONTENT_URI,
Accounts.COLUMNS, null, null, null);
if (cur == null) return false;
final String[] keySecrets = context.getResources().getStringArray(R.array.values_official_consumer_key_secret);
final String[] keySecrets = context.getResources().getStringArray(R.array.values_official_consumer_secret_crc32);
final ParcelableAccount.Indices indices = new ParcelableAccount.Indices(cur);
cur.moveToFirst();
final CRC32 crc32 = new CRC32();
try {
while (!cur.isAfterLast()) {
final String consumerKey = cur.getString(indices.consumer_key);
final String consumerSecret = cur.getString(indices.consumer_secret);
final byte[] consumerSecretBytes = consumerSecret.getBytes(Charset.forName("UTF-8"));
crc32.update(consumerSecretBytes, 0, consumerSecretBytes.length);
final long value = crc32.getValue();
crc32.reset();
for (final String keySecret : keySecrets) {
final String[] pair = keySecret.split(";");
if (pair[0].equals(consumerKey) && pair[1].equals(consumerSecret)) return true;
if (Long.parseLong(keySecret, 16) == value) return true;
}
cur.moveToNext();
}
@ -2796,10 +2802,14 @@ public final class Utils implements Constants, TwitterConstants {
public static boolean isOfficialConsumerKeySecret(final Context context, final String consumerKey,
final String consumerSecret) {
if (context == null || consumerKey == null || consumerSecret == null) return false;
final String[] keySecrets = context.getResources().getStringArray(R.array.values_official_consumer_key_secret);
final String[] keySecrets = context.getResources().getStringArray(R.array.values_official_consumer_secret_crc32);
final CRC32 crc32 = new CRC32();
final byte[] consumerSecretBytes = consumerSecret.getBytes(Charset.forName("UTF-8"));
crc32.update(consumerSecretBytes, 0, consumerSecretBytes.length);
final long value = crc32.getValue();
crc32.reset();
for (final String keySecret : keySecrets) {
final String[] pair = keySecret.split(";");
if (pair[0].equals(consumerKey) && pair[1].equals(consumerSecret)) return true;
if (Long.parseLong(keySecret, 16) == value) return true;
}
return false;
}

View File

@ -53,7 +53,10 @@ import org.mariotaku.twidere.R;
* An ImageView class with a circle mask so that all images are drawn in a
* circle instead of a square.
*/
public class CircularImageView extends ImageView {
public class ProfileImageView extends ImageView {
public static final int STYLE_CIRCLE = 0x1;
public static final int STYLE_RECTANGLE = 0x2;
private static final int SHADOW_START_COLOR = 0x37000000;
@ -63,6 +66,7 @@ public class CircularImageView extends ImageView {
private final Matrix mMatrix;
private final RectF mSource;
private final RectF mDestination;
private final RectF mTempDestination;
private final Paint mBitmapPaint;
private final Paint mBorderPaint;
@ -71,46 +75,53 @@ public class CircularImageView extends ImageView {
private float mShadowRadius;
private Drawable mBackground;
public CircularImageView(Context context) {
private int mStyle;
private float mCornerRadius, mCornerRadiusRatio;
public ProfileImageView(Context context) {
this(context, null, 0);
}
public CircularImageView(Context context, AttributeSet attrs) {
public ProfileImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircularImageView(Context context, AttributeSet attrs, int defStyle) {
public ProfileImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircularImageView, defStyle, 0);
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ProfileImageView, defStyle, 0);
mMatrix = new Matrix();
mSource = new RectF();
mDestination = new RectF();
mTempDestination = new RectF();
mBitmapPaint = new Paint(Paint.LINEAR_TEXT_FLAG);
mBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBitmapPaint.setFilterBitmap(true);
mBitmapPaint.setDither(true);
mBorderPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mBorderPaint.setStyle(Paint.Style.STROKE);
if (a.hasValue(R.styleable.CircularImageView_civBorder)) {
setBorderEnabled(a.getBoolean(R.styleable.CircularImageView_civBorder, false));
} else if (a.hasValue(R.styleable.CircularImageView_civBorderColor)
|| a.hasValue(R.styleable.CircularImageView_civBorderWidth)) {
if (a.hasValue(R.styleable.ProfileImageView_pivBorder)) {
setBorderEnabled(a.getBoolean(R.styleable.ProfileImageView_pivBorder, false));
} else if (a.hasValue(R.styleable.ProfileImageView_pivBorderColor)
|| a.hasValue(R.styleable.ProfileImageView_pivBorderWidth)) {
setBorderEnabled(true);
}
setBorderColor(a.getColor(R.styleable.CircularImageView_civBorderColor, Color.TRANSPARENT));
setBorderWidth(a.getDimensionPixelSize(R.styleable.CircularImageView_civBorderWidth, 0));
setBorderColor(a.getColor(R.styleable.ProfileImageView_pivBorderColor, Color.TRANSPARENT));
setBorderWidth(a.getDimensionPixelSize(R.styleable.ProfileImageView_pivBorderWidth, 0));
setStyle(a.getInt(R.styleable.ProfileImageView_pivStyle, STYLE_RECTANGLE));
setCornerRadius(a.getDimension(R.styleable.ProfileImageView_pivCornerRadius, 0));
setCornerRadiusRatio(a.getFraction(R.styleable.ProfileImageView_pivCornerRadiusRatio, 1, 1, -1));
if (USE_OUTLINE) {
if (a.hasValue(R.styleable.CircularImageView_civElevation)) {
if (a.hasValue(R.styleable.ProfileImageView_pivElevation)) {
ViewCompat.setElevation(this,
a.getDimensionPixelSize(R.styleable.CircularImageView_civElevation, 0));
a.getDimensionPixelSize(R.styleable.ProfileImageView_pivElevation, 0));
}
} else {
mShadowRadius = a.getDimensionPixelSize(R.styleable.CircularImageView_civElevation, 0);
mShadowRadius = a.getDimensionPixelSize(R.styleable.ProfileImageView_pivElevation, 0);
}
a.recycle();
@ -120,14 +131,75 @@ public class CircularImageView extends ImageView {
}
}
public void setBorderWidth(int width) {
mBorderPaint.setStrokeWidth(width);
invalidate();
public void setCornerRadiusRatio(float ratio) {
mCornerRadiusRatio = ratio;
}
public void setBorderEnabled(boolean enabled) {
mBorderEnabled = enabled;
invalidate();
/**
* Given the source bitmap and a canvas, draws the bitmap through a circular
* mask. Only draws a circle with diameter equal to the destination width.
*
* @param bitmap The source bitmap to draw.
* @param canvas The canvas to draw it on.
* @param source The source bound of the bitmap.
* @param dest The destination bound on the canvas.
*/
public void drawBitmapWithCircleOnCanvas(Bitmap bitmap, Canvas canvas,
RectF source, RectF dest) {
// Draw bitmap through shader first.
BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP,
Shader.TileMode.CLAMP);
mMatrix.reset();
switch (getScaleType()) {
case CENTER_CROP: {
final float srcRatio = source.width() / source.height();
final float dstRatio = dest.width() / dest.height();
if (srcRatio > dstRatio) {
// Source is wider than destination, fit height
mTempDestination.top = dest.top;
mTempDestination.bottom = dest.bottom;
final float dstWidth = dest.height() * srcRatio;
mTempDestination.left = dest.centerX() - dstWidth / 2;
mTempDestination.right = dest.centerX() + dstWidth / 2;
} else if (srcRatio < dstRatio) {
mTempDestination.left = dest.left;
mTempDestination.right = dest.right;
final float dstHeight = dest.width() / srcRatio;
mTempDestination.top = dest.centerY() - dstHeight / 2;
mTempDestination.bottom = dest.centerY() + dstHeight / 2;
} else {
mTempDestination.set(dest);
}
break;
}
default: {
mTempDestination.set(dest);
break;
}
}
// Fit bitmap to bounds.
mMatrix.setRectToRect(source, mTempDestination, ScaleToFit.CENTER);
shader.setLocalMatrix(mMatrix);
mBitmapPaint.setShader(shader);
if (getStyle() == STYLE_CIRCLE) {
canvas.drawCircle(dest.centerX(), dest.centerY(), Math.min(dest.width(), dest.height()) / 2f,
mBitmapPaint);
} else {
final float cornerRadius = getCalculatedCornerRadius();
canvas.drawRoundRect(dest, cornerRadius, cornerRadius, mBitmapPaint);
}
}
public int getStyle() {
return mStyle;
}
public void setStyle(int style) {
mStyle = style;
}
public void setBorderColor(int color) {
@ -136,103 +208,14 @@ public class CircularImageView extends ImageView {
invalidate();
}
private void initOutlineProvider() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
setClipToOutline(true);
setOutlineProvider(new CircularOutlineProvider());
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
updateShadowBitmap();
updateBackgroundPadding();
}
@Override
public void setPadding(int left, int top, int right, int bottom) {
super.setPadding(left, top, right, bottom);
updateShadowBitmap();
updateBackgroundPadding();
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
public void setPaddingRelative(int start, int top, int end, int bottom) {
super.setPaddingRelative(start, top, end, bottom);
updateShadowBitmap();
updateBackgroundPadding();
}
private void updateShadowBitmap() {
if (USE_OUTLINE) return;
final int width = getWidth(), height = getHeight();
if (width <= 0 || height <= 0) return;
final int contentLeft = getPaddingLeft(), contentTop = getPaddingTop(),
contentRight = width - getPaddingRight(),
contentBottom = height - getPaddingBottom();
final int contentWidth = contentRight - contentLeft,
contentHeight = contentBottom - contentTop;
final float radius = mShadowRadius, dy = radius * 1.5f / 2;
final int size = Math.round(Math.min(contentWidth, contentHeight) + radius * 2);
mShadowBitmap = Bitmap.createBitmap(size, Math.round(size + dy), Config.ARGB_8888);
Canvas canvas = new Canvas(mShadowBitmap);
final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.WHITE);
paint.setShadowLayer(radius, 0, radius * 1.5f / 2, SHADOW_START_COLOR);
final RectF rect = new RectF(radius, radius, size - radius, size - radius);
canvas.drawOval(rect, paint);
paint.setShadowLayer(0, 0, 0, 0);
paint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
canvas.drawOval(rect, paint);
public void setBorderEnabled(boolean enabled) {
mBorderEnabled = enabled;
invalidate();
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
}
@Override
public void setBackgroundDrawable(Drawable background) {
if (OUTLINE_DRAW) {
super.setBackgroundDrawable(background);
return;
}
super.setBackgroundDrawable(null);
mBackground = background;
updateBackgroundPadding();
}
private void updateBackgroundPadding() {
final Drawable drawable = mBackground;
if (drawable == null) return;
final int width = getWidth(), height = getHeight();
if (width <= 0 || height <= 0) return;
final int contentLeft = getPaddingLeft(), contentTop = getPaddingTop(),
contentRight = width - getPaddingRight(),
contentBottom = height - getPaddingBottom();
final int contentWidth = contentRight - contentLeft,
contentHeight = contentBottom - contentTop;
final int size = Math.min(contentWidth, contentHeight);
drawable.setBounds(contentLeft + (contentWidth - size) / 2,
contentTop + (contentHeight - size) / 2,
contentRight - (contentWidth - size) / 2,
contentBottom - (contentHeight - size) / 2);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public void setBackground(Drawable background) {
if (OUTLINE_DRAW) {
super.setBackground(background);
return;
}
super.setBackground(null);
mBackground = background;
updateBackgroundPadding();
public void setBorderWidth(int width) {
mBorderPaint.setStrokeWidth(width);
invalidate();
}
@Override
@ -284,8 +267,13 @@ public class CircularImageView extends ImageView {
// Then draw the border.
if (mBorderEnabled) {
canvas.drawCircle(mDestination.centerX(), mDestination.centerY(),
mDestination.width() / 2f - mBorderPaint.getStrokeWidth() / 2, mBorderPaint);
if (getStyle() == STYLE_CIRCLE) {
canvas.drawCircle(mDestination.centerX(), mDestination.centerY(),
mDestination.width() / 2f - mBorderPaint.getStrokeWidth() / 2, mBorderPaint);
} else {
final float radius = getCalculatedCornerRadius();
canvas.drawRoundRect(mDestination, radius, radius, mBorderPaint);
}
}
}
@ -298,61 +286,111 @@ public class CircularImageView extends ImageView {
mBitmapPaint.setColorFilter(cf);
}
/**
* Given the source bitmap and a canvas, draws the bitmap through a circular
* mask. Only draws a circle with diameter equal to the destination width.
*
* @param bitmap The source bitmap to draw.
* @param canvas The canvas to draw it on.
* @param source The source bound of the bitmap.
* @param dest The destination bound on the canvas.
*/
public void drawBitmapWithCircleOnCanvas(Bitmap bitmap, Canvas canvas,
RectF source, RectF dest) {
// Draw bitmap through shader first.
BitmapShader shader = new BitmapShader(bitmap, Shader.TileMode.CLAMP,
Shader.TileMode.CLAMP);
mMatrix.reset();
switch (getScaleType()) {
case CENTER_CROP: {
final float srcRatio = source.width() / source.height();
final float dstRatio = dest.width() / dest.height();
if (srcRatio > dstRatio) {
// Source is wider than destination, fit height
tempDest.top = dest.top;
tempDest.bottom = dest.bottom;
final float dstWidth = dest.height() * srcRatio;
tempDest.left = dest.centerX() - dstWidth / 2;
tempDest.right = dest.centerX() + dstWidth / 2;
} else if (srcRatio < dstRatio) {
tempDest.left = dest.left;
tempDest.right = dest.right;
final float dstHeight = dest.width() / srcRatio;
tempDest.top = dest.centerY() - dstHeight / 2;
tempDest.bottom = dest.centerY() + dstHeight / 2;
} else {
tempDest.set(dest);
}
break;
}
default: {
tempDest.set(dest);
break;
}
}
// Fit bitmap to bounds.
mMatrix.setRectToRect(source, tempDest, ScaleToFit.CENTER);
shader.setLocalMatrix(mMatrix);
mBitmapPaint.setShader(shader);
canvas.drawCircle(dest.centerX(), dest.centerY(), Math.min(dest.width(), dest.height()) / 2f,
mBitmapPaint);
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
updateShadowBitmap();
updateBackgroundPadding();
}
private RectF tempDest = new RectF();
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public void setBackground(Drawable background) {
if (OUTLINE_DRAW) {
super.setBackground(background);
return;
}
super.setBackground(null);
mBackground = background;
updateBackgroundPadding();
}
@Override
public void setBackgroundDrawable(Drawable background) {
if (OUTLINE_DRAW) {
super.setBackgroundDrawable(background);
return;
}
super.setBackgroundDrawable(null);
mBackground = background;
updateBackgroundPadding();
}
@Override
public void setPadding(int left, int top, int right, int bottom) {
super.setPadding(left, top, right, bottom);
updateShadowBitmap();
updateBackgroundPadding();
}
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
@Override
public void setPaddingRelative(int start, int top, int end, int bottom) {
super.setPaddingRelative(start, top, end, bottom);
updateShadowBitmap();
updateBackgroundPadding();
}
private float getCornerRadius() {
return mCornerRadius;
}
public void setCornerRadius(float radius) {
mCornerRadius = radius;
}
private void initOutlineProvider() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
setClipToOutline(true);
setOutlineProvider(new CircularOutlineProvider());
}
}
private void updateBackgroundPadding() {
final Drawable drawable = mBackground;
if (drawable == null) return;
final int width = getWidth(), height = getHeight();
if (width <= 0 || height <= 0) return;
final int contentLeft = getPaddingLeft(), contentTop = getPaddingTop(),
contentRight = width - getPaddingRight(),
contentBottom = height - getPaddingBottom();
final int contentWidth = contentRight - contentLeft,
contentHeight = contentBottom - contentTop;
final int size = Math.min(contentWidth, contentHeight);
drawable.setBounds(contentLeft + (contentWidth - size) / 2,
contentTop + (contentHeight - size) / 2,
contentRight - (contentWidth - size) / 2,
contentBottom - (contentHeight - size) / 2);
}
private void updateShadowBitmap() {
if (USE_OUTLINE) return;
final int width = getWidth(), height = getHeight();
if (width <= 0 || height <= 0) return;
final int contentLeft = getPaddingLeft(), contentTop = getPaddingTop(),
contentRight = width - getPaddingRight(),
contentBottom = height - getPaddingBottom();
final int contentWidth = contentRight - contentLeft,
contentHeight = contentBottom - contentTop;
final float radius = mShadowRadius, dy = radius * 1.5f / 2;
final int size = Math.round(Math.min(contentWidth, contentHeight) + radius * 2);
mShadowBitmap = Bitmap.createBitmap(size, Math.round(size + dy), Config.ARGB_8888);
Canvas canvas = new Canvas(mShadowBitmap);
final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setColor(Color.WHITE);
paint.setShadowLayer(radius, 0, radius * 1.5f / 2, SHADOW_START_COLOR);
final RectF rect = new RectF(radius, radius, size - radius, size - radius);
canvas.drawOval(rect, paint);
paint.setShadowLayer(0, 0, 0, 0);
paint.setXfermode(new PorterDuffXfermode(Mode.CLEAR));
canvas.drawOval(rect, paint);
invalidate();
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
private static class CircularOutlineProvider extends ViewOutlineProvider {
@ -361,13 +399,28 @@ public class CircularImageView extends ImageView {
final int contentLeft = view.getPaddingLeft(), contentTop = view.getPaddingTop(),
contentRight = view.getWidth() - view.getPaddingRight(),
contentBottom = view.getHeight() - view.getPaddingBottom();
final int contentWidth = contentRight - contentLeft,
contentHeight = contentBottom - contentTop;
final int size = Math.min(contentWidth, contentHeight);
outline.setOval(contentLeft + (contentWidth - size) / 2,
contentTop + (contentHeight - size) / 2,
contentRight - (contentWidth - size) / 2,
contentBottom - (contentHeight - size) / 2);
final ProfileImageView imageView = (ProfileImageView) view;
if (imageView.getStyle() == STYLE_CIRCLE) {
final int contentWidth = contentRight - contentLeft,
contentHeight = contentBottom - contentTop;
final int size = Math.min(contentWidth, contentHeight);
outline.setOval(contentLeft + (contentWidth - size) / 2,
contentTop + (contentHeight - size) / 2,
contentRight - (contentWidth - size) / 2,
contentBottom - (contentHeight - size) / 2);
} else {
final float radius = imageView.getCalculatedCornerRadius();
outline.setRoundRect(contentLeft, contentTop, contentRight, contentBottom, radius);
}
}
}
private float getCalculatedCornerRadius() {
if (mCornerRadiusRatio > 0) {
return Math.min(getWidth(), getHeight()) * mCornerRadiusRatio;
} else if (mCornerRadius > 0) {
return mCornerRadius;
}
return 0;
}
}

View File

@ -22,9 +22,8 @@ package org.mariotaku.twidere.view;
import android.content.Context;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.ImageView;
public class SquareCircularImageView extends CircularImageView {
public class SquareCircularImageView extends ProfileImageView {
public SquareCircularImageView(final Context context) {
this(context, null);

View File

@ -31,7 +31,7 @@ import org.mariotaku.twidere.view.ShortTimeView;
public class DirectMessageEntryViewHolder extends ListViewHolder {
public final ImageView profile_image;
public final TextView name, text;
public final TextView name, screen_name, text;
public final ShortTimeView time;
private float text_size;
private boolean account_color_enabled;
@ -42,6 +42,7 @@ public class DirectMessageEntryViewHolder extends ListViewHolder {
final Context context = view.getContext();
profile_image = (ImageView) findViewById(R.id.profile_image);
name = (TextView) findViewById(R.id.name);
screen_name = (TextView) findViewById(R.id.screen_name);
text = (TextView) findViewById(R.id.text);
time = (ShortTimeView) findViewById(R.id.time);
is_rtl = Utils.isRTL(context);
@ -70,6 +71,8 @@ public class DirectMessageEntryViewHolder extends ListViewHolder {
public void setTextSize(final float text_size) {
if (this.text_size == text_size) return;
this.text_size = text_size;
text.setTextSize(text_size);
name.setTextSize(text_size);
}
public void setUserColor(final int color) {

View File

@ -21,7 +21,7 @@ import org.mariotaku.twidere.util.ImageLoaderWrapper;
import org.mariotaku.twidere.util.ImageLoadingHandler;
import org.mariotaku.twidere.util.UserColorNicknameUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.CircularImageView;
import org.mariotaku.twidere.view.ProfileImageView;
import org.mariotaku.twidere.view.ShortTimeView;
import java.util.Locale;
@ -38,7 +38,7 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements OnClick
private final IStatusesAdapter<?> adapter;
private final ImageView retweetProfileImageView;
private final CircularImageView profileImageView;
private final ProfileImageView profileImageView;
private final ImageView profileTypeView;
private final ImageView mediaPreviewView;
private final TextView textView;
@ -56,7 +56,7 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements OnClick
public StatusViewHolder(IStatusesAdapter<?> adapter, View itemView) {
super(itemView);
this.adapter = adapter;
profileImageView = (CircularImageView) itemView.findViewById(R.id.profile_image);
profileImageView = (ProfileImageView) itemView.findViewById(R.id.profile_image);
profileTypeView = (ImageView) itemView.findViewById(R.id.profile_type);
textView = (TextView) itemView.findViewById(R.id.text);
nameView = (TextView) itemView.findViewById(R.id.name);
@ -310,7 +310,7 @@ public class StatusViewHolder extends RecyclerView.ViewHolder implements OnClick
return (CardView) itemView.findViewById(R.id.card);
}
public CircularImageView getProfileImageView() {
public ProfileImageView getProfileImageView() {
return profileImageView;
}

View File

@ -24,8 +24,9 @@
android:layout_height="match_parent"
android:padding="@dimen/element_spacing_small">
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
android:id="@android:id/icon"
style="?profileImageStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

View File

@ -24,8 +24,9 @@
android:layout_height="match_parent"
android:layout_margin="@dimen/element_spacing_msmall">
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
android:id="@android:id/icon"
style="?profileImageStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"/>

View File

@ -42,7 +42,7 @@
android:layout_height="wrap_content"
android:padding="@dimen/element_spacing_small">
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
android:id="@+id/media_profile_image"
android:layout_width="@dimen/element_size_small"
android:layout_height="@dimen/element_size_small"/>

View File

@ -21,7 +21,7 @@
android:paddingRight="@dimen/element_spacing_large"
android:paddingTop="@dimen/element_spacing_normal">
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
style="?profileImageStyle"
android:id="@+id/profile_image"
android:layout_width="@dimen/icon_size_card_list_item"
@ -77,7 +77,7 @@
android:textColor="?android:attr/textColorSecondary"/>
</LinearLayout>
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
style="?profileImageStyle"
android:id="@+id/my_profile_image"
android:layout_width="@dimen/icon_size_card_list_item"

View File

@ -14,7 +14,7 @@
android:layout_height="wrap_content"
android:padding="@dimen/element_spacing_normal">
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
style="?profileImageStyle"
android:id="@+id/profile_image"
android:layout_width="@dimen/icon_size_card_list_item"
@ -25,7 +25,7 @@
android:contentDescription="@string/profile_image"
android:scaleType="fitCenter"/>
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
style="?profileImageStyle"
android:id="@+id/my_profile_image"
android:layout_width="@dimen/icon_size_card_list_item"
@ -156,7 +156,7 @@
android:orientation="horizontal"
android:paddingTop="@dimen/element_spacing_small">
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
style="?profileImageStyle"
android:id="@+id/activity_profile_image_1"
android:layout_width="@dimen/profile_image_size_activity_small"
@ -165,7 +165,7 @@
android:contentDescription="@string/profile_image"
android:scaleType="fitCenter"/>
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
style="?profileImageStyle"
android:id="@+id/activity_profile_image_2"
android:layout_width="@dimen/profile_image_size_activity_small"
@ -174,7 +174,7 @@
android:contentDescription="@string/profile_image"
android:scaleType="fitCenter"/>
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
style="?profileImageStyle"
android:id="@+id/activity_profile_image_3"
android:layout_width="@dimen/profile_image_size_activity_small"
@ -183,7 +183,7 @@
android:contentDescription="@string/profile_image"
android:scaleType="fitCenter"/>
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
style="?profileImageStyle"
android:id="@+id/activity_profile_image_4"
android:layout_width="@dimen/profile_image_size_activity_small"
@ -192,7 +192,7 @@
android:contentDescription="@string/profile_image"
android:scaleType="fitCenter"/>
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
style="?profileImageStyle"
android:id="@+id/activity_profile_image_5"
android:layout_width="@dimen/profile_image_size_activity_small"

View File

@ -30,8 +30,9 @@
android:background="?android:selectableItemBackground"
android:orientation="vertical">
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
android:id="@+id/retweet_profile_image"
style="?profileImageStyle"
android:layout_width="@dimen/element_size_small"
android:layout_height="@dimen/element_size_small"
android:layout_marginBottom="@dimen/element_spacing_small"
@ -64,7 +65,7 @@
android:layout_marginTop="@dimen/element_spacing_normal"
android:paddingLeft="@dimen/element_spacing_mlarge">
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
android:id="@+id/profile_image"
style="?profileImageStyle"
android:layout_width="@dimen/icon_size_status_profile_image"

View File

@ -11,8 +11,9 @@
android:paddingRight="@dimen/element_spacing_normal"
android:paddingTop="@dimen/element_spacing_normal">
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
android:id="@+id/retweet_profile_image"
style="?profileImageStyle"
android:layout_width="@dimen/element_size_small"
android:layout_height="@dimen/element_size_small"
android:layout_marginLeft="@dimen/element_spacing_normal"
@ -33,8 +34,9 @@
android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="10sp"/>
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
android:id="@+id/profile_image"
style="?profileImageStyle"
android:layout_width="@dimen/icon_size_status_profile_image"
android:layout_height="@dimen/icon_size_status_profile_image"
android:layout_alignLeft="@id/retweet_profile_image"

View File

@ -21,7 +21,7 @@
android:paddingRight="@dimen/element_spacing_xlarge"
android:paddingTop="@dimen/element_spacing_normal">
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
android:id="@+id/profile_image"
android:layout_width="@dimen/icon_size_card_list_item"
android:layout_height="@dimen/icon_size_card_list_item"

View File

@ -19,7 +19,7 @@
android:paddingRight="@dimen/item_menu_card_padding_compact"
android:paddingTop="@dimen/element_spacing_normal">
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
android:id="@+id/profile_image"
android:layout_width="@dimen/icon_size_card_list_item"
android:layout_height="@dimen/icon_size_card_list_item"

View File

@ -23,7 +23,7 @@
android:paddingRight="@dimen/element_spacing_xlarge"
android:paddingTop="@dimen/element_spacing_normal">
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
android:id="@+id/profile_image"
style="?profileImageStyle"
android:layout_width="@dimen/icon_size_card_list_item"

View File

@ -19,7 +19,7 @@
android:paddingRight="@dimen/item_menu_card_padding_compact"
android:paddingTop="@dimen/element_spacing_normal">
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
style="?profileImageStyle"
android:id="@+id/profile_image"
android:layout_width="@dimen/icon_size_card_list_item"

View File

@ -28,10 +28,11 @@
android:paddingRight="@dimen/element_spacing_large"
android:paddingTop="@dimen/element_spacing_normal">
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
android:id="@+id/profile_image"
android:layout_width="@dimen/icon_size_profile_image_dashboard_current"
android:layout_height="@dimen/icon_size_profile_image_dashboard_current"
style="?profileImageStyle"
android:layout_marginBottom="@dimen/element_spacing_mlarge"
android:layout_marginTop="@dimen/element_spacing_mlarge"/>

View File

@ -43,8 +43,9 @@
android:padding="@dimen/element_spacing_small"
app:ignorePadding="true">
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
android:id="@+id/profile_image"
style="?profileImageStyle"
android:layout_width="@dimen/element_size_mlarge"
android:layout_height="@dimen/element_size_mlarge"
android:layout_alignParentLeft="true"
@ -52,8 +53,8 @@
android:layout_margin="@dimen/padding_profile_image_detail_page"
android:contentDescription="@string/profile_image"
android:scaleType="centerCrop"
app:civBorder="true"
app:civBorderWidth="1dp"/>
app:pivBorder="true"
app:pivBorderWidth="1dp"/>
<ImageView
android:id="@+id/profile_type"

View File

@ -328,7 +328,7 @@
</android.support.v7.widget.CardView>
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
android:id="@+id/profile_image"
style="?profileImageStyleLarge"
android:layout_width="@dimen/icon_size_user_profile"

View File

@ -33,7 +33,7 @@
android:padding="@dimen/element_spacing_normal"
app:ignorePadding="true">
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
android:id="@+id/profile_image"
android:layout_width="@dimen/icon_size_card_details"
android:layout_height="@dimen/icon_size_card_details"

View File

@ -36,7 +36,7 @@
android:layout_weight="0"
android:background="@drawable/list_drag_handle"/>
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
android:id="@android:id/icon"
style="?profileImageStyle"
android:layout_width="@dimen/icon_size_list_item"

View File

@ -19,7 +19,7 @@
android:orientation="horizontal"
android:padding="@dimen/element_spacing_small">
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
android:id="@+id/profile_image"
style="?profileImageStyle"
android:layout_width="@dimen/icon_size_list_item_small"

View File

@ -8,7 +8,7 @@
android:orientation="horizontal"
tools:context=".adapter.DirectMessagesEntryAdapter">
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
android:id="@+id/profile_image"
style="?profileImageStyle"
android:layout_width="@dimen/icon_size_card_list_item"
@ -21,26 +21,45 @@
<org.mariotaku.twidere.view.BottomDividerFrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginRight="@dimen/element_spacing_normal"
android:layout_toRightOf="@id/profile_image"
android:divider="?android:dividerVertical"
android:gravity="center_vertical"
android:minHeight="?android:listPreferredItemHeight"
android:orientation="vertical">
android:orientation="vertical"
android:paddingBottom="@dimen/element_spacing_large"
android:paddingRight="@dimen/element_spacing_normal"
android:paddingTop="@dimen/element_spacing_large">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical">
<org.mariotaku.twidere.view.HandleSpanClickTextView
android:id="@+id/name"
android:layout_width="0dp"
<LinearLayout
android:id="@+id/name_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="@id/time"
android:singleLine="true"
android:textColor="?android:attr/textColorPrimary"/>
android:orientation="horizontal">
<org.mariotaku.twidere.view.HandleSpanClickTextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textColor="?android:attr/textColorPrimary"/>
<org.mariotaku.twidere.view.HandleSpanClickTextView
android:id="@+id/screen_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/element_spacing_small"
android:singleLine="true"
android:textColor="?android:attr/textColorPrimary"/>
</LinearLayout>
<org.mariotaku.twidere.view.ShortTimeView
android:id="@+id/time"
@ -56,9 +75,9 @@
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@id/name"
android:layout_below="@id/name"
android:layout_marginTop="@dimen/element_spacing_small"
android:layout_alignLeft="@id/name_container"
android:layout_below="@id/name_container"
android:layout_marginTop="@dimen/element_spacing_xsmall"
android:singleLine="true"
android:textColor="?android:attr/textColorSecondary"/>
</RelativeLayout>

View File

@ -27,7 +27,7 @@
android:orientation="horizontal"
android:padding="@dimen/element_spacing_small">
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
android:id="@android:id/icon"
android:layout_width="@dimen/icon_size_list_item_small"
android:layout_height="@dimen/icon_size_list_item_small"

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
android:id="@+id/color"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/element_size_small"

View File

@ -26,7 +26,7 @@
tools:layout_height="?android:actionBarSize"
android:padding="@dimen/element_spacing_small">
<org.mariotaku.twidere.view.CircularImageView
<org.mariotaku.twidere.view.ProfileImageView
android:id="@android:id/icon"
android:layout_width="@dimen/icon_size_list_item_small"
android:layout_height="@dimen/icon_size_list_item_small"

View File

@ -19,7 +19,8 @@
-->
<transitionSet
xmlns:android="http://schemas.android.com/apk/res/android">
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="@android:integer/config_shortAnimTime">
<changeBounds>
<targets>
<target android:targetId="@id/profile_image"/>

View File

@ -11,14 +11,14 @@
<style name="Widget.ProfileImage.Large">
<item name="android:background">@drawable/bg_oval_white</item>
<item name="civElevation">@dimen/elevation_card</item>
<item name="civBorderWidth">2dp</item>
<item name="pivElevation">@dimen/elevation_card</item>
<item name="pivBorderWidth">2dp</item>
</style>
<style name="Widget.Light.ProfileImage.Large">
<item name="android:background">@drawable/bg_oval_white</item>
<item name="civElevation">@dimen/elevation_card</item>
<item name="civBorderWidth">2dp</item>
<item name="pivElevation">@dimen/elevation_card</item>
<item name="pivBorderWidth">2dp</item>
</style>
<style name="Widget.ProfileType" parent="Widget.Base">

View File

@ -20,16 +20,39 @@
<resources>
<style name="Theme.Base" parent="android:Theme.Material"/>
<style name="Theme.Base" parent="android:Theme.Material">
<item name="android:colorPrimary">@color/material_light_blue</item>
<item name="android:colorPrimaryDark">@color/material_light_blue_700</item>
<item name="android:colorAccent">@color/material_light_blue_a200</item>
</style>
<style name="Theme.Base.NoActionBar" parent="android:Theme.Material.NoActionBar"/>
<style name="Theme.Base.NoActionBar" parent="android:Theme.Material.NoActionBar">
<item name="android:colorPrimary">@color/material_light_blue</item>
<item name="android:colorPrimaryDark">@color/material_light_blue_700</item>
<item name="android:colorAccent">@color/material_light_blue_a200</item>
</style>
<style name="Theme.Base.Dialog" parent="android:Theme.Material.Dialog"/>
<style name="Theme.Base.Dialog" parent="android:Theme.Material.Dialog">
<item name="android:colorPrimary">@color/material_light_blue</item>
<item name="android:colorPrimaryDark">@color/material_light_blue_700</item>
<item name="android:colorAccent">@color/material_light_blue_a200</item>
</style>
<style name="Theme.Base.Light" parent="android:Theme.Material.Light"/>
<style name="Theme.Base.Light" parent="android:Theme.Material.Light">
<item name="android:colorPrimary">@color/material_light_blue</item>
<item name="android:colorPrimaryDark">@color/material_light_blue_700</item>
<item name="android:colorAccent">@color/material_light_blue_a200</item>
</style>
<style name="Theme.Base.Light.DarkActionBar" parent="android:Theme.Material.Light.DarkActionBar"/>
<style name="Theme.Base.Light.Dialog" parent="android:Theme.Material.Light.Dialog"/>
<style name="Theme.Base.Light.DarkActionBar" parent="android:Theme.Material.Light.DarkActionBar">
<item name="android:colorPrimary">@color/material_light_blue</item>
<item name="android:colorPrimaryDark">@color/material_light_blue_700</item>
<item name="android:colorAccent">@color/material_light_blue_a200</item>
</style>
<style name="Theme.Base.Light.Dialog" parent="android:Theme.Material.Light.Dialog">
<item name="android:colorPrimary">@color/material_light_blue</item>
<item name="android:colorPrimaryDark">@color/material_light_blue_700</item>
<item name="android:colorAccent">@color/material_light_blue_a200</item>
</style>
</resources>

View File

@ -51,21 +51,20 @@
<item>save</item>
<item>discard</item>
</string-array>
<string-array name="entries_official_consumer_key_secret">
<item>Twitter for Android</item>
<item>Twitter for iPhone</item>
<item>Twitter for iPad</item>
<item>Twitter for Mac</item>
<item>Twitter for Windows Phone</item>
<item>Twitter for Google TV</item>
</string-array>
<string-array name="values_official_consumer_key_secret">
<item>3nVuSoBZnx6U4vzUxf5w;Bcs59EFbbsdF6Sl9Ng71smgStWEGwXXKSjYvPVt7qys</item>
<item>IQKbtAYlXLripLGPWd0HUA;GgDYlkSvaPxGxC4X8liwpUoqKwwr3lCADbz8A7ADU</item>
<item>CjulERsDeqhhjSme66ECg;IQWdVyqFxghAtURHGeGiWAsmCAGmdW3WmbEx6Hck</item>
<item>3rJOl1ODzm9yZy63FACdg;5jPoQ5kQvMJFDYRNE8bQ4rHuds4xJqhvgNJM4awaE8</item>
<item>yN3DUNVO0Me63IAQdhTfCA;c768oTKdzAjIYCmpSNIdZbGaG0t6rOhSFQP0S5uC79g</item>
<item>iAtYJ4HpUVfIUoNnif1DA;172fOpzuZoYzNYaU3mMYvE8m8MEyLbztOdbrUolU</item>
<!-- CRC32 checksum of consumer secret of official clients to check whether user is using official keys -->
<string-array name="values_official_consumer_secret_crc32">
<!--Twitter for Android-->
<item>6ce85096</item>
<!--Twitter for iPhone-->
<item>deffe9c7</item>
<!--Twitter for iPad-->
<item>9f00e0cb</item>
<!--Twitter for Mac-->
<item>df27640e</item>
<!--Twitter for Windows Phone-->
<item>62bd0d33</item>
<!--Twitter for Google TV-->
<item>56d8f9ff</item>
</string-array>
<string-array name="entries_theme">
<item>@string/theme_light</item>

View File

@ -66,11 +66,14 @@
<attr name="iabActivatedColor" format="color"/>
<attr name="iabDisabledColor" format="color"/>
</declare-styleable>
<declare-styleable name="CircularImageView">
<attr name="civBorder" format="boolean"/>
<attr name="civBorderWidth" format="dimension"/>
<attr name="civBorderColor" format="color"/>
<attr name="civElevation" format="dimension"/>
<declare-styleable name="ProfileImageView">
<attr name="pivBorder" format="boolean"/>
<attr name="pivBorderWidth" format="dimension"/>
<attr name="pivBorderColor" format="color"/>
<attr name="pivElevation" format="dimension"/>
<attr name="pivCornerRadius" format="dimension"/>
<attr name="pivCornerRadiusRatio" format="fraction"/>
<attr name="pivStyle"/>
</declare-styleable>
<declare-styleable name="HeaderDrawerLayout">
<attr name="headerLayout" format="reference"/>
@ -86,4 +89,8 @@
<flag name="label" value="0x1"/>
<flag name="icon" value="0x2"/>
</attr>
<attr name="pivStyle">
<enum name="circle" value="0x1"/>
<enum name="rectangle" value="0x2"/>
</attr>
</resources>

View File

@ -18,4 +18,8 @@
<color name="material_brown">#796648</color>
<color name="material_grey">#9E9E9E</color>
<color name="material_blue_grey">#607D8B</color>
<color name="material_light_blue_700">#0288D1</color>
<color name="material_light_blue_a200">#40C4FF</color>
</resources>

View File

@ -688,5 +688,7 @@
<string name="profile_background_color">Background color</string>
<string name="profile_link_color_main_color">Link color (main color)</string>
<string name="retweet_quote_confirm_title">Retweet to your followers?</string>
<string name="font">Font</string>
<string name="size">Size</string>
</resources>

View File

@ -115,12 +115,14 @@
<style name="Widget.ProfileImage" parent="Widget.Base">
<item name="android:scaleType">centerCrop</item>
<item name="civBorderWidth">1dp</item>
<item name="pivBorderWidth">1dp</item>
<item name="pivCornerRadiusRatio">10%p</item>
</style>
<style name="Widget.Light.ProfileImage" parent="Widget.Base">
<item name="android:scaleType">centerCrop</item>
<item name="civBorderWidth">1dp</item>
<item name="pivBorderWidth">1dp</item>
<item name="pivCornerRadiusRatio">10%p</item>
</style>
<style name="Widget.ProfileImage.Large">
@ -129,8 +131,8 @@
<item name="android:paddingLeft">2dp</item>
<item name="android:paddingRight">2dp</item>
<item name="android:paddingBottom">3dp</item>
<item name="civElevation">@dimen/elevation_card</item>
<item name="civBorderWidth">2dp</item>
<item name="pivElevation">@dimen/elevation_card</item>
<item name="pivBorderWidth">2dp</item>
</style>
<style name="Widget.Light.ProfileImage.Large">
@ -139,8 +141,8 @@
<item name="android:paddingLeft">2dp</item>
<item name="android:paddingRight">2dp</item>
<item name="android:paddingBottom">3dp</item>
<item name="civElevation">@dimen/elevation_card</item>
<item name="civBorderWidth">2dp</item>
<item name="pivElevation">@dimen/elevation_card</item>
<item name="pivBorderWidth">2dp</item>
</style>
<style name="Widget.ProfileType" parent="Widget.Base">

View File

@ -33,6 +33,7 @@
<!-- Card UI styles -->
<item name="cardActionButtonStyle">@style/Widget.CardActionButton</item>
<item name="profileImageStyle">@style/Widget.ProfileImage</item>
<item name="profileImageStyleLarge">@style/Widget.ProfileImage.Large</item>
<item name="cardItemBackgroundColor">#1a1a1a</item>
@ -59,6 +60,7 @@
<!-- Card UI styles -->
<item name="cardActionButtonStyle">@style/Widget.Light.CardActionButton</item>
<item name="profileImageStyle">@style/Widget.Light.ProfileImage</item>
<item name="profileImageStyleLarge">@style/Widget.Light.ProfileImage.Large</item>
<item name="cardItemBackgroundColor">#f8f8f8</item>
<!-- Twidere specific styles -->
@ -115,6 +117,7 @@
<!-- Card UI styles -->
<item name="cardActionButtonStyle">@style/Widget.CardActionButton</item>
<item name="profileImageStyle">@style/Widget.ProfileImage</item>
<item name="profileImageStyleLarge">@style/Widget.ProfileImage.Large</item>
<item name="cardItemBackgroundColor">#1a1a1a</item>
@ -131,6 +134,7 @@
<!-- Card UI styles -->
<item name="cardActionButtonStyle">@style/Widget.Light.CardActionButton</item>
<item name="profileImageStyle">@style/Widget.Light.ProfileImage</item>
<item name="profileImageStyleLarge">@style/Widget.Light.ProfileImage.Large</item>
<item name="cardItemBackgroundColor">#f8f8f8</item>
@ -178,6 +182,7 @@
<!-- Card UI styles -->
<item name="cardActionButtonStyle">@style/Widget.CardActionButton</item>
<item name="profileImageStyle">@style/Widget.ProfileImage</item>
<item name="profileImageStyleLarge">@style/Widget.ProfileImage.Large</item>
<item name="cardItemBackgroundColor">#1a1a1a</item>
@ -261,6 +266,7 @@
<!-- Card UI styles -->
<item name="cardActionButtonStyle">@style/Widget.CardActionButton</item>
<item name="profileImageStyle">@style/Widget.ProfileImage</item>
<item name="profileImageStyleLarge">@style/Widget.ProfileImage.Large</item>
<item name="cardItemBackgroundColor">#1a1a1a</item>
@ -283,6 +289,7 @@
<!-- Card UI styles -->
<item name="cardActionButtonStyle">@style/Widget.Light.CardActionButton</item>
<item name="profileImageStyle">@style/Widget.Light.ProfileImage</item>
<item name="profileImageStyleLarge">@style/Widget.Light.ProfileImage.Large</item>
<item name="cardItemBackgroundColor">#f8f8f8</item>
@ -305,6 +312,7 @@
<!-- Card UI styles -->
<item name="cardActionButtonStyle">@style/Widget.Light.CardActionButton</item>
<item name="profileImageStyle">@style/Widget.Light.ProfileImage</item>
<item name="profileImageStyleLarge">@style/Widget.Light.ProfileImage.Large</item>
<item name="cardItemBackgroundColor">#f8f8f8</item>

View File

@ -1,7 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:title="@string/cards">
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:title="@string/cards">
<PreferenceCategory
android:key="cat_card_preview"
@ -10,16 +11,6 @@
<org.mariotaku.twidere.preference.CardPreviewPreference android:key="card_preview"/>
</PreferenceCategory>
<org.mariotaku.twidere.preference.SeekBarDialogPreference
android:defaultValue="@integer/default_text_size"
android:key="text_size_int"
android:order="21"
android:summary="@string/text_size_summary"
android:title="@string/text_size"
app:max="24"
app:min="12"
app:progressTextSuffix="sp"/>
<org.mariotaku.twidere.preference.AutoFixCheckBoxPreference
android:defaultValue="true"
android:key="name_first"
@ -59,14 +50,14 @@
android:order="27"
android:title="@string/link_highlight_option"/>
<org.mariotaku.twidere.preference.AutoInvalidateListPreference
android:defaultValue="background"
android:entries="@array/entries_card_highlight_option"
android:entryValues="@array/values_card_highlight_option"
android:key="card_highlight_option"
android:order="28"
android:summary="%s"
android:title="@string/card_highlight_option"/>
<!--<org.mariotaku.twidere.preference.AutoInvalidateListPreference-->
<!--android:defaultValue="background"-->
<!--android:entries="@array/entries_card_highlight_option"-->
<!--android:entryValues="@array/values_card_highlight_option"-->
<!--android:key="card_highlight_option"-->
<!--android:order="28"-->
<!--android:summary="%s"-->
<!--android:title="@string/card_highlight_option"/>-->
<org.mariotaku.twidere.preference.AutoFixCheckBoxPreference
android:defaultValue="true"

View File

@ -1,7 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/settings_interface">
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:title="@string/settings_interface">
<PreferenceCategory android:title="@string/font">
<org.mariotaku.twidere.preference.ThemeFontFamilyPreference
android:defaultValue="sans-serif-light"
android:enabled="@bool/has_font_family"
android:key="theme_font_family"
android:title="@string/style"/>
<org.mariotaku.twidere.preference.SeekBarDialogPreference
android:defaultValue="@integer/default_text_size"
android:key="text_size_int"
android:summary="@string/text_size_summary"
android:title="@string/size"
app:max="24"
app:min="12"
app:progressTextSuffix="sp"/>
</PreferenceCategory>
<org.mariotaku.twidere.preference.AutoFixCheckBoxPreference
android:defaultValue="true"
android:key="unread_count"
@ -17,10 +37,6 @@
android:defaultValue="false"
android:key="fast_scroll_thumb"
android:title="@string/fast_scroll_thumb"/>
<org.mariotaku.twidere.preference.AutoFixCheckBoxPreference
android:defaultValue="false"
android:key="disable_tab_swipe"
android:title="@string/disable_tab_swipe"/>
<org.mariotaku.twidere.preference.AutoInvalidateListPreference
android:defaultValue="@string/default_tab_display_option"
@ -30,9 +46,4 @@
android:summary="%s"
android:title="@string/tab_display_option"/>
<org.mariotaku.twidere.preference.AutoFixCheckBoxPreference
android:defaultValue="false"
android:key="long_click_to_open_menu"
android:title="@string/long_click_to_open_menu"/>
</PreferenceScreen>

View File

@ -29,11 +29,5 @@
android:order="25"
android:title="@string/color"/>
<org.mariotaku.twidere.preference.ThemeFontFamilyPreference
android:defaultValue="sans-serif-light"
android:enabled="@bool/has_font_family"
android:key="theme_font_family"
android:order="26"
android:title="@string/font_family"/>
</PreferenceScreen>