implementing new tweets list

This commit is contained in:
Mariotaku Lee 2014-11-19 13:06:09 +08:00
parent b52ee59b76
commit ef2e93da4e
36 changed files with 1375 additions and 303 deletions

View File

@ -59,10 +59,12 @@ public class SettingsActivity extends BasePreferenceActivity {
private HeaderAdapter mAdapter;
private int mCurrentThemeColor, mCurrentThemeBackgroundAlpha;
private int mCurrentThemeColor, mThemeBackgroundAlpha;
private boolean mCompactCards, mPlainListStyle;
private String mCurrentThemeFontFamily;
private String mTheme;
private String mThemeFontFamily;
private String mThemeBackground;
@Override
public void finish() {
@ -150,8 +152,8 @@ public class SettingsActivity extends BasePreferenceActivity {
}
@Override
public void switchToHeader(final Header header) {
if (header == null || header.fragment == null && header.intent == null) return;
public void switchToHeader(@NonNull final Header header) {
if (header.fragment == null && header.intent == null) return;
super.switchToHeader(header);
}
@ -178,9 +180,11 @@ public class SettingsActivity extends BasePreferenceActivity {
mPreferences = getSharedPreferences(SHARED_PREFERENCES_NAME, MODE_PRIVATE);
mCompactCards = mPreferences.getBoolean(KEY_COMPACT_CARDS, false);
mPlainListStyle = mPreferences.getBoolean(KEY_PLAIN_LIST_STYLE, false);
mTheme = mPreferences.getString(KEY_THEME, DEFAULT_THEME);
mThemeBackground = mPreferences.getString(KEY_THEME_BACKGROUND, DEFAULT_THEME_BACKGROUND);
mThemeBackgroundAlpha = mPreferences.getInt(KEY_THEME_BACKGROUND_ALPHA, DEFAULT_THEME_BACKGROUND_ALPHA);
mThemeFontFamily = mPreferences.getString(KEY_THEME_FONT_FAMILY, DEFAULT_THEME_FONT_FAMILY);
mCurrentThemeColor = ThemeUtils.getUserAccentColor(this);
mCurrentThemeFontFamily = getThemeFontFamily();
mCurrentThemeBackgroundAlpha = getThemeBackgroundAlpha();
super.onCreate(savedInstanceState);
setIntent(getIntent().addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT));
final ActionBar actionBar = getActionBar();
@ -193,12 +197,13 @@ public class SettingsActivity extends BasePreferenceActivity {
}
private boolean shouldNotifyThemeChange() {
return mCompactCards != mPreferences.getBoolean(KEY_COMPACT_CARDS, false)
|| mPlainListStyle != mPreferences.getBoolean(KEY_PLAIN_LIST_STYLE, false)
|| getThemeResourceId() != getCurrentThemeResourceId()
|| ThemeUtils.getUserAccentColor(this) != mCurrentThemeColor
|| !CompareUtils.objectEquals(getThemeFontFamily(), mCurrentThemeFontFamily)
|| getThemeBackgroundAlpha() != mCurrentThemeBackgroundAlpha;
return !CompareUtils.objectEquals(mTheme, mPreferences.getString(KEY_THEME, DEFAULT_THEME))
|| !CompareUtils.objectEquals(mThemeFontFamily, mPreferences.getString(KEY_THEME_FONT_FAMILY, DEFAULT_THEME_FONT_FAMILY))
|| !CompareUtils.objectEquals(mThemeBackground, mPreferences.getString(KEY_THEME_BACKGROUND, DEFAULT_THEME_BACKGROUND))
|| mCurrentThemeColor != ThemeUtils.getUserAccentColor(this)
|| mThemeBackgroundAlpha != mPreferences.getInt(KEY_THEME_BACKGROUND_ALPHA, DEFAULT_THEME_BACKGROUND_ALPHA)
|| mCompactCards != mPreferences.getBoolean(KEY_COMPACT_CARDS, false)
|| mPlainListStyle != mPreferences.getBoolean(KEY_PLAIN_LIST_STYLE, false);
}
private static class HeaderAdapter extends ArrayAdapter<Header> {

View File

@ -274,8 +274,10 @@ public class BrowserSignInActivity extends BaseSupportDialogActivity implements
mActivity.setLoadProgressShown(false);
mActivity.setRequestToken(data);
if (data == null) {
Toast.makeText(mActivity, R.string.error_occurred, Toast.LENGTH_SHORT).show();
mActivity.finish();
if (!mActivity.isFinishing()) {
Toast.makeText(mActivity, R.string.error_occurred, Toast.LENGTH_SHORT).show();
mActivity.finish();
}
return;
}
mActivity.loadUrl(data.getAuthorizationURL());

View File

@ -1482,7 +1482,7 @@ public class ComposeActivity extends BaseSupportDialogActivity implements TextWa
final View view = super.getView(position, convertView, parent);
final ParcelableMediaUpdate media = getItem(position);
final ImageView image = (ImageView) view.findViewById(R.id.image);
mImageLoader.displayPreviewImage(image, media.uri);
mImageLoader.displayPreviewImage(media.uri, image);
return view;
}

View File

@ -32,7 +32,7 @@ import android.view.ViewGroup;
import android.widget.ImageView.ScaleType;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.iface.IStatusesAdapter;
import org.mariotaku.twidere.adapter.iface.IStatusesListAdapter;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.model.ParcelableMedia;
import org.mariotaku.twidere.model.ParcelableStatus;
@ -59,7 +59,7 @@ import static org.mariotaku.twidere.util.Utils.isFiltered;
import static org.mariotaku.twidere.util.Utils.openImage;
import static org.mariotaku.twidere.util.Utils.openUserProfile;
public class CursorStatusesAdapter extends BaseCursorAdapter implements IStatusesAdapter<Cursor>, OnClickListener,
public class CursorStatusesAdapter extends BaseCursorAdapter implements IStatusesListAdapter<Cursor>, OnClickListener,
OnOverflowIconClickListener {
public static final String[] CURSOR_COLS = Statuses.COLUMNS;

View File

@ -31,7 +31,7 @@ import android.view.ViewGroup;
import android.widget.ImageView.ScaleType;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.iface.IStatusesAdapter;
import org.mariotaku.twidere.adapter.iface.IStatusesListAdapter;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.ParcelableUserMention;
@ -58,7 +58,7 @@ import static org.mariotaku.twidere.util.Utils.openImage;
import static org.mariotaku.twidere.util.Utils.openUserProfile;
public class ParcelableStatusesAdapter extends BaseArrayAdapter<ParcelableStatus> implements
IStatusesAdapter<List<ParcelableStatus>>, OnClickListener, OnOverflowIconClickListener {
IStatusesListAdapter<List<ParcelableStatus>>, OnClickListener, OnOverflowIconClickListener {
private final Context mContext;
private final MultiSelectManager mMultiSelectManager;

View File

@ -0,0 +1,108 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.mariotaku.twidere.adapter.decorator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private static final int[] ATTRS = new int[]{
android.R.attr.listDivider
};
public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
private Drawable mDivider;
private int mOrientation;
public DividerItemDecoration(Context context, int orientation) {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
setOrientation(orientation);
}
public void setOrientation(int orientation) {
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
throw new IllegalArgumentException("invalid orientation");
}
mOrientation = orientation;
}
@Override
public void onDraw(Canvas c, RecyclerView parent) {
if (mOrientation == VERTICAL_LIST) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}
public void drawVertical(Canvas c, RecyclerView parent) {
final int left = parent.getPaddingLeft();
final int right = parent.getWidth() - parent.getPaddingRight();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int top = child.getBottom() + params.bottomMargin +
Math.round(ViewCompat.getTranslationY(child));
final int bottom = top + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
public void drawHorizontal(Canvas c, RecyclerView parent) {
final int top = parent.getPaddingTop();
final int bottom = parent.getHeight() - parent.getPaddingBottom();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int left = child.getRight() + params.rightMargin +
Math.round(ViewCompat.getTranslationX(child));
final int right = left + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
@Override
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
if (mOrientation == VERTICAL_LIST) {
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else {
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
}
}
}

View File

@ -1,67 +1,11 @@
/*
* 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.iface;
import org.mariotaku.twidere.model.ParcelableStatus;
public interface IStatusesAdapter<Data> extends IBaseCardAdapter {
public int findPositionByStatusId(final long statusId);
public long getAccountId(final int position);
public int getActualCount();
public ParcelableStatus getLastStatus();
public long getLastStatusId();
public ParcelableStatus getStatus(int position);
public long getStatusId(final int position);
public boolean isLastItemFiltered();
public void setCardHighlightOption(String option);
public void setData(Data data);
public void setDisplayImagePreview(boolean display);
public void setDisplaySensitiveContents(boolean display);
public void setFavoritesHightlightDisabled(boolean disable);
public void setFiltersEnabled(boolean enabled);
public void setGapDisallowed(boolean disallowed);
public void setHighlightKeyword(String... keywords);
public void setIgnoredFilterFields(final boolean user, final boolean textPlain, final boolean textHtml,
final boolean source, final boolean retweetedById);
public void setImagePreviewScaleType(String scaleType);
public void setIndicateMyStatusDisabled(boolean disable);
public void setMentionsHightlightDisabled(boolean disable);
/**
* Created by mariotaku on 14/11/18.
*/
public interface IStatusesAdapter {
public ParcelableStatus getStatus(int position);
}

View File

@ -0,0 +1,67 @@
/*
* 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.iface;
import org.mariotaku.twidere.model.ParcelableStatus;
public interface IStatusesListAdapter<Data> extends IBaseCardAdapter, IStatusesAdapter {
public int findPositionByStatusId(final long statusId);
public long getAccountId(final int position);
public int getActualCount();
public ParcelableStatus getLastStatus();
public long getLastStatusId();
public ParcelableStatus getStatus(int position);
public long getStatusId(final int position);
public boolean isLastItemFiltered();
public void setCardHighlightOption(String option);
public void setData(Data data);
public void setDisplayImagePreview(boolean display);
public void setDisplaySensitiveContents(boolean display);
public void setFavoritesHightlightDisabled(boolean disable);
public void setFiltersEnabled(boolean enabled);
public void setGapDisallowed(boolean disallowed);
public void setHighlightKeyword(String... keywords);
public void setIgnoredFilterFields(final boolean user, final boolean textPlain, final boolean textHtml,
final boolean source, final boolean retweetedById);
public void setImagePreviewScaleType(String scaleType);
public void setIndicateMyStatusDisabled(boolean disable);
public void setMentionsHightlightDisabled(boolean disable);
}

View File

@ -38,9 +38,8 @@ import android.widget.ImageView.ScaleType;
import android.widget.ListView;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.MainActivity;
import org.mariotaku.twidere.adapter.iface.IBaseCardAdapter.MenuButtonClickListener;
import org.mariotaku.twidere.adapter.iface.IStatusesAdapter;
import org.mariotaku.twidere.adapter.iface.IStatusesListAdapter;
import org.mariotaku.twidere.model.Account;
import org.mariotaku.twidere.model.Account.AccountWithCredentials;
import org.mariotaku.twidere.model.Panes;
@ -79,7 +78,7 @@ abstract class BaseStatusesListFragment<Data> extends BasePullToRefreshListFragm
private SharedPreferences mPreferences;
private ListView mListView;
private IStatusesAdapter<Data> mAdapter;
private IStatusesListAdapter<Data> mAdapter;
private Data mData;
private ParcelableStatus mSelectedStatus;
@ -108,7 +107,7 @@ abstract class BaseStatusesListFragment<Data> extends BasePullToRefreshListFragm
}
@Override
public IStatusesAdapter<Data> getListAdapter() {
public IStatusesListAdapter<Data> getListAdapter() {
return mAdapter;
}
@ -483,7 +482,7 @@ abstract class BaseStatusesListFragment<Data> extends BasePullToRefreshListFragm
protected abstract void loadMoreStatuses();
protected abstract IStatusesAdapter<Data> newAdapterInstance(boolean compact, boolean plain);
protected abstract IStatusesListAdapter<Data> newAdapterInstance(boolean compact, boolean plain);
@Override
protected void onReachedBottom() {
@ -571,7 +570,7 @@ abstract class BaseStatusesListFragment<Data> extends BasePullToRefreshListFragm
static class RemoveUnreadCountsTask<T> extends AsyncTask<Void, Void, Void> {
private final List<Integer> read_positions;
private final IStatusesAdapter<T> adapter;
private final IStatusesListAdapter<T> adapter;
private final BaseStatusesListFragment<T> fragment;
RemoveUnreadCountsTask(final List<Integer> read_positions, final BaseStatusesListFragment<T> fragment) {

View File

@ -50,7 +50,7 @@ import com.etsy.android.grid.StaggeredGridView;
import org.mariotaku.menucomponent.widget.PopupMenu;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.iface.IBaseCardAdapter.MenuButtonClickListener;
import org.mariotaku.twidere.adapter.iface.IStatusesAdapter;
import org.mariotaku.twidere.adapter.iface.IStatusesListAdapter;
import org.mariotaku.twidere.model.Panes;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.task.AsyncTask;
@ -79,7 +79,7 @@ abstract class BaseStatusesStaggeredGridFragment<Data> extends BasePullToRefresh
private SharedPreferences mPreferences;
private StaggeredGridView mListView;
private IStatusesAdapter<Data> mAdapter;
private IStatusesListAdapter<Data> mAdapter;
private PopupMenu mPopupMenu;
private Data mData;
@ -109,7 +109,7 @@ abstract class BaseStatusesStaggeredGridFragment<Data> extends BasePullToRefresh
}
@Override
public IStatusesAdapter<Data> getListAdapter() {
public IStatusesListAdapter<Data> getListAdapter() {
return mAdapter;
}
@ -456,7 +456,7 @@ abstract class BaseStatusesStaggeredGridFragment<Data> extends BasePullToRefresh
protected abstract void loadMoreStatuses();
protected abstract IStatusesAdapter<Data> newAdapterInstance();
protected abstract IStatusesListAdapter<Data> newAdapterInstance();
@Override
protected void onReachedBottom() {
@ -548,7 +548,7 @@ abstract class BaseStatusesStaggeredGridFragment<Data> extends BasePullToRefresh
static class RemoveUnreadCountsTask<T> extends AsyncTask<Void, Void, Void> {
private final List<Integer> read_positions;
private final IStatusesAdapter<T> adapter;
private final IStatusesListAdapter<T> adapter;
private final BaseStatusesStaggeredGridFragment<T> fragment;
RemoveUnreadCountsTask(final List<Integer> read_positions, final BaseStatusesStaggeredGridFragment<T> fragment) {

View File

@ -29,7 +29,7 @@ import android.support.v4.app.LoaderManager;
import android.support.v4.content.Loader;
import org.mariotaku.twidere.adapter.ParcelableStatusesAdapter;
import org.mariotaku.twidere.adapter.iface.IStatusesAdapter;
import org.mariotaku.twidere.adapter.iface.IStatusesListAdapter;
import org.mariotaku.twidere.loader.support.DummyParcelableStatusesLoader;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.util.ArrayUtils;
@ -135,7 +135,7 @@ public abstract class ParcelableStatusesListFragment extends BaseStatusesListFra
@Override
public void onRefreshFromStart() {
if (isRefreshing()) return;
final IStatusesAdapter<List<ParcelableStatus>> adapter = getListAdapter();
final IStatusesListAdapter<List<ParcelableStatus>> adapter = getListAdapter();
final int count = adapter.getCount();
final ParcelableStatus status = count > 0 ? adapter.getStatus(0) : null;
if (status != null) {
@ -170,14 +170,14 @@ public abstract class ParcelableStatusesListFragment extends BaseStatusesListFra
@Override
protected final long[] getNewestStatusIds() {
final IStatusesAdapter<List<ParcelableStatus>> adapter = getListAdapter();
final IStatusesListAdapter<List<ParcelableStatus>> adapter = getListAdapter();
final long last_id = adapter.getCount() > 0 ? adapter.getStatus(0).id : -1;
return last_id > 0 ? new long[]{last_id} : null;
}
@Override
protected final long[] getOldestStatusIds() {
final IStatusesAdapter<List<ParcelableStatus>> adapter = getListAdapter();
final IStatusesListAdapter<List<ParcelableStatus>> adapter = getListAdapter();
final ParcelableStatus status = adapter.getLastStatus();
final long last_id = status != null ? status.id : -1;
return last_id > 0 ? new long[]{last_id} : null;
@ -200,7 +200,7 @@ public abstract class ParcelableStatusesListFragment extends BaseStatusesListFra
@Override
protected void loadMoreStatuses() {
if (isRefreshing()) return;
final IStatusesAdapter<List<ParcelableStatus>> adapter = getListAdapter();
final IStatusesListAdapter<List<ParcelableStatus>> adapter = getListAdapter();
final ParcelableStatus status = adapter.getLastStatus();
if (status != null) {
getStatuses(new long[]{status.account_id}, new long[]{status.id}, null);

View File

@ -23,7 +23,7 @@ import android.content.Context;
import android.os.Bundle;
import android.support.v4.content.Loader;
import org.mariotaku.twidere.adapter.iface.IStatusesAdapter;
import org.mariotaku.twidere.adapter.iface.IStatusesListAdapter;
import org.mariotaku.twidere.loader.support.RetweetsOfMeLoader;
import org.mariotaku.twidere.model.ParcelableStatus;
@ -45,7 +45,7 @@ public class RetweetsOfMeFragment extends ParcelableStatusesListFragment {
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final IStatusesAdapter<List<ParcelableStatus>> adapter = getListAdapter();
final IStatusesListAdapter<List<ParcelableStatus>> adapter = getListAdapter();
adapter.setIndicateMyStatusDisabled(false);
adapter.setFiltersEnabled(true);
adapter.setIgnoredFilterFields(true, false, false, false, false);

View File

@ -28,7 +28,7 @@ import android.support.v4.content.Loader;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import org.mariotaku.twidere.adapter.iface.IStatusesAdapter;
import org.mariotaku.twidere.adapter.iface.IStatusesListAdapter;
import org.mariotaku.twidere.loader.support.TweetSearchLoader;
import org.mariotaku.twidere.model.ParcelableStatus;
@ -44,7 +44,7 @@ public class SearchStatusesFragment extends ParcelableStatusesListFragment {
final long sinceId = args.getLong(EXTRA_SINCE_ID, -1);
final String query = args.getString(EXTRA_QUERY);
final int tabPosition = args.getInt(EXTRA_TAB_POSITION, -1);
final IStatusesAdapter<List<ParcelableStatus>> adapter = getListAdapter();
final IStatusesListAdapter<List<ParcelableStatus>> adapter = getListAdapter();
adapter.setHighlightKeyword(query.split(" "));
return new TweetSearchLoader(getActivity(), accountId, query, maxId, sinceId, getData(),
getSavedStatusesFileArgs(), tabPosition);
@ -53,7 +53,7 @@ public class SearchStatusesFragment extends ParcelableStatusesListFragment {
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final IStatusesAdapter<List<ParcelableStatus>> adapter = getListAdapter();
final IStatusesListAdapter<List<ParcelableStatus>> adapter = getListAdapter();
adapter.setFiltersEnabled(true);
adapter.setIgnoredFilterFields(false, false, false, false, false);
}

View File

@ -72,7 +72,7 @@ import org.mariotaku.twidere.activity.support.AccountSelectorActivity;
import org.mariotaku.twidere.activity.support.ColorPickerDialogActivity;
import org.mariotaku.twidere.activity.support.LinkHandlerActivity;
import org.mariotaku.twidere.adapter.ParcelableStatusesAdapter;
import org.mariotaku.twidere.adapter.iface.IStatusesAdapter;
import org.mariotaku.twidere.adapter.iface.IStatusesListAdapter;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.model.Account;
import org.mariotaku.twidere.model.Account.AccountWithCredentials;
@ -718,7 +718,7 @@ public class StatusFragment extends ParcelableStatusesListFragment implements On
@Override
public boolean scrollToStart() {
if (mListView == null) return false;
final IStatusesAdapter<List<ParcelableStatus>> adapter = getListAdapter();
final IStatusesListAdapter<List<ParcelableStatus>> adapter = getListAdapter();
scrollListToPosition(mListView, adapter.getCount() + mListView.getFooterViewsCount() - 1, 0);
return true;
}
@ -773,17 +773,13 @@ public class StatusFragment extends ParcelableStatusesListFragment implements On
}
case MENU_QUOTE: {
final Intent intent = new Intent(INTENT_ACTION_QUOTE);
final Bundle bundle = new Bundle();
bundle.putParcelable(EXTRA_STATUS, status);
intent.putExtras(bundle);
intent.putExtra(EXTRA_STATUS, status);
startActivity(intent);
break;
}
case MENU_REPLY: {
final Intent intent = new Intent(INTENT_ACTION_REPLY);
final Bundle bundle = new Bundle();
bundle.putParcelable(EXTRA_STATUS, status);
intent.putExtras(bundle);
intent.putExtra(EXTRA_STATUS, status);
startActivity(intent);
break;
}
@ -940,7 +936,7 @@ public class StatusFragment extends ParcelableStatusesListFragment implements On
mConversationTask.cancel(true);
return;
}
final IStatusesAdapter<List<ParcelableStatus>> adapter = getListAdapter();
final IStatusesListAdapter<List<ParcelableStatus>> adapter = getListAdapter();
final int count = adapter.getCount();
final ParcelableStatus status;
if (count == 0) {
@ -980,7 +976,7 @@ public class StatusFragment extends ParcelableStatusesListFragment implements On
private void updateConversationInfo() {
final boolean has_converstion = mStatus != null && mStatus.in_reply_to_status_id > 0;
final IStatusesAdapter<List<ParcelableStatus>> adapter = getListAdapter();
final IStatusesListAdapter<List<ParcelableStatus>> adapter = getListAdapter();
final boolean load_not_finished = adapter.isEmpty()
|| adapter.getStatus(adapter.getCount() - 1).in_reply_to_status_id > 0;
final boolean enable = has_converstion && load_not_finished;
@ -1037,7 +1033,7 @@ public class StatusFragment extends ParcelableStatusesListFragment implements On
@Override
public void run() {
final String uri = getMapStaticImageUri(mLocation.latitude, mLocation.longitude, mView);
mLoader.displayPreviewImage(mView, uri);
mLoader.displayPreviewImage(uri, mView);
}
}

View File

@ -29,7 +29,7 @@ import android.content.IntentFilter;
import android.os.Bundle;
import android.support.v4.content.Loader;
import org.mariotaku.twidere.adapter.iface.IStatusesAdapter;
import org.mariotaku.twidere.adapter.iface.IStatusesListAdapter;
import org.mariotaku.twidere.loader.support.UserFavoritesLoader;
import org.mariotaku.twidere.model.ParcelableStatus;
@ -82,7 +82,7 @@ public class UserFavoritesFragment extends ParcelableStatusesListFragment {
final String screen_name = args != null ? args.getString(EXTRA_SCREEN_NAME) : null;
final boolean is_my_timeline = user_id > 0 ? account_id == user_id : account_id == getAccountId(getActivity(),
screen_name);
final IStatusesAdapter<List<ParcelableStatus>> adapter = getListAdapter();
final IStatusesListAdapter<List<ParcelableStatus>> adapter = getListAdapter();
adapter.setFavoritesHightlightDisabled(is_my_timeline);
adapter.setFiltersEnabled(false);
}

View File

@ -23,7 +23,7 @@ import android.content.Context;
import android.os.Bundle;
import android.support.v4.content.Loader;
import org.mariotaku.twidere.adapter.iface.IStatusesAdapter;
import org.mariotaku.twidere.adapter.iface.IStatusesListAdapter;
import org.mariotaku.twidere.loader.support.UserListTimelineLoader;
import org.mariotaku.twidere.model.ParcelableStatus;
@ -49,7 +49,7 @@ public class UserListTimelineFragment extends ParcelableStatusesListFragment {
@Override
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final IStatusesAdapter<List<ParcelableStatus>> adapter = getListAdapter();
final IStatusesListAdapter<List<ParcelableStatus>> adapter = getListAdapter();
adapter.setFiltersEnabled(true);
adapter.setIgnoredFilterFields(false, false, false, false, false);
}

View File

@ -23,7 +23,7 @@ import android.content.Context;
import android.os.Bundle;
import android.support.v4.content.Loader;
import org.mariotaku.twidere.adapter.iface.IStatusesAdapter;
import org.mariotaku.twidere.adapter.iface.IStatusesListAdapter;
import org.mariotaku.twidere.loader.support.UserTimelineLoader;
import org.mariotaku.twidere.model.ParcelableStatus;
@ -56,7 +56,7 @@ public class UserTimelineFragment extends ParcelableStatusesListFragment {
final String screenName = args != null ? args.getString(EXTRA_SCREEN_NAME) : null;
final boolean isMyTimeline = userId > 0 ? accountId == userId : accountId == getAccountId(getActivity(),
screenName);
final IStatusesAdapter<List<ParcelableStatus>> adapter = getListAdapter();
final IStatusesListAdapter<List<ParcelableStatus>> adapter = getListAdapter();
adapter.setIndicateMyStatusDisabled(isMyTimeline);
adapter.setFiltersEnabled(!isMyTimeline);
adapter.setIgnoredFilterFields(true, false, false, false, false);

View File

@ -0,0 +1,339 @@
package org.mariotaku.twidere.fragment.support;
import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.Adapter;
import android.support.v7.widget.RecyclerView.OnScrollListener;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.pkmmte.view.CircularImageView;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.decorator.DividerItemDecoration;
import org.mariotaku.twidere.adapter.iface.IStatusesAdapter;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.loader.support.UserTimelineLoader;
import org.mariotaku.twidere.model.ParcelableMedia;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.util.ImageLoaderWrapper;
import org.mariotaku.twidere.util.ImageLoadingHandler;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.ShortTimeView;
import java.util.List;
import java.util.Locale;
/**
* Created by mariotaku on 14/11/5.
*/
public class UserTimelineFragment2 extends BaseSupportFragment
implements LoaderCallbacks<List<ParcelableStatus>> {
private RecyclerView mRecyclerView;
private ProgressBar mProgress;
private ParcelableTimelineAdapter mAdapter;
private OnScrollListener mOnScrollListener = new OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
}
};
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
final View view = getView();
assert view != null;
final Context context = view.getContext();
final boolean compact = Utils.isCompactCards(context);
mAdapter = new ParcelableTimelineAdapter(context, compact);
final LinearLayoutManager layoutManager = new LinearLayoutManager(context);
layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mRecyclerView.setLayoutManager(layoutManager);
if (compact) {
mRecyclerView.addItemDecoration(new DividerItemDecoration(context, layoutManager.getOrientation()));
}
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setOnScrollListener(mOnScrollListener);
getLoaderManager().initLoader(0, getArguments(), this);
setListShown(false);
}
public void setListShown(boolean shown) {
mRecyclerView.setVisibility(shown ? View.VISIBLE : View.GONE);
mProgress.setVisibility(shown ? View.GONE : View.VISIBLE);
}
public int getStatuses(final long maxId, final long sinceId) {
final Bundle args = new Bundle(getArguments());
args.putLong(EXTRA_MAX_ID, maxId);
args.putLong(EXTRA_SINCE_ID, sinceId);
getLoaderManager().restartLoader(0, args, this);
return -1;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mRecyclerView = (RecyclerView) view.findViewById(android.R.id.list);
mProgress = (ProgressBar) view.findViewById(android.R.id.progress);
}
@Override
protected void fitSystemWindows(Rect insets) {
super.fitSystemWindows(insets);
mRecyclerView.setClipToPadding(false);
mRecyclerView.setPadding(insets.left, insets.top, insets.right, insets.bottom);
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_recycler_view, container, false);
}
@Override
public Loader<List<ParcelableStatus>> onCreateLoader(int id, Bundle args) {
final Context context = getActivity();
final long accountId = args.getLong(EXTRA_ACCOUNT_ID, -1);
final long maxId = args.getLong(EXTRA_MAX_ID, -1);
final long sinceId = args.getLong(EXTRA_SINCE_ID, -1);
final long userId = args.getLong(EXTRA_USER_ID, -1);
final String screenName = args.getString(EXTRA_SCREEN_NAME);
final int tabPosition = args.getInt(EXTRA_TAB_POSITION, -1);
return new UserTimelineLoader(context, accountId, userId, screenName, maxId, sinceId, null,
null, tabPosition);
}
@Override
public void onLoadFinished(Loader<List<ParcelableStatus>> loader, List<ParcelableStatus> data) {
mAdapter.setData(data);
setListShown(true);
}
@Override
public void onLoaderReset(Loader<List<ParcelableStatus>> loader) {
mAdapter.setData(null);
}
private static class ParcelableTimelineAdapter extends Adapter<ViewHolder> implements IStatusesAdapter, OnClickListener {
private static final int ITEM_VIEW_TYPE_STATUS = 1;
private static final int ITEM_VIEW_TYPE_LOAD_INDICATOR = 2;
private final Context mContext;
private final LayoutInflater mInflater;
private final ImageLoaderWrapper mImageLoader;
private final ImageLoadingHandler mLoadingHandler;
private final int mCardLayoutResource;
private List<ParcelableStatus> mData;
private boolean mHasMoreItem;
ParcelableTimelineAdapter(Context context, boolean compact) {
mContext = context;
mInflater = LayoutInflater.from(context);
mImageLoader = TwidereApplication.getInstance(context).getImageLoaderWrapper();
mLoadingHandler = new ImageLoadingHandler(R.id.media_preview_progress);
if (compact) {
mCardLayoutResource = R.layout.card_item_list_status_compat;
} else {
mCardLayoutResource = R.layout.card_item_list_status;
}
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case ITEM_VIEW_TYPE_STATUS: {
final View view = mInflater.inflate(mCardLayoutResource, parent, false);
return new MediaTimelineViewHolder(this, view);
}
case ITEM_VIEW_TYPE_LOAD_INDICATOR: {
final View view = mInflater.inflate(R.layout.card_item_load_indicator, parent, false);
return new LoadIndicatorViewHolder(view);
}
}
throw new IllegalStateException("Unknown view type " + viewType);
}
public void setHasMoreItem(boolean hasMoreItem) {
if (mHasMoreItem == hasMoreItem) return;
mHasMoreItem = hasMoreItem;
notifyDataSetChanged();
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
if (mData == null) return;
if (holder instanceof MediaTimelineViewHolder) {
((MediaTimelineViewHolder) holder).displayStatus(this, getStatus(position));
}
}
public void setData(List<ParcelableStatus> data) {
mData = data;
notifyDataSetChanged();
}
@Override
public int getItemViewType(int position) {
if (position == getItemCount() - 1) {
return ITEM_VIEW_TYPE_LOAD_INDICATOR;
}
return ITEM_VIEW_TYPE_STATUS;
}
@Override
public int getItemCount() {
if (mData == null) return mHasMoreItem ? 1 : 0;
return mData.size() + (mHasMoreItem ? 1 : 0);
}
public ImageLoaderWrapper getImageLoader() {
return mImageLoader;
}
public Context getContext() {
return mContext;
}
public ImageLoadingHandler getImageLoadingHandler() {
return mLoadingHandler;
}
@Override
public void onClick(View v) {
}
@Override
public ParcelableStatus getStatus(int position) {
if (mData == null || (mHasMoreItem && position == mData.size() - 1)) return null;
return mData.get(position);
}
}
private static class LoadIndicatorViewHolder extends ViewHolder {
public LoadIndicatorViewHolder(View view) {
super(view);
}
}
private static class MediaTimelineViewHolder extends ViewHolder implements OnClickListener {
private final IStatusesAdapter adapter;
private final ImageView mediaPreviewView;
private final CircularImageView profileImageView;
private final TextView textView;
private final TextView nameView;
private final ShortTimeView timeView;
private final View mediaPreviewContainer;
private final View replyIndicator, retweetIndicator, favoriteIndicator;
private final TextView replyCountView, retweetCountView, favoriteCountView;
public MediaTimelineViewHolder(IStatusesAdapter adapter, View itemView) {
super(itemView);
this.adapter = adapter;
itemView.findViewById(R.id.item_content).setOnClickListener(this);
profileImageView = (CircularImageView) itemView.findViewById(R.id.profile_image);
textView = (TextView) itemView.findViewById(R.id.text);
nameView = (TextView) itemView.findViewById(R.id.name);
timeView = (ShortTimeView) itemView.findViewById(R.id.time);
mediaPreviewContainer = itemView.findViewById(R.id.media_preview_container);
mediaPreviewView = (ImageView) itemView.findViewById(R.id.media_preview);
replyIndicator = itemView.findViewById(R.id.reply_indicator);
retweetIndicator = itemView.findViewById(R.id.retweet_indicator);
favoriteIndicator = itemView.findViewById(R.id.favorite_indicator);
replyCountView = (TextView) itemView.findViewById(R.id.reply_count);
retweetCountView = (TextView) itemView.findViewById(R.id.retweet_count);
favoriteCountView = (TextView) itemView.findViewById(R.id.favorite_count);
profileImageView.setSelectorColor(ThemeUtils.getUserHighlightColor(itemView.getContext()));
itemView.setOnClickListener(this);
profileImageView.setOnClickListener(this);
mediaPreviewContainer.setOnClickListener(this);
replyIndicator.setOnClickListener(this);
retweetIndicator.setOnClickListener(this);
favoriteIndicator.setOnClickListener(this);
}
public void displayStatus(ParcelableTimelineAdapter adapter, ParcelableStatus status) {
final ImageLoaderWrapper loader = adapter.getImageLoader();
final Context context = adapter.getContext();
final ParcelableMedia[] media = status.media;
nameView.setText(status.user_name);
timeView.setTime(status.timestamp);
loader.displayProfileImage(profileImageView, status.user_profile_image_url);
// profileImageView.setBorderColor(UserColorNicknameUtils.getUserColor(context, status.user_id));
if (media != null && media.length > 0) {
final ParcelableMedia firstMedia = media[0];
if (status.text_plain.codePointCount(0, status.text_plain.length()) == firstMedia.end) {
textView.setText(status.text_unescaped.substring(0, firstMedia.start));
} else {
textView.setText(status.text_unescaped);
}
loader.displayPreviewImageWithCredentials(mediaPreviewView, firstMedia.media_url,
status.account_id, adapter.getImageLoadingHandler());
mediaPreviewContainer.setVisibility(View.VISIBLE);
} else {
loader.cancelDisplayTask(mediaPreviewView);
textView.setText(status.text_unescaped);
mediaPreviewContainer.setVisibility(View.GONE);
}
retweetIndicator.setActivated(status.is_retweet);
favoriteIndicator.setActivated(status.is_favorite);
replyCountView.setVisibility(status.reply_count > 0 ? View.VISIBLE : View.INVISIBLE);
retweetCountView.setVisibility(status.retweet_count > 0 ? View.VISIBLE : View.INVISIBLE);
favoriteCountView.setVisibility(status.favorite_count > 0 ? View.VISIBLE : View.INVISIBLE);
replyCountView.setText(Utils.getLocalizedNumber(Locale.getDefault(), status.reply_count));
retweetCountView.setText(Utils.getLocalizedNumber(Locale.getDefault(), status.retweet_count));
favoriteCountView.setText(Utils.getLocalizedNumber(Locale.getDefault(), status.favorite_count));
}
@Override
public void onClick(View v) {
final Context context = itemView.getContext();
final ParcelableStatus status = adapter.getStatus(getPosition());
switch (v.getId()) {
case R.id.item_content: {
Utils.openStatus(context, status);
break;
}
case R.id.profile_image: {
Utils.openUserProfile(context, status.account_id, status.user_id, status.user_screen_name);
break;
}
case R.id.reply_indicator: {
final Intent intent = new Intent(INTENT_ACTION_REPLY);
intent.setPackage(context.getPackageName());
intent.putExtra(EXTRA_STATUS, status);
context.startActivity(intent);
break;
}
}
}
}
}

View File

@ -21,7 +21,6 @@ package org.mariotaku.twidere.preference;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
@ -51,6 +50,7 @@ import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.model.Account;
import org.mariotaku.twidere.task.AsyncTask;
import org.mariotaku.twidere.util.ImageLoaderWrapper;
import org.mariotaku.twidere.util.Utils;
import java.util.List;
@ -102,8 +102,11 @@ public abstract class AccountsListPreference extends PreferenceCategory implemen
private final Account mAccount;
private final SharedPreferences mSwitchPreference;
private final ImageLoaderWrapper mImageLoader;
private final String mSwitchKey;
private final boolean mSwitchDefault;
private Switch mToggle;
public AccountItemPreference(final Context context, final Account account, final String switchKey,
final boolean switchDefault) {
@ -113,6 +116,8 @@ public abstract class AccountsListPreference extends PreferenceCategory implemen
final String switchPreferenceName = ACCOUNT_PREFERENCES_NAME_PREFIX + account.account_id;
mAccount = account;
mSwitchPreference = context.getSharedPreferences(switchPreferenceName, Context.MODE_PRIVATE);
final TwidereApplication app = TwidereApplication.getInstance(context);
mImageLoader = app.getImageLoaderWrapper();
mSwitchKey = switchKey;
mSwitchDefault = switchDefault;
mSwitchPreference.registerOnSharedPreferenceChangeListener(this);
@ -133,7 +138,8 @@ public abstract class AccountsListPreference extends PreferenceCategory implemen
@Override
public void onLoadingComplete(final String imageUri, final View view, final Bitmap loadedImage) {
setIcon(new BitmapDrawable(getContext().getResources(), loadedImage));
final Bitmap roundedBitmap = Utils.getCircleBitmap(loadedImage);
setIcon(new BitmapDrawable(getContext().getResources(), roundedBitmap));
}
@Override
@ -157,9 +163,7 @@ public abstract class AccountsListPreference extends PreferenceCategory implemen
setTitle(mAccount.name);
setSummary(String.format("@%s", mAccount.screen_name));
setIcon(R.drawable.ic_profile_image_default);
final TwidereApplication app = TwidereApplication.getInstance(getContext());
final ImageLoaderWrapper loader = app.getImageLoaderWrapper();
loader.loadProfileImage(mAccount.profile_image_url, this);
mImageLoader.loadProfileImage(mAccount.profile_image_url, this);
}
@Override
@ -168,6 +172,7 @@ public abstract class AccountsListPreference extends PreferenceCategory implemen
view.findViewById(R.id.settings).setOnClickListener(this);
final Switch toggle = (Switch) view.findViewById(android.R.id.toggle);
toggle.setOnCheckedChangeListener(this);
mToggle = toggle;
return view;
}
@ -176,7 +181,8 @@ public abstract class AccountsListPreference extends PreferenceCategory implemen
super.onBindView(view);
final View iconView = view.findViewById(android.R.id.icon);
if (iconView instanceof ImageView) {
((ImageView) iconView).setScaleType(ScaleType.FIT_CENTER);
final ImageView imageView = (ImageView) iconView;
imageView.setScaleType(ScaleType.CENTER_CROP);
}
final View titleView = view.findViewById(android.R.id.title);
if (titleView instanceof TextView) {
@ -194,7 +200,9 @@ public abstract class AccountsListPreference extends PreferenceCategory implemen
@Override
public boolean onPreferenceClick(Preference preference) {
if (mToggle != null) {
mToggle.toggle();
}
return true;
}

View File

@ -175,6 +175,13 @@ public class ThemeBackgroundPreference extends DialogPreference implements Const
ViewAccessor.setBackground(mAlphaPreview, new AlphaPatternDrawable(patternSize));
updateAlphaVisibility();
updateAlphaPreview();
final int checkedIdx = findIndexOfValue(getPersistedString(mValue));
if (checkedIdx < 0) {
listView.clearChoices();
} else {
listView.setItemChecked(checkedIdx, true);
}
}
}

View File

@ -31,13 +31,16 @@ import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.util.imageloader.AccountExtra;
import org.mariotaku.twidere.util.imageloader.OvalBitmapDisplayer;
import static org.mariotaku.twidere.util.Utils.getBestBannerType;
public class ImageLoaderWrapper implements Constants {
private final ImageLoader mImageLoader;
private final DisplayImageOptions mProfileImageDisplayOptions, mImageDisplayOptions, mBannerDisplayOptions;
private final DisplayImageOptions mProfileImageDisplayOptions;
private final DisplayImageOptions mOvalProfileImageDisplayOptions;
private final DisplayImageOptions mImageDisplayOptions, mBannerDisplayOptions;
public ImageLoaderWrapper(final ImageLoader loader) {
mImageLoader = loader;
@ -49,6 +52,15 @@ public class ImageLoaderWrapper implements Constants {
profileOptsBuilder.showImageOnLoading(R.drawable.ic_profile_image_default);
profileOptsBuilder.bitmapConfig(Bitmap.Config.ARGB_8888);
profileOptsBuilder.resetViewBeforeLoading(true);
final DisplayImageOptions.Builder ovalProfileOptsBuilder = new DisplayImageOptions.Builder();
ovalProfileOptsBuilder.cacheInMemory(true);
ovalProfileOptsBuilder.cacheOnDisk(true);
ovalProfileOptsBuilder.showImageForEmptyUri(R.drawable.ic_profile_image_default);
ovalProfileOptsBuilder.showImageOnFail(R.drawable.ic_profile_image_default);
ovalProfileOptsBuilder.showImageOnLoading(R.drawable.ic_profile_image_default);
ovalProfileOptsBuilder.bitmapConfig(Bitmap.Config.ARGB_8888);
ovalProfileOptsBuilder.displayer(new OvalBitmapDisplayer());
ovalProfileOptsBuilder.resetViewBeforeLoading(true);
final DisplayImageOptions.Builder imageOptsBuilder = new DisplayImageOptions.Builder();
imageOptsBuilder.cacheInMemory(true);
imageOptsBuilder.cacheOnDisk(true);
@ -61,6 +73,7 @@ public class ImageLoaderWrapper implements Constants {
bannerOptsBuilder.displayer(new FadeInBitmapDisplayer(200, true, true, false));
mProfileImageDisplayOptions = profileOptsBuilder.build();
mOvalProfileImageDisplayOptions = ovalProfileOptsBuilder.build();
mImageDisplayOptions = imageOptsBuilder.build();
mBannerDisplayOptions = bannerOptsBuilder.build();
}
@ -73,8 +86,8 @@ public class ImageLoaderWrapper implements Constants {
mImageLoader.clearMemoryCache();
}
public void displayPreviewImage(final ImageView view, final String url) {
mImageLoader.displayImage(url, view, mImageDisplayOptions);
public void displayPreviewImage(final String uri, final ImageView view) {
mImageLoader.displayImage(uri, view, mImageDisplayOptions);
}
public void displayPreviewImage(final ImageView view, final String url, final ImageLoadingHandler loadingHandler) {
@ -103,6 +116,10 @@ public class ImageLoaderWrapper implements Constants {
mImageLoader.loadImage(url, mProfileImageDisplayOptions, listener);
}
public void displayOvalProfileImage(final String url, final ImageView view) {
mImageLoader.displayImage(url, view, mOvalProfileImageDisplayOptions);
}
public void cancelDisplayTask(ImageView imageView) {
mImageLoader.cancelDisplayTask(imageView);
}

View File

@ -24,150 +24,129 @@ import android.content.Context;
import android.content.SharedPreferences;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.activity.support.BaseSupportActivity;
import org.mariotaku.twidere.activity.support.HomeActivity;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public final class MessagesManager implements Constants {
private final Set<Activity> mMessageCallbacks = Collections.synchronizedSet(new HashSet<Activity>());
private final Context mContext;
private final SharedPreferences mPreferences;
private final Context mContext;
private final SharedPreferences mPreferences;
public MessagesManager(final Context context) {
mContext = context;
mPreferences = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
}
public MessagesManager(final Context context) {
mContext = context;
mPreferences = context.getSharedPreferences(SHARED_PREFERENCES_NAME, Context.MODE_PRIVATE);
}
public boolean addMessageCallback(final Activity activity) {
if (activity == null) return false;
return mMessageCallbacks.add(activity);
}
public boolean addMessageCallback(final Activity activity) {
if (activity == null) return false;
return true;
}
public boolean removeMessageCallback(final Activity activity) {
if (activity == null) return false;
return mMessageCallbacks.remove(activity);
}
public boolean removeMessageCallback(final Activity activity) {
if (activity == null) return false;
return true;
}
public void showErrorMessage(final CharSequence message, final boolean long_message) {
final Activity best = getBestActivity();
if (best != null) {
Utils.showErrorMessage(best, message, long_message);
return;
}
if (showToast()) {
Utils.showErrorMessage(mContext, message, long_message);
return;
}
}
public void showErrorMessage(final CharSequence message, final boolean long_message) {
final Activity best = getBestActivity();
if (best != null) {
Utils.showErrorMessage(best, message, long_message);
return;
}
if (showToast()) {
Utils.showErrorMessage(mContext, message, long_message);
return;
}
}
public void showErrorMessage(final int actionRes, final Exception e, final boolean long_message) {
final String action = mContext.getString(actionRes);
final Activity best = getBestActivity();
if (best != null) {
Utils.showErrorMessage(best, action, e, long_message);
return;
}
if (showToast()) {
Utils.showErrorMessage(mContext, action, e, long_message);
return;
}
}
public void showErrorMessage(final int actionRes, final Exception e, final boolean long_message) {
final String action = mContext.getString(actionRes);
final Activity best = getBestActivity();
if (best != null) {
Utils.showErrorMessage(best, action, e, long_message);
return;
}
if (showToast()) {
Utils.showErrorMessage(mContext, action, e, long_message);
return;
}
}
public void showErrorMessage(final int action_res, final String message, final boolean long_message) {
final String action = mContext.getString(action_res);
final Activity best = getBestActivity();
if (best != null) {
Utils.showErrorMessage(best, action, message, long_message);
return;
}
if (showToast()) {
Utils.showErrorMessage(mContext, action, message, long_message);
return;
}
}
public void showErrorMessage(final int action_res, final String message, final boolean longMessage) {
final String action = mContext.getString(action_res);
final Activity best = getBestActivity();
if (best != null) {
Utils.showErrorMessage(best, action, message, longMessage);
return;
}
if (showToast()) {
Utils.showErrorMessage(mContext, action, message, longMessage);
return;
}
}
public void showInfoMessage(final CharSequence message, final boolean long_message) {
final Activity best = getBestActivity();
if (best != null) {
Utils.showInfoMessage(best, message, long_message);
return;
}
if (showToast()) {
Utils.showInfoMessage(mContext, message, long_message);
return;
}
}
public void showInfoMessage(final CharSequence message, final boolean longMessage) {
final Activity best = getBestActivity();
if (best != null) {
Utils.showInfoMessage(best, message, longMessage);
return;
}
if (showToast()) {
Utils.showInfoMessage(mContext, message, longMessage);
return;
}
}
public void showInfoMessage(final int message_res, final boolean long_message) {
final Activity best = getBestActivity();
if (best != null) {
Utils.showInfoMessage(best, message_res, long_message);
return;
}
if (showToast()) {
Utils.showInfoMessage(mContext, message_res, long_message);
return;
}
}
public void showInfoMessage(final int messageRes, final boolean longMessage) {
final Activity best = getBestActivity();
if (best != null) {
Utils.showInfoMessage(best, messageRes, longMessage);
return;
}
if (showToast()) {
Utils.showInfoMessage(mContext, messageRes, longMessage);
return;
}
}
public void showOkMessage(final CharSequence message, final boolean long_message) {
final Activity best = getBestActivity();
if (best != null) {
Utils.showOkMessage(best, message, long_message);
return;
}
if (showToast()) {
Utils.showOkMessage(mContext, message, long_message);
}
}
public void showOkMessage(final CharSequence message, final boolean longMessage) {
final Activity best = getBestActivity();
if (best != null) {
Utils.showOkMessage(best, message, longMessage);
return;
}
if (showToast()) {
Utils.showOkMessage(mContext, message, longMessage);
}
}
public void showOkMessage(final int message_res, final boolean long_message) {
final Activity best = getBestActivity();
if (best != null) {
Utils.showOkMessage(best, message_res, long_message);
return;
}
if (showToast()) {
Utils.showOkMessage(mContext, message_res, long_message);
return;
}
}
public void showOkMessage(final int messageRes, final boolean longMessage) {
final Activity best = getBestActivity();
if (best != null) {
Utils.showOkMessage(best, messageRes, longMessage);
return;
}
if (showToast()) {
Utils.showOkMessage(mContext, messageRes, longMessage);
return;
}
}
public void showWarnMessage(final int message_res, final boolean long_message) {
final Activity best = getBestActivity();
if (best != null) {
Utils.showWarnMessage(best, message_res, long_message);
return;
}
if (showToast()) {
Utils.showWarnMessage(mContext, message_res, long_message);
}
}
public void showWarnMessage(final int messageRes, final boolean longMessage) {
final Activity best = getBestActivity();
if (best != null) {
Utils.showWarnMessage(best, messageRes, longMessage);
return;
}
if (showToast()) {
Utils.showWarnMessage(mContext, messageRes, longMessage);
}
}
private Activity getBestActivity() {
for (final Activity activity : mMessageCallbacks) {
if (activity instanceof BaseSupportActivity) {
final BaseSupportActivity base = (BaseSupportActivity) activity;
if (base.isOnTop()) return base;
}
}
for (final Activity activity : mMessageCallbacks) {
if (activity instanceof HomeActivity) {
final HomeActivity home = (HomeActivity) activity;
if (home.isVisible()) return home;
}
}
for (final Activity activity : mMessageCallbacks)
if (ThemeUtils.isFloatingWindow(activity)) return activity;
return null;
}
private Activity getBestActivity() {
return null;
}
private boolean showToast() {
return mPreferences.getBoolean(KEY_BACKGROUND_TOAST_NOTIFICATION, false);
}
private boolean showToast() {
return true;
}
}

View File

@ -41,8 +41,12 @@ import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
@ -139,7 +143,7 @@ import org.mariotaku.twidere.fragment.support.UserListsListFragment;
import org.mariotaku.twidere.fragment.support.UserMediaTimelineFragment;
import org.mariotaku.twidere.fragment.support.UserMentionsFragment;
import org.mariotaku.twidere.fragment.support.UserProfileFragmentOld;
import org.mariotaku.twidere.fragment.support.UserTimelineFragment;
import org.mariotaku.twidere.fragment.support.UserTimelineFragment2;
import org.mariotaku.twidere.fragment.support.UsersListFragment;
import org.mariotaku.twidere.graphic.PaddingDrawable;
import org.mariotaku.twidere.model.Account;
@ -676,6 +680,27 @@ public final class Utils implements Constants, TwitterConstants {
}
}
public static Bitmap getCircleBitmap(Bitmap bitmap) {
final Bitmap output = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(),
Bitmap.Config.ARGB_8888);
final Canvas canvas = new Canvas(output);
final int color = Color.RED;
final Paint paint = new Paint();
final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
final RectF rectF = new RectF(rect);
paint.setAntiAlias(true);
canvas.drawARGB(0, 0, 0, 0);
paint.setColor(color);
canvas.drawOval(rectF, paint);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(bitmap, rect, rect, paint);
return output;
}
public static Fragment createFragmentForIntent(final Context context, final Intent intent) {
final long start = System.currentTimeMillis();
intent.setExtrasClassLoader(context.getClassLoader());
@ -721,7 +746,7 @@ public final class Utils implements Constants, TwitterConstants {
break;
}
case LINK_ID_USER_TIMELINE: {
fragment = new UserTimelineFragment();
fragment = new UserTimelineFragment2();
final String paramScreenName = uri.getQueryParameter(QUERY_PARAM_SCREEN_NAME);
final String paramUserId = uri.getQueryParameter(QUERY_PARAM_USER_ID);
if (!args.containsKey(EXTRA_SCREEN_NAME)) {
@ -2990,8 +3015,8 @@ public final class Utils implements Constants, TwitterConstants {
activity.startActivity(intent);
}
public static void openStatus(final Activity activity, final ParcelableStatus status) {
if (activity == null || status == null) return;
public static void openStatus(final Context context, final ParcelableStatus status) {
if (context == null || status == null) return;
final long account_id = status.account_id, status_id = status.id;
final Bundle extras = new Bundle();
extras.putParcelable(EXTRA_STATUS, status);
@ -3001,9 +3026,9 @@ public final class Utils implements Constants, TwitterConstants {
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(account_id));
builder.appendQueryParameter(QUERY_PARAM_STATUS_ID, String.valueOf(status_id));
final Intent intent = new Intent(Intent.ACTION_VIEW, builder.build());
intent.setExtrasClassLoader(activity.getClassLoader());
intent.setExtrasClassLoader(context.getClassLoader());
intent.putExtras(extras);
activity.startActivity(intent);
context.startActivity(intent);
}
public static void openStatuses(final Activity activity, final List<ParcelableStatus> statuses) {
@ -3302,21 +3327,21 @@ public final class Utils implements Constants, TwitterConstants {
activity.startActivity(intent);
}
public static void openUserProfile(final Activity activity, final long account_id, final long user_id,
final String screen_name) {
if (activity == null || account_id <= 0 || user_id <= 0 && isEmpty(screen_name)) return;
public static void openUserProfile(final Context context, final long accountId, final long userId,
final String screenName) {
if (context == null || accountId <= 0 || userId <= 0 && isEmpty(screenName)) return;
final Uri.Builder builder = new Uri.Builder();
builder.scheme(SCHEME_TWIDERE);
builder.authority(AUTHORITY_USER);
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(account_id));
if (user_id > 0) {
builder.appendQueryParameter(QUERY_PARAM_USER_ID, String.valueOf(user_id));
builder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(accountId));
if (userId > 0) {
builder.appendQueryParameter(QUERY_PARAM_USER_ID, String.valueOf(userId));
}
if (screen_name != null) {
builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screen_name);
if (screenName != null) {
builder.appendQueryParameter(QUERY_PARAM_SCREEN_NAME, screenName);
}
final Intent intent = new Intent(Intent.ACTION_VIEW, builder.build());
activity.startActivity(intent);
context.startActivity(intent);
}
public static void openUserProfile(final Activity activity, final ParcelableUser user) {

View File

@ -0,0 +1,124 @@
/*******************************************************************************
* Copyright 2011-2013 Sergey Tarasevich
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package org.mariotaku.twidere.util.imageloader;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import com.nostra13.universalimageloader.core.assist.LoadedFrom;
import com.nostra13.universalimageloader.core.display.BitmapDisplayer;
import com.nostra13.universalimageloader.core.imageaware.ImageAware;
import com.nostra13.universalimageloader.core.imageaware.ImageViewAware;
/**
* Can display bitmap with rounded corners. This implementation works only with ImageViews wrapped
* in ImageViewAware.
* <br />
* This implementation is inspired by
* <a href="http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/">
* Romain Guy's article</a>. It rounds images using custom drawable drawing. Original bitmap isn't changed.
* <br />
* <br />
* If this implementation doesn't meet your needs then consider
* <a href="https://github.com/vinc3m1/RoundedImageView">RoundedImageView</a> or
* <a href="https://github.com/Pkmmte/CircularImageView">CircularImageView</a> projects for usage.
*
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
* @since 1.5.6
*/
public class OvalBitmapDisplayer implements BitmapDisplayer {
protected final int margin;
public OvalBitmapDisplayer() {
this(0);
}
public OvalBitmapDisplayer(int marginPixels) {
this.margin = marginPixels;
}
@Override
public void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) {
if (!(imageAware instanceof ImageViewAware)) {
throw new IllegalArgumentException("ImageAware should wrap ImageView. ImageViewAware is expected.");
}
imageAware.setImageDrawable(new OvalDrawable(bitmap, margin));
}
public static class OvalDrawable extends Drawable {
protected final int margin;
protected final RectF mRect = new RectF(),
mBitmapRect;
protected final BitmapShader bitmapShader;
protected final Paint paint;
public OvalDrawable(Bitmap bitmap, int margin) {
this.margin = margin;
bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
mBitmapRect = new RectF(margin, margin, bitmap.getWidth() - margin, bitmap.getHeight() - margin);
paint = new Paint();
paint.setAntiAlias(true);
paint.setShader(bitmapShader);
}
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
mRect.set(margin, margin, bounds.width() - margin, bounds.height() - margin);
// Resize the original bitmap to fit the new bound
Matrix shaderMatrix = new Matrix();
shaderMatrix.setRectToRect(mBitmapRect, mRect, Matrix.ScaleToFit.FILL);
bitmapShader.setLocalMatrix(shaderMatrix);
}
@Override
public void draw(Canvas canvas) {
canvas.drawOval(mRect, paint);
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
@Override
public void setAlpha(int alpha) {
paint.setAlpha(alpha);
}
@Override
public void setColorFilter(ColorFilter cf) {
paint.setColorFilter(cf);
}
}
}

View File

@ -0,0 +1,49 @@
package org.mariotaku.twidere.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.PorterDuff.Mode;
import android.util.AttributeSet;
import android.widget.ImageButton;
import org.mariotaku.twidere.R;
/**
* Created by mariotaku on 14/11/5.
*/
public class IconActionButton extends ImageButton {
private final int mColor, mActivatedColor;
public IconActionButton(Context context) {
this(context, null);
}
public IconActionButton(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public IconActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
final TypedArray defaultValues = context.obtainStyledAttributes(
new int[]{android.R.attr.colorForeground, android.R.attr.colorActivatedHighlight});
final int defaultColor = defaultValues.getColor(0, 0);
final int defaultActivatedColor = defaultValues.getColor(1, 0);
defaultValues.recycle();
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.IconActionButton);
mColor = a.getColor(R.styleable.IconActionButton_color, defaultColor);
mActivatedColor = a.getColor(R.styleable.IconActionButton_activatedColor, defaultActivatedColor);
a.recycle();
updateColorFilter();
}
@Override
public void setActivated(boolean activated) {
super.setActivated(activated);
updateColorFilter();
}
private void updateColorFilter() {
setColorFilter(isActivated() ? mActivatedColor : mColor, Mode.SRC_ATOP);
}
}

View File

@ -19,13 +19,12 @@
package org.mariotaku.twidere.view.iface;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v4.view.GravityCompat;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
@ -226,10 +225,9 @@ public interface IForegroundView {
return who == mForeground;
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public void dispatchDrawableHotspotChanged(float x, float y) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) return;
mForeground.setHotspot(x, y);
if (mForeground == null) return;
DrawableCompat.setHotspot(mForeground, x, y);
}
}
}

View File

@ -1372,6 +1372,8 @@ final class TwitterImpl extends TwitterBaseImpl implements Twitter {
final String sign_url = conf.getSigningRestBaseURL() + ENDPOINT_CONVERSATION_SHOW;
final List<HttpParameter> paramsList = new ArrayList<HttpParameter>();
paramsList.add(INCLUDE_ENTITIES);
paramsList.add(INCLUDE_REPLY_COUNT);
paramsList.add(INCLUDE_DESCENDENT_REPLY_COUNT);
paramsList.add(INCLUDE_MY_RETWEET);
paramsList.add(new HttpParameter("id", statusId));
if (paging != null) {

View File

@ -0,0 +1,179 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/element_spacing_small"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_marginRight="@dimen/element_spacing_normal"
android:layout_marginTop="@dimen/element_spacing_small"
app:cardCornerRadius="2dp"
app:cardElevation="2dp">
<LinearLayout
android:id="@+id/item_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:selectableItemBackground"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingBottom="@dimen/element_spacing_normal"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingTop="@dimen/element_spacing_normal">
<com.pkmmte.view.CircularImageView
android:id="@+id/profile_image"
android:layout_width="@dimen/icon_size_status_profile_image"
android:layout_height="@dimen/icon_size_status_profile_image"
android:layout_margin="@dimen/element_spacing_small"
android:layout_weight="0"
android:contentDescription="@string/profile_image"
android:scaleType="centerCrop"
app:border="false"
app:selector="true"
app:selector_stroke_color="@android:color/transparent"
app:selector_stroke_width="0dp"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/element_spacing_xsmall"
android:paddingTop="@dimen/element_spacing_small"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorPrimary"
android:textStyle="bold"/>
<org.mariotaku.twidere.view.ShortTimeView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/element_spacing_small"
android:paddingTop="@dimen/element_spacing_xsmall"
android:textAppearance="?android:textAppearanceSmall"/>
</LinearLayout>
<org.mariotaku.twidere.view.ActionIconButton
style="?cardActionButtonStyle"
android:layout_width="@dimen/element_size_normal"
android:layout_height="@dimen/element_size_normal"
android:layout_weight="0"
android:src="@drawable/ic_action_more_vertical"/>
</LinearLayout>
<org.mariotaku.twidere.view.ImagePreviewContainer
android:id="@+id/media_preview_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/element_spacing_small"
android:foreground="?android:selectableItemBackground">
<ImageView
android:id="@+id/media_preview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/media"
android:scaleType="centerCrop"/>
<ProgressBar
android:id="@+id/media_preview_progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="@dimen/element_spacing_large"/>
</org.mariotaku.twidere.view.ImagePreviewContainer>
<org.mariotaku.twidere.view.HandleSpanClickTextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_marginRight="@dimen/element_spacing_normal"
android:layout_marginTop="@dimen/element_spacing_small"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/element_spacing_small"
android:gravity="center_vertical"
android:orientation="horizontal">
<org.mariotaku.twidere.view.IconActionButton
android:id="@+id/reply_indicator"
style="?cardActionButtonStyle"
android:layout_width="@dimen/button_size_content_card"
android:layout_height="@dimen/button_size_content_card"
android:layout_weight="0"
android:padding="@dimen/element_spacing_small"
android:src="@drawable/ic_action_reply"
app:activatedColor="@android:color/holo_blue_light"
app:color="?android:textColorSecondary"/>
<TextView
android:id="@+id/reply_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:minWidth="@dimen/element_spacing_mlarge"/>
<org.mariotaku.twidere.view.IconActionButton
android:id="@+id/retweet_indicator"
style="?cardActionButtonStyle"
android:layout_width="@dimen/button_size_content_card"
android:layout_height="@dimen/button_size_content_card"
android:layout_weight="0"
android:padding="@dimen/element_spacing_small"
android:src="@drawable/ic_action_retweet"
app:activatedColor="@android:color/holo_green_light"
app:color="?android:textColorSecondary"/>
<TextView
android:id="@+id/retweet_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:minWidth="@dimen/element_spacing_mlarge"/>
<org.mariotaku.twidere.view.IconActionButton
android:id="@+id/favorite_indicator"
style="?cardActionButtonStyle"
android:layout_width="@dimen/button_size_content_card"
android:layout_height="@dimen/button_size_content_card"
android:layout_weight="0"
android:padding="@dimen/element_spacing_small"
android:src="@drawable/ic_action_star"
app:activatedColor="@android:color/holo_orange_light"
app:color="?android:textColorSecondary"/>
<TextView
android:id="@+id/favorite_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:minWidth="@dimen/element_spacing_mlarge"/>
</LinearLayout>
</LinearLayout>
</android.support.v7.widget.CardView>

View File

@ -0,0 +1,173 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
android:id="@+id/item_content"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:selectableItemBackground"
android:orientation="horizontal"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:paddingTop="@dimen/element_spacing_normal">
<com.pkmmte.view.CircularImageView
android:id="@+id/profile_image"
android:layout_width="@dimen/icon_size_status_profile_image"
android:layout_height="@dimen/icon_size_status_profile_image"
android:contentDescription="@string/profile_image"
android:scaleType="centerCrop"
app:border="false"
app:selector="true"
app:selector_stroke_color="@android:color/transparent"
app:selector_stroke_width="0dp"/>
<LinearLayout
android:id="@+id/status_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignTop="@id/profile_image"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_toRightOf="@+id/profile_image"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorPrimary"
android:textStyle="bold"/>
</FrameLayout>
<org.mariotaku.twidere.view.ShortTimeView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:textAppearance="?android:textAppearanceSmall"/>
</LinearLayout>
<org.mariotaku.twidere.view.ImagePreviewContainer
android:id="@+id/media_preview_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/element_spacing_small"
android:foreground="?android:selectableItemBackground">
<ImageView
android:id="@+id/media_preview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="@string/media"
android:scaleType="centerCrop"/>
<ProgressBar
android:id="@+id/media_preview_progress"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="@dimen/element_spacing_large"/>
</org.mariotaku.twidere.view.ImagePreviewContainer>
<org.mariotaku.twidere.view.HandleSpanClickTextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/element_spacing_small"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@id/status_content"
android:layout_below="@+id/status_content"
android:gravity="center_vertical"
android:layout_marginTop="@dimen/element_spacing_small"
android:orientation="horizontal">
<org.mariotaku.twidere.view.IconActionButton
android:id="@+id/reply_indicator"
style="?cardActionButtonStyle"
android:layout_width="@dimen/button_size_content_card"
android:layout_height="@dimen/button_size_content_card"
android:layout_weight="0"
android:padding="@dimen/element_spacing_small"
android:src="@drawable/ic_action_reply"
app:activatedColor="@android:color/holo_blue_light"
app:color="?android:textColorSecondary"/>
<TextView
android:id="@+id/reply_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:minWidth="@dimen/element_spacing_mlarge"/>
<org.mariotaku.twidere.view.IconActionButton
android:id="@+id/retweet_indicator"
style="?cardActionButtonStyle"
android:layout_width="@dimen/button_size_content_card"
android:layout_height="@dimen/button_size_content_card"
android:layout_weight="0"
android:padding="@dimen/element_spacing_small"
android:src="@drawable/ic_action_retweet"
app:activatedColor="@android:color/holo_green_light"
app:color="?android:textColorSecondary"/>
<TextView
android:id="@+id/retweet_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:minWidth="@dimen/element_spacing_mlarge"/>
<org.mariotaku.twidere.view.IconActionButton
android:id="@+id/favorite_indicator"
style="?cardActionButtonStyle"
android:layout_width="@dimen/button_size_content_card"
android:layout_height="@dimen/button_size_content_card"
android:layout_weight="0"
android:padding="@dimen/element_spacing_small"
android:src="@drawable/ic_action_star"
app:activatedColor="@android:color/holo_orange_light"
app:color="?android:textColorSecondary"/>
<TextView
android:id="@+id/favorite_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:minWidth="@dimen/element_spacing_mlarge"/>
<Space
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"/>
<org.mariotaku.twidere.view.ActionIconButton
style="?cardActionButtonStyle"
android:layout_width="@dimen/button_size_content_card"
android:layout_height="@dimen/button_size_content_card"
android:layout_weight="0"
android:src="@drawable/ic_action_more_horizontal"/>
</LinearLayout>
</RelativeLayout>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ProgressBar
android:layout_margin="@dimen/element_spacing_normal"
style="?android:progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"/>
</FrameLayout>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Widget.CardActionButton" parent="android:Widget.DeviceDefault.ImageButton">
<item name="android:background">?android:selectableItemBackgroundBorderless</item>
</style>
<style name="Widget.Light.CardActionButton" parent="android:Widget.DeviceDefault.ImageButton">
<item name="android:background">?android:selectableItemBackgroundBorderless</item>
</style>
</resources>

View File

@ -2,6 +2,7 @@
<resources>
<declare-styleable name="Twidere">
<attr name="cardActionButtonStyle" format="reference"/>
<attr name="cardItemBackground" format="reference"/>
<attr name="cardItemBackgroundColor" format="color"/>
<attr name="cardItemMessageIncomingBackground" format="reference"/>
@ -67,6 +68,10 @@
<declare-styleable name="AssetFontTextView">
<attr name="fontPath" format="string"/>
</declare-styleable>
<declare-styleable name="IconActionButton">
<attr name="color" format="color"/>
<attr name="activatedColor" format="color"/>
</declare-styleable>
<attr name="notificationType">
<flag name="none" value="0"/>
<flag name="ringtone" value="1"/>

View File

@ -2,6 +2,7 @@
<resources>
<dimen name="element_size_normal">48dp</dimen>
<dimen name="button_size_content_card">42dp</dimen>
<dimen name="element_size_small">24dp</dimen>
<dimen name="element_spacing_xsmall">2dp</dimen>
<dimen name="element_spacing_small">4dp</dimen>
@ -72,5 +73,6 @@
<dimen name="action_icon_size">32dp</dimen>
<dimen name="unread_indicator_size">16dp</dimen>
<dimen name="account_selector_popup_width">180dp</dimen>
<dimen name="icon_size_status_profile_image">48dp</dimen>
</resources>

View File

@ -147,4 +147,11 @@
<item name="column_count_landscape">@integer/staggered_grid_columns_land</item>
</style>
<style name="Widget.CardActionButton" parent="android:Widget.DeviceDefault.ImageButton">
<item name="android:background">?android:selectableItemBackground</item>
</style>
<style name="Widget.Light.CardActionButton" parent="android:Widget.DeviceDefault.ImageButton">
<item name="android:background">?android:selectableItemBackground</item>
</style>
</resources>

View File

@ -38,6 +38,7 @@
<item name="staggeredGridViewStyle">@style/Widget.StaggeredGridView</item>
<!-- Card UI styles -->
<item name="cardActionButtonStyle">@style/Widget.CardActionButton</item>
<item name="cardItemBackground">@drawable/bg_card_item_dark</item>
<item name="cardItemBackgroundColor">#1a1a1a</item>
<item name="cardItemMessageIncomingBackground">
@ -81,6 +82,7 @@
<item name="staggeredGridViewStyle">@style/Widget.StaggeredGridView</item>
<!-- Card UI styles -->
<item name="cardActionButtonStyle">@style/Widget.Light.CardActionButton</item>
<item name="cardItemBackground">@drawable/bg_card_item_light</item>
<item name="cardItemBackgroundColor">#f8f8f8</item>
<item name="cardItemMessageIncomingBackground">
@ -150,6 +152,7 @@
<item name="staggeredGridViewStyle">@style/Widget.StaggeredGridView</item>
<!-- Card UI styles -->
<item name="cardActionButtonStyle">@style/Widget.CardActionButton</item>
<item name="cardItemBackground">@drawable/bg_card_item_dark</item>
<item name="cardItemBackgroundColor">#1a1a1a</item>
<item name="cardItemMessageIncomingBackground">
@ -178,6 +181,7 @@
<item name="staggeredGridViewStyle">@style/Widget.StaggeredGridView</item>
<!-- Card UI styles -->
<item name="cardActionButtonStyle">@style/Widget.Light.CardActionButton</item>
<item name="cardItemBackground">@drawable/bg_card_item_light</item>
<item name="cardItemBackgroundColor">#f8f8f8</item>
<item name="cardItemMessageIncomingBackground">
@ -235,6 +239,7 @@
<item name="android:actionBarStyle">@style/Widget.Twidere.Viewer.ActionBar</item>
<!-- Card UI styles -->
<item name="cardActionButtonStyle">@style/Widget.CardActionButton</item>
<item name="cardItemBackground">@drawable/bg_card_item_dark</item>
<item name="cardItemBackgroundColor">#1a1a1a</item>
<item name="cardItemMessageIncomingBackground">
@ -332,6 +337,7 @@
<item name="tabItemTextStyle">@style/Widget.TabPageIndicator.TabItem.TextView.Dark</item>
<!-- Card UI styles -->
<item name="cardActionButtonStyle">@style/Widget.CardActionButton</item>
<item name="cardItemBackground">@drawable/bg_card_item_dark</item>
<item name="cardItemBackgroundColor">#1a1a1a</item>
<item name="cardItemMessageIncomingBackground">
@ -366,6 +372,7 @@
<item name="tabItemTextStyle">@style/Widget.TabPageIndicator.TabItem.TextView.Light</item>
<!-- Card UI styles -->
<item name="cardActionButtonStyle">@style/Widget.Light.CardActionButton</item>
<item name="cardItemBackground">@drawable/bg_card_item_light</item>
<item name="cardItemBackgroundColor">#f8f8f8</item>
<item name="cardItemMessageIncomingBackground">
@ -400,6 +407,7 @@
<item name="tabItemTextStyle">@style/Widget.TabPageIndicator.TabItem.TextView.Light</item>
<!-- Card UI styles -->
<item name="cardActionButtonStyle">@style/Widget.Light.CardActionButton</item>
<item name="cardItemBackground">@drawable/bg_card_item_light</item>
<item name="cardItemBackgroundColor">#f8f8f8</item>
<item name="cardItemMessageIncomingBackground">

View File

@ -1,33 +1,37 @@
<?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:key="settings_storage"
android:title="@string/storage">
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:key="settings_storage"
android:title="@string/storage">
<PreferenceCategory
android:key="category_storage"
android:title="@string/storage">
<org.mariotaku.twidere.preference.SeekBarDialogPreference
android:defaultValue="100"
android:key="database_item_limit"
android:summary="@string/database_item_limit_summary"
android:title="@string/database_item_limit"
app:max="500"
app:min="50"/>
<PreferenceCategory
android:key="category_storage"
android:title="@string/storage">
<org.mariotaku.twidere.preference.ClearSearchHistoryPreference
android:key="clear_search_history"
android:title="@string/clear_search_history"/>
<org.mariotaku.twidere.preference.SeekBarDialogPreference
android:defaultValue="100"
android:key="database_item_limit"
android:summary="@string/database_item_limit_summary"
android:title="@string/database_item_limit"
app:max="500"
app:min="50"
app:step="10"/>
<org.mariotaku.twidere.preference.ClearCachePreference
android:key="clear_cache"
android:summary="@string/clear_cache_summary"
android:title="@string/clear_cache"/>
<org.mariotaku.twidere.preference.ClearSearchHistoryPreference
android:key="clear_search_history"
android:title="@string/clear_search_history"/>
<org.mariotaku.twidere.preference.ClearDatabasesPreference
android:key="clear_databases"
android:summary="@string/clear_databases_summary"
android:title="@string/clear_databases"/>
</PreferenceCategory>
<org.mariotaku.twidere.preference.ClearCachePreference
android:key="clear_cache"
android:summary="@string/clear_cache_summary"
android:title="@string/clear_cache"/>
<org.mariotaku.twidere.preference.ClearDatabasesPreference
android:key="clear_databases"
android:summary="@string/clear_databases_summary"
android:title="@string/clear_databases"/>
</PreferenceCategory>
</PreferenceScreen>