redesigning status fragment, now you can see official client like tweet list in tweet details

This commit is contained in:
Mariotaku Lee 2014-12-06 22:40:22 +08:00
parent 55c33033b1
commit 048de51d4d
40 changed files with 4819 additions and 1481 deletions

View File

@ -0,0 +1,32 @@
/*
* 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 android.support.v7.widget;
import android.support.v7.widget.RecyclerView.ViewHolder;
/**
* Created by mariotaku on 14/12/6.
*/
public class ViewHolderTrojan {
public static boolean isRemoved(ViewHolder holder) {
return holder.isRemoved();
}
}

View File

@ -28,7 +28,7 @@ package org.mariotaku.twidere;
public interface Constants extends TwidereConstants {
public static final String DATABASES_NAME = "twidere.sqlite";
public static final int DATABASES_VERSION = 74;
public static final int DATABASES_VERSION = 75;
public static final int MENU_GROUP_STATUS_EXTENSION = 10;
public static final int MENU_GROUP_COMPOSE_EXTENSION = 11;

View File

@ -14,7 +14,6 @@ import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.iface.IStatusesAdapter;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.fragment.support.StatusMenuDialogFragment;
import org.mariotaku.twidere.fragment.support.UserFragment;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.util.ImageLoaderWrapper;
@ -30,9 +29,9 @@ import org.mariotaku.twidere.view.holder.StatusViewHolder;
public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implements Constants,
IStatusesAdapter<D> {
private static final int ITEM_VIEW_TYPE_STATUS = 1;
private static final int ITEM_VIEW_TYPE_GAP = 2;
private static final int ITEM_VIEW_TYPE_LOAD_INDICATOR = 3;
private static final int ITEM_VIEW_TYPE_STATUS = 0;
private static final int ITEM_VIEW_TYPE_GAP = 1;
private static final int ITEM_VIEW_TYPE_LOAD_INDICATOR = 2;
private final Context mContext;
private final LayoutInflater mInflater;
@ -49,9 +48,9 @@ public abstract class AbsStatusesAdapter<D> extends Adapter<ViewHolder> implemen
mImageLoader = TwidereApplication.getInstance(context).getImageLoaderWrapper();
mLoadingHandler = new ImageLoadingHandler(R.id.media_preview_progress);
if (compact) {
mCardLayoutResource = R.layout.card_item_list_status_compat;
mCardLayoutResource = R.layout.card_item_status_compat;
} else {
mCardLayoutResource = R.layout.card_item_list_status;
mCardLayoutResource = R.layout.card_item_status;
}
}

View File

@ -357,7 +357,7 @@ public class CursorStatusesListAdapter extends BaseCursorAdapter implements ISta
}
private static int getItemResource(final boolean compactCards) {
return compactCards ? R.layout.card_item_list_status_compat : R.layout.card_item_list_status;
return compactCards ? R.layout.card_item_status_compat : R.layout.card_item_status;
}
private static boolean moveCursorToLast(final Cursor c) {

View File

@ -341,7 +341,7 @@ public class ParcelableStatusesListAdapter extends BaseArrayAdapter<ParcelableSt
}
private static int getItemResource(final boolean compactCards) {
return compactCards ? R.layout.card_item_list_status_compat : R.layout.card_item_list_status;
return compactCards ? R.layout.card_item_status_compat : R.layout.card_item_status;
}
}

View File

@ -366,7 +366,7 @@ public class UserFragment extends BaseSupportFragment implements OnClickListener
mProgressContainer.setVisibility(View.GONE);
mUser = user;
final int userColor = getUserColor(getActivity(), user.id, true);
mProfileImageView.setBorderColor(userColor);
mProfileImageView.setBorderColor(userColor != 0 ? userColor : Color.WHITE);
mProfileNameContainer.drawEnd(getAccountColor(getActivity(), user.account_id));
final String nick = getUserNickname(getActivity(), user.id, true);
mNameView

View File

@ -0,0 +1,70 @@
/*
* 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.loader;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.content.AsyncTaskLoader;
import org.mariotaku.twidere.constant.IntentConstants;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.model.SingleResponse;
import twitter4j.TwitterException;
import static org.mariotaku.twidere.util.Utils.findStatus;
/**
* Created by mariotaku on 14/12/5.
*/
public class ParcelableStatusLoader extends AsyncTaskLoader<SingleResponse<ParcelableStatus>> {
private final boolean mOmitIntentExtra;
private final Bundle mExtras;
private final long mAccountId, mStatusId;
public ParcelableStatusLoader(final Context context, final boolean omitIntentExtra, final Bundle extras,
final long accountId, final long statusId) {
super(context);
mOmitIntentExtra = omitIntentExtra;
mExtras = extras;
mAccountId = accountId;
mStatusId = statusId;
}
@Override
public SingleResponse<ParcelableStatus> loadInBackground() {
if (!mOmitIntentExtra && mExtras != null) {
final ParcelableStatus cache = mExtras.getParcelable(IntentConstants.EXTRA_STATUS);
if (cache != null) return SingleResponse.getInstance(cache);
}
try {
return SingleResponse.getInstance(findStatus(getContext(), mAccountId, mStatusId));
} catch (final TwitterException e) {
return SingleResponse.getInstance(e);
}
}
@Override
protected void onStartLoading() {
forceLoad();
}
}

View File

@ -19,54 +19,53 @@
package org.mariotaku.twidere.loader.support;
import static org.mariotaku.twidere.util.Utils.isOfficialTwitterInstance;
import static org.mariotaku.twidere.util.Utils.shouldForceUsingPrivateAPIs;
import android.content.Context;
import org.mariotaku.twidere.model.ParcelableStatus;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import twitter4j.Paging;
import twitter4j.Status;
import twitter4j.Twitter;
import twitter4j.TwitterException;
import java.util.ArrayList;
import java.util.List;
import static org.mariotaku.twidere.util.Utils.isOfficialTwitterInstance;
import static org.mariotaku.twidere.util.Utils.shouldForceUsingPrivateAPIs;
public class StatusRepliesLoader extends UserMentionsLoader {
private final long mInReplyToStatusId;
private final long mInReplyToStatusId;
public StatusRepliesLoader(final Context context, final long accountId, final String screenName,
final long statusId, final long maxId, final long sinceId, final List<ParcelableStatus> data,
final String[] savedStatusesArgs, final int tabPosition) {
super(context, accountId, screenName, maxId, sinceId, data, savedStatusesArgs, tabPosition);
mInReplyToStatusId = statusId;
}
public StatusRepliesLoader(final Context context, final long accountId, final String screenName,
final long statusId, final long maxId, final long sinceId, final List<ParcelableStatus> data,
final String[] savedStatusesArgs, final int tabPosition) {
super(context, accountId, screenName, maxId, sinceId, data, savedStatusesArgs, tabPosition);
mInReplyToStatusId = statusId;
}
@Override
public List<Status> getStatuses(final Twitter twitter, final Paging paging) throws TwitterException {
final Context context = getContext();
if (shouldForceUsingPrivateAPIs(context) || isOfficialTwitterInstance(context, twitter)) {
final List<Status> statuses = twitter.showConversation(mInReplyToStatusId, paging);
final List<Status> result = new ArrayList<Status>();
for (final Status status : statuses) {
if (status.getId() > mInReplyToStatusId) {
result.add(status);
}
}
return result;
} else {
final List<Status> statuses = super.getStatuses(twitter, paging);
final List<Status> result = new ArrayList<Status>();
for (final Status status : statuses) {
if (status.getInReplyToStatusId() == mInReplyToStatusId) {
result.add(status);
}
}
return result;
}
}
@Override
public List<Status> getStatuses(final Twitter twitter, final Paging paging) throws TwitterException {
final Context context = getContext();
final List<Status> result = new ArrayList<>();
if (shouldForceUsingPrivateAPIs(context) || isOfficialTwitterInstance(context, twitter)) {
final List<Status> statuses = twitter.showConversation(mInReplyToStatusId, paging);
for (final Status status : statuses) {
if (status.getId() > mInReplyToStatusId) {
result.add(status);
}
}
} else {
final List<Status> statuses = super.getStatuses(twitter, paging);
for (final Status status : statuses) {
if (status.getInReplyToStatusId() == mInReplyToStatusId) {
result.add(status);
}
}
}
return result;
}
}

View File

@ -34,6 +34,7 @@ import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
@ -53,6 +54,7 @@ public abstract class Twitter4JStatusesLoader extends ParcelableStatusesLoader {
private final SQLiteDatabase mDatabase;
private final Handler mHandler;
private final Object[] mSavedStatusesFileArgs;
private Comparator<ParcelableStatus> mComparator;
public Twitter4JStatusesLoader(final Context context, final long account_id, final long max_id,
final long since_id, final List<ParcelableStatus> data, final String[] savedStatusesArgs,
@ -76,7 +78,11 @@ public abstract class Twitter4JStatusesLoader extends ParcelableStatusesLoader {
final List<ParcelableStatus> cached = getCachedData(serializationFile);
if (cached != null) {
data.addAll(cached);
Collections.sort(data);
if (mComparator != null) {
Collections.sort(data, mComparator);
} else {
Collections.sort(data);
}
return new CopyOnWriteArrayList<>(data);
}
}
@ -109,7 +115,6 @@ public abstract class Twitter4JStatusesLoader extends ParcelableStatusesLoader {
final boolean deleted = deleteStatus(data, id);
data.add(new ParcelableStatus(status, mAccountId, minStatusId == id && insertGap && !deleted));
}
Collections.sort(data);
final ParcelableStatus[] array = data.toArray(new ParcelableStatus[data.size()]);
for (int i = 0, size = array.length; i < size; i++) {
final ParcelableStatus status = array[i];
@ -117,10 +122,19 @@ public abstract class Twitter4JStatusesLoader extends ParcelableStatusesLoader {
deleteStatus(data, status.id);
}
}
if (mComparator != null) {
Collections.sort(data, mComparator);
} else {
Collections.sort(data);
}
saveCachedData(serializationFile, data);
return new CopyOnWriteArrayList<>(data);
}
public final void setComparator(Comparator<ParcelableStatus> comparator) {
mComparator = comparator;
}
protected abstract List<Status> getStatuses(Twitter twitter, Paging paging) throws TwitterException;
protected final Twitter getTwitter() {

View File

@ -25,16 +25,24 @@ import java.util.List;
public class ListResponse<Data> extends SingleResponse<List<Data>> {
public final List<Data> list;
public final List<Data> list;
public ListResponse(final List<Data> list, final Exception exception) {
super(list, exception);
this.list = list;
}
public ListResponse(final List<Data> list, final Exception exception) {
super(list, exception);
this.list = list;
}
public ListResponse(final List<Data> list, final Exception exception, final Bundle extras) {
super(list, exception, extras);
this.list = list;
}
public ListResponse(final List<Data> list, final Exception exception, final Bundle extras) {
super(list, exception, extras);
this.list = list;
}
public static <Data> ListResponse<Data> getListInstance(Exception exception) {
return new ListResponse<>(null, exception);
}
public static <Data> ListResponse<Data> getListInstance(List<Data> data) {
return new ListResponse<>(data, null);
}
}

View File

@ -85,18 +85,18 @@ public class SingleResponse<Data> {
}
public static <T> SingleResponse<T> getInstance() {
return new SingleResponse<T>(null, null);
return new SingleResponse<>(null, null);
}
public static <T> SingleResponse<T> getInstance(final Exception exception) {
return new SingleResponse<T>(null, exception);
return new SingleResponse<>(null, exception);
}
public static <T> SingleResponse<T> getInstance(final T data) {
return new SingleResponse<T>(data, null);
return new SingleResponse<>(data, null);
}
public static <T> SingleResponse<T> getInstance(final T data, final Exception exception) {
return new SingleResponse<T>(data, exception);
return new SingleResponse<>(data, exception);
}
}

View File

@ -136,8 +136,8 @@ public class CardPreviewPreference extends Preference implements Constants, OnSh
@Override
protected View onCreateView(final ViewGroup parent) {
if (mPreferences != null && mPreferences.getBoolean(KEY_COMPACT_CARDS, false))
return mInflater.inflate(R.layout.card_item_status_compact, parent, false);
return mInflater.inflate(R.layout.card_item_status, parent, false);
return mInflater.inflate(R.layout.card_item_status_compact_deprecated, parent, false);
return mInflater.inflate(R.layout.card_item_status_deprecated, parent, false);
}
}

View File

@ -771,10 +771,11 @@ public interface TweetStore {
public static final String POSITION = "position";
public static final String[] COLUMNS = new String[]{_ID, NAME, ICON, TYPE, ARGUMENTS, EXTRAS, POSITION};
public static final String[] COLUMNS = new String[]{_ID, NAME, ICON, TYPE, ARGUMENTS, EXTRAS,
POSITION};
public static final String[] TYPES = new String[]{TYPE_PRIMARY_KEY, TYPE_TEXT_NOT_NULL, TYPE_TEXT, TYPE_TEXT,
TYPE_TEXT, TYPE_TEXT, TYPE_INT};
public static final String[] TYPES = new String[]{TYPE_PRIMARY_KEY, TYPE_TEXT, TYPE_TEXT,
TYPE_TEXT_NOT_NULL, TYPE_TEXT, TYPE_TEXT, TYPE_INT};
public static final String DEFAULT_SORT_ORDER = POSITION + " ASC";
}

View File

@ -1128,21 +1128,22 @@ public final class Utils implements Constants, TwitterConstants {
return message;
}
public static ParcelableStatus findStatus(final Context context, final long account_id, final long status_id)
@NonNull
public static ParcelableStatus findStatus(final Context context, final long accountId, final long statusId)
throws TwitterException {
if (context == null || account_id <= 0 || status_id <= 0) return null;
final ParcelableStatus p_status = findStatusInDatabases(context, account_id, status_id);
if (p_status != null) return p_status;
final Twitter twitter = getTwitterInstance(context, account_id, true);
if (twitter == null) return null;
final Status status = twitter.showStatus(status_id);
if (status == null || status.getId() <= 0) return null;
final String where = Statuses.ACCOUNT_ID + " = " + account_id + " AND " + Statuses.STATUS_ID + " = "
+ status.getId();
if (context == null) throw new NullPointerException();
final ParcelableStatus cached = findStatusInDatabases(context, accountId, statusId);
if (cached != null) return cached;
final Twitter twitter = getTwitterInstance(context, accountId, true);
if (twitter == null) throw new TwitterException("Account does not exist");
final Status status = twitter.showStatus(statusId);
final String where = Expression.and(Expression.equals(Statuses.ACCOUNT_ID, accountId),
Expression.equals(Statuses.STATUS_ID, statusId)).getSQL();
final ContentResolver resolver = context.getContentResolver();
resolver.delete(CachedStatuses.CONTENT_URI, where, null);
resolver.insert(CachedStatuses.CONTENT_URI, ContentValuesCreator.makeStatusContentValues(status, account_id));
return new ParcelableStatus(status, account_id, false);
resolver.insert(CachedStatuses.CONTENT_URI,
ContentValuesCreator.makeStatusContentValues(status, accountId));
return new ParcelableStatus(status, accountId, false);
}
public static ParcelableStatus findStatusInDatabases(final Context context, final long account_id,
@ -3503,7 +3504,16 @@ public final class Utils implements Constants, TwitterConstants {
scrollListToPosition(list, 0);
}
public static void setMenuForStatus(final Context context, final Menu menu, final ParcelableStatus status) {
public static void setMenuForStatus(final Context context, final Menu menu,
final ParcelableStatus status) {
final ParcelableAccountWithCredentials account
= ParcelableAccount.getAccountWithCredentials(context, status.account_id);
setMenuForStatus(context, menu, status, account);
}
public static void setMenuForStatus(final Context context, final Menu menu,
final ParcelableStatus status,
final ParcelableAccountWithCredentials account) {
if (context == null || menu == null || status == null) return;
final Resources resources = context.getResources();
final int retweetHighlight = resources.getColor(R.color.highlight_retweet);
@ -3531,7 +3541,6 @@ public final class Utils implements Constants, TwitterConstants {
}
final MenuItem translate = menu.findItem(MENU_TRANSLATE);
if (translate != null) {
final ParcelableAccountWithCredentials account = ParcelableAccount.getAccountWithCredentials(context, status.account_id);
final boolean isOfficialKey = ParcelableAccountWithCredentials.isOfficialCredentials(context, account);
setMenuItemAvailability(menu, MENU_TRANSLATE, isOfficialKey);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,363 @@
/*
* 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.util.layout;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.LinearLayout;
/**
* Helper class for LayoutManagers to abstract measurements depending on the View's orientation.
* <p/>
* It is developed to easily support vertical and horizontal orientations in a LayoutManager but
* can also be used to abstract calls around view bounds and child measurements with margins and
* decorations.
*
* @see #createHorizontalHelper(RecyclerView.LayoutManager)
* @see #createVerticalHelper(RecyclerView.LayoutManager)
*/
public abstract class OrientationHelper {
private static final int INVALID_SIZE = Integer.MIN_VALUE;
protected final RecyclerView.LayoutManager mLayoutManager;
public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
public static final int VERTICAL = LinearLayout.VERTICAL;
private int mLastTotalSpace = INVALID_SIZE;
private OrientationHelper(RecyclerView.LayoutManager layoutManager) {
mLayoutManager = layoutManager;
}
/**
* Call this method after onLayout method is complete if state is NOT pre-layout.
* This method records information like layout bounds that might be useful in the next layout
* calculations.
*/
public void onLayoutComplete() {
mLastTotalSpace = getTotalSpace();
}
/**
* Returns the layout space change between the previous layout pass and current layout pass.
* <p/>
* Make sure you call {@link #onLayoutComplete()} at the end of your LayoutManager's
* {@link RecyclerView.LayoutManager#onLayoutChildren(RecyclerView.Recycler,
* RecyclerView.State)} method.
*
* @return The difference between the current total space and previous layout's total space.
* @see #onLayoutComplete()
*/
public int getTotalSpaceChange() {
return INVALID_SIZE == mLastTotalSpace ? 0 : getTotalSpace() - mLastTotalSpace;
}
/**
* Returns the start of the view including its decoration and margin.
* <p/>
* For example, for the horizontal helper, if a View's left is at pixel 20, has 2px left
* decoration and 3px left margin, returned value will be 15px.
*
* @param view The view element to check
* @return The first pixel of the element
* @see #getDecoratedEnd(android.view.View)
*/
public abstract int getDecoratedStart(View view);
/**
* Returns the end of the view including its decoration and margin.
* <p/>
* For example, for the horizontal helper, if a View's right is at pixel 200, has 2px right
* decoration and 3px right margin, returned value will be 205.
*
* @param view The view element to check
* @return The last pixel of the element
* @see #getDecoratedStart(android.view.View)
*/
public abstract int getDecoratedEnd(View view);
/**
* Returns the space occupied by this View in the current orientation including decorations and
* margins.
*
* @param view The view element to check
* @return Total space occupied by this view
* @see #getDecoratedMeasurementInOther(View)
*/
public abstract int getDecoratedMeasurement(View view);
/**
* Returns the space occupied by this View in the perpendicular orientation including
* decorations and margins.
*
* @param view The view element to check
* @return Total space occupied by this view in the perpendicular orientation to current one
* @see #getDecoratedMeasurement(View)
*/
public abstract int getDecoratedMeasurementInOther(View view);
/**
* Returns the start position of the layout after the start padding is added.
*
* @return The very first pixel we can draw.
*/
public abstract int getStartAfterPadding();
/**
* Returns the end position of the layout after the end padding is removed.
*
* @return The end boundary for this layout.
*/
public abstract int getEndAfterPadding();
/**
* Returns the end position of the layout without taking padding into account.
*
* @return The end boundary for this layout without considering padding.
*/
public abstract int getEnd();
/**
* Offsets all children's positions by the given amount.
*
* @param amount Value to add to each child's layout parameters
*/
public abstract void offsetChildren(int amount);
/**
* Returns the total space to layout. This number is the difference between
* {@link #getEndAfterPadding()} and {@link #getStartAfterPadding()}.
*
* @return Total space to layout children
*/
public abstract int getTotalSpace();
/**
* Offsets the child in this orientation.
*
* @param view View to offset
* @param offset offset amount
*/
public abstract void offsetChild(View view, int offset);
/**
* Returns the padding at the end of the layout. For horizontal helper, this is the right
* padding and for vertical helper, this is the bottom padding. This method does not check
* whether the layout is RTL or not.
*
* @return The padding at the end of the layout.
*/
public abstract int getEndPadding();
/**
* Creates an OrientationHelper for the given LayoutManager and orientation.
*
* @param layoutManager LayoutManager to attach to
* @param orientation Desired orientation. Should be {@link #HORIZONTAL} or {@link #VERTICAL}
* @return A new OrientationHelper
*/
public static OrientationHelper createOrientationHelper(
RecyclerView.LayoutManager layoutManager, int orientation) {
switch (orientation) {
case HORIZONTAL:
return createHorizontalHelper(layoutManager);
case VERTICAL:
return createVerticalHelper(layoutManager);
}
throw new IllegalArgumentException("invalid orientation");
}
/**
* Creates a horizontal OrientationHelper for the given LayoutManager.
*
* @param layoutManager The LayoutManager to attach to.
* @return A new OrientationHelper
*/
public static OrientationHelper createHorizontalHelper(
RecyclerView.LayoutManager layoutManager) {
return new OrientationHelper(layoutManager) {
@Override
public int getEndAfterPadding() {
return mLayoutManager.getWidth() - mLayoutManager.getPaddingRight();
}
@Override
public int getEnd() {
return mLayoutManager.getWidth();
}
@Override
public void offsetChildren(int amount) {
mLayoutManager.offsetChildrenHorizontal(amount);
}
@Override
public int getStartAfterPadding() {
return mLayoutManager.getPaddingLeft();
}
@Override
public int getDecoratedMeasurement(View view) {
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
view.getLayoutParams();
return mLayoutManager.getDecoratedMeasuredWidth(view) + params.leftMargin
+ params.rightMargin;
}
@Override
public int getDecoratedMeasurementInOther(View view) {
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
view.getLayoutParams();
return mLayoutManager.getDecoratedMeasuredHeight(view) + params.topMargin
+ params.bottomMargin;
}
@Override
public int getDecoratedEnd(View view) {
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
view.getLayoutParams();
return mLayoutManager.getDecoratedRight(view) + params.rightMargin;
}
@Override
public int getDecoratedStart(View view) {
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
view.getLayoutParams();
return mLayoutManager.getDecoratedLeft(view) - params.leftMargin;
}
@Override
public int getTotalSpace() {
return mLayoutManager.getWidth() - mLayoutManager.getPaddingLeft()
- mLayoutManager.getPaddingRight();
}
@Override
public void offsetChild(View view, int offset) {
view.offsetLeftAndRight(offset);
}
@Override
public int getEndPadding() {
return mLayoutManager.getPaddingRight();
}
};
}
/**
* Creates a vertical OrientationHelper for the given LayoutManager.
*
* @param layoutManager The LayoutManager to attach to.
* @return A new OrientationHelper
*/
public static OrientationHelper createVerticalHelper(RecyclerView.LayoutManager layoutManager) {
return new OrientationHelper(layoutManager) {
int diff;
@Override
public int getEndAfterPadding() {
int heightSum = 0;
for (int i = 0, j = mLayoutManager.getChildCount(); i < j; i++) {
final View child = mLayoutManager.getChildAt(i);
if (mLayoutManager.getItemViewType(child) == 0 || heightSum != 0) {
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
child.getLayoutParams();
heightSum += mLayoutManager.getDecoratedMeasuredHeight(child)
+ params.topMargin + params.bottomMargin;
}
}
final int normalEnd = mLayoutManager.getHeight() - mLayoutManager.getPaddingBottom();
if (heightSum == 0) {
diff = 0;
return normalEnd;
}
diff = (mLayoutManager.getPaddingTop() + heightSum) - normalEnd;
// return normalEnd;
return Math.min(mLayoutManager.getPaddingTop() + heightSum, normalEnd);
}
@Override
public int getEnd() {
return mLayoutManager.getHeight() + Math.max(0, diff);
}
@Override
public void offsetChildren(int amount) {
mLayoutManager.offsetChildrenVertical(amount);
}
@Override
public int getStartAfterPadding() {
return mLayoutManager.getPaddingTop();
}
@Override
public int getDecoratedMeasurement(View view) {
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
view.getLayoutParams();
return mLayoutManager.getDecoratedMeasuredHeight(view) + params.topMargin
+ params.bottomMargin;
}
@Override
public int getDecoratedMeasurementInOther(View view) {
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
view.getLayoutParams();
return mLayoutManager.getDecoratedMeasuredWidth(view) + params.leftMargin
+ params.rightMargin;
}
@Override
public int getDecoratedEnd(View view) {
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
view.getLayoutParams();
return mLayoutManager.getDecoratedBottom(view) + params.bottomMargin;
}
@Override
public int getDecoratedStart(View view) {
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
view.getLayoutParams();
return mLayoutManager.getDecoratedTop(view) - params.topMargin;
}
@Override
public int getTotalSpace() {
return mLayoutManager.getHeight() - mLayoutManager.getPaddingTop()
- mLayoutManager.getPaddingBottom();
}
@Override
public void offsetChild(View view, int offset) {
view.offsetTopAndBottom(offset);
mLayoutManager.requestLayout();
}
@Override
public int getEndPadding() {
return mLayoutManager.getPaddingBottom();
}
};
}
}

View File

@ -0,0 +1,99 @@
/*
* 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.util.layout;
import android.support.v7.widget.RecyclerView;
import android.view.View;
/**
* A helper class to do scroll offset calculations.
*/
class ScrollbarHelper {
/**
* @param startChild View closest to start of the list. (top or left)
* @param endChild View closest to end of the list (bottom or right)
*/
static int computeScrollOffset(RecyclerView.State state, OrientationHelper orientation,
View startChild, View endChild, RecyclerView.LayoutManager lm,
boolean smoothScrollbarEnabled, boolean reverseLayout) {
if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null ||
endChild == null) {
return 0;
}
final int minPosition = Math.min(lm.getPosition(startChild), lm.getPosition(endChild));
final int maxPosition = Math.max(lm.getPosition(startChild), lm.getPosition(endChild));
final int itemsBefore = reverseLayout
? Math.max(0, state.getItemCount() - maxPosition - 1)
: Math.max(0, minPosition);
if (!smoothScrollbarEnabled) {
return itemsBefore;
}
final int laidOutArea = Math.abs(orientation.getDecoratedEnd(endChild) -
orientation.getDecoratedStart(startChild));
final int itemRange = Math.abs(lm.getPosition(startChild) - lm.getPosition(endChild)) + 1;
final float avgSizePerRow = (float) laidOutArea / itemRange;
return Math.round(itemsBefore * avgSizePerRow + (orientation.getStartAfterPadding()
- orientation.getDecoratedStart(startChild)));
}
/**
* @param startChild View closest to start of the list. (top or left)
* @param endChild View closest to end of the list (bottom or right)
*/
static int computeScrollExtent(RecyclerView.State state, OrientationHelper orientation,
View startChild, View endChild, RecyclerView.LayoutManager lm,
boolean smoothScrollbarEnabled) {
if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null ||
endChild == null) {
return 0;
}
if (!smoothScrollbarEnabled) {
return Math.abs(lm.getPosition(startChild) - lm.getPosition(endChild)) + 1;
}
final int extend = orientation.getDecoratedEnd(endChild)
- orientation.getDecoratedStart(startChild);
return Math.min(orientation.getTotalSpace(), extend);
}
/**
* @param startChild View closest to start of the list. (top or left)
* @param endChild View closest to end of the list (bottom or right)
*/
static int computeScrollRange(RecyclerView.State state, OrientationHelper orientation,
View startChild, View endChild, RecyclerView.LayoutManager lm,
boolean smoothScrollbarEnabled) {
if (lm.getChildCount() == 0 || state.getItemCount() == 0 || startChild == null ||
endChild == null) {
return 0;
}
if (!smoothScrollbarEnabled) {
return state.getItemCount();
}
// smooth scrollbar enabled. try to estimate better.
final int laidOutArea = orientation.getDecoratedEnd(endChild) -
orientation.getDecoratedStart(startChild);
final int laidOutRange = Math.abs(lm.getPosition(startChild) - lm.getPosition(endChild))
+ 1;
// estimate a size for full list.
return (int) ((float) laidOutArea / laidOutRange * state.getItemCount());
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 964 B

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

View File

@ -1,232 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
android:id="@+id/card"
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:cardBackgroundColor="?cardItemBackgroundColor"
app:cardCornerRadius="2dp"
app:cardElevation="2dp">
<RelativeLayout
android:id="@+id/item_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:selectableItemBackground"
android:orientation="vertical">
<org.mariotaku.twidere.view.CircularImageView
android:id="@+id/retweet_profile_image"
android:layout_width="@dimen/element_size_small"
android:layout_height="@dimen/element_size_small"
android:layout_marginBottom="@dimen/element_spacing_small"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_marginTop="@dimen/element_spacing_small"
android:scaleType="centerCrop"/>
<org.mariotaku.twidere.view.ActionIconTextView
android:id="@+id/reply_retweet_status"
android:layout_width="match_parent"
android:layout_height="@dimen/element_size_small"
android:layout_marginBottom="@dimen/element_spacing_minus_normal"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_marginRight="@dimen/element_spacing_normal"
android:layout_marginTop="@dimen/element_spacing_small"
android:layout_toRightOf="@id/retweet_profile_image"
android:ellipsize="end"
android:gravity="center_vertical"
android:minHeight="@dimen/element_size_small"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="10sp"/>
<RelativeLayout
android:id="@+id/profile_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@id/retweet_profile_image"
android:layout_below="@id/reply_retweet_status"
android:layout_marginTop="@dimen/element_spacing_normal"
android:paddingLeft="@dimen/element_spacing_mlarge">
<org.mariotaku.twidere.view.CircularImageView
android:id="@+id/profile_image"
style="?profileImageStyle"
android:layout_width="@dimen/element_size_normal"
android:layout_height="@dimen/element_size_normal"
android:layout_centerVertical="true"
android:contentDescription="@string/profile_image"
android:padding="@dimen/padding_profile_image_list_item"
android:scaleType="centerCrop"/>
<ImageView
android:id="@+id/profile_type"
android:layout_width="@dimen/icon_size_profile_type"
android:layout_height="@dimen/icon_size_profile_type"
android:layout_alignBottom="@id/profile_image"
android:layout_alignRight="@id/profile_image"
android:scaleType="fitCenter"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_toLeftOf="@+id/menu"
android:layout_toRightOf="@id/profile_image"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/element_spacing_xsmall"
android:layout_marginTop="@dimen/element_spacing_small"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorPrimary"
android:textStyle="bold"/>
<TextView
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:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorSecondary"
android:textSize="10sp"/>
</LinearLayout>
<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:singleLine="true"
android:textAppearance="?android:textAppearanceSmall"
android:textSize="10sp"/>
</LinearLayout>
<org.mariotaku.twidere.view.ActionIconButton
android:id="@+id/menu"
style="?cardActionButtonStyle"
android:layout_width="@dimen/element_size_normal"
android:layout_height="@dimen/element_size_normal"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:src="@drawable/ic_action_more_vertical"/>
</RelativeLayout>
<org.mariotaku.twidere.view.ImagePreviewContainer
android:id="@+id/media_preview_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/profile_container"
android:layout_below="@id/profile_container"
android:layout_marginTop="@dimen/element_spacing_normal"
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_alignLeft="@+id/profile_container"
android:layout_below="@id/media_preview_container"
android:layout_marginBottom="@dimen/element_spacing_normal"
android:layout_marginTop="@dimen/element_spacing_normal"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary"/>
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/profile_container"
android:layout_below="@+id/text"
android:overScrollMode="never"
android:scrollbars="none">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<org.mariotaku.twidere.view.ActionIconTextView
android:id="@+id/reply_count"
style="?cardActionButtonStyle"
android:layout_width="wrap_content"
android:layout_height="@dimen/button_size_content_card"
android:layout_weight="0"
android:drawableLeft="@drawable/ic_action_reply"
android:gravity="center"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:textAppearance="?android:textAppearanceSmall"
app:activatedColor="@color/highlight_reply"/>
<org.mariotaku.twidere.view.ActionIconTextView
android:id="@+id/retweet_count"
style="?cardActionButtonStyle"
android:layout_width="wrap_content"
android:layout_height="@dimen/button_size_content_card"
android:layout_weight="0"
android:drawableLeft="@drawable/ic_action_retweet"
android:gravity="center"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:textAppearance="?android:textAppearanceSmall"
app:activatedColor="@color/highlight_retweet"/>
<org.mariotaku.twidere.view.ActionIconTextView
android:id="@+id/favorite_count"
style="?cardActionButtonStyle"
android:layout_width="wrap_content"
android:layout_height="@dimen/button_size_content_card"
android:layout_weight="0"
android:drawableLeft="@drawable/ic_action_star"
android:gravity="center"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:textAppearance="?android:textAppearanceSmall"
app:activatedColor="@color/highlight_favorite"/>
</LinearLayout>
</HorizontalScrollView>
</RelativeLayout>
</android.support.v7.widget.CardView>

View File

@ -1,155 +1,232 @@
<?xml version="1.0" encoding="utf-8"?>
<org.mariotaku.twidere.view.CardItemLinearLayout
<android.support.v7.widget.CardView
android:id="@+id/card"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="@dimen/element_spacing_small"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:paddingTop="@dimen/element_spacing_small"
tools:context=".adapter.CursorStatusesAdapter">
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:cardBackgroundColor="?cardItemBackgroundColor"
app:cardCornerRadius="2dp"
app:cardElevation="2dp">
<LinearLayout
<RelativeLayout
android:id="@+id/item_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingBottom="@dimen/element_spacing_normal"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_xlarge"
android:paddingTop="@dimen/element_spacing_normal">
android:background="?android:selectableItemBackground"
android:orientation="vertical">
<org.mariotaku.twidere.view.CircularImageView
style="?profileImageStyle"
android:id="@+id/profile_image"
android:layout_width="@dimen/icon_size_card_list_item"
android:layout_height="@dimen/icon_size_card_list_item"
android:layout_marginRight="@dimen/element_spacing_normal"
android:layout_weight="0"
android:contentDescription="@string/profile_image"
android:id="@+id/retweet_profile_image"
android:layout_width="@dimen/element_size_small"
android:layout_height="@dimen/element_size_small"
android:layout_marginBottom="@dimen/element_spacing_small"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_marginTop="@dimen/element_spacing_small"
android:scaleType="centerCrop"/>
<LinearLayout
<org.mariotaku.twidere.view.ActionIconTextView
android:id="@+id/reply_retweet_status"
android:layout_width="match_parent"
android:layout_height="@dimen/element_size_small"
android:layout_marginBottom="@dimen/element_spacing_minus_normal"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_marginRight="@dimen/element_spacing_normal"
android:layout_marginTop="@dimen/element_spacing_small"
android:layout_toRightOf="@id/retweet_profile_image"
android:ellipsize="end"
android:gravity="center_vertical"
android:minHeight="@dimen/element_size_small"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="10sp"/>
<RelativeLayout
android:id="@+id/profile_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
android:layout_alignLeft="@id/retweet_profile_image"
android:layout_below="@id/reply_retweet_status"
android:layout_marginTop="@dimen/element_spacing_normal"
android:paddingLeft="@dimen/element_spacing_mlarge">
<org.mariotaku.twidere.view.CircularImageView
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_centerVertical="true"
android:layout_margin="@dimen/element_spacing_small"
android:contentDescription="@string/profile_image"
android:scaleType="centerCrop"/>
<ImageView
android:id="@+id/profile_type"
android:layout_width="@dimen/icon_size_profile_type"
android:layout_height="@dimen/icon_size_profile_type"
android:layout_alignBottom="@id/profile_image"
android:layout_alignRight="@id/profile_image"
android:scaleType="fitCenter"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_toLeftOf="@+id/menu"
android:layout_toRightOf="@id/profile_image"
android:orientation="vertical">
<FrameLayout
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1">
android:layout_marginBottom="@dimen/element_spacing_xsmall"
android:layout_marginTop="@dimen/element_spacing_small"
android:gravity="center_vertical"
android:orientation="horizontal">
<org.mariotaku.twidere.view.HandleSpanClickTextView
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary"
android:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorPrimary"
android:textStyle="bold"/>
</FrameLayout>
<TextView
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:textAppearance="?android:textAppearanceSmall"
android:textColor="?android:textColorSecondary"
android:textSize="10sp"/>
</LinearLayout>
<org.mariotaku.twidere.view.ShortTimeView
android:id="@+id/time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0"
android:drawablePadding="@dimen/element_spacing_small"
android:paddingBottom="@dimen/element_spacing_small"
android:paddingTop="@dimen/element_spacing_xsmall"
android:singleLine="true"
android:textColor="?android:attr/textColorSecondary"/>
android:textAppearance="?android:textAppearanceSmall"
android:textSize="10sp"/>
</LinearLayout>
<org.mariotaku.twidere.view.HandleSpanClickTextView
android:id="@+id/screen_name"
<org.mariotaku.twidere.view.ActionIconButton
android:id="@+id/menu"
style="?cardActionButtonStyle"
android:layout_width="@dimen/element_size_normal"
android:layout_height="@dimen/element_size_normal"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:src="@drawable/ic_action_more_vertical"/>
</RelativeLayout>
<org.mariotaku.twidere.view.ImagePreviewContainer
android:id="@+id/media_preview_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/profile_container"
android:layout_below="@id/profile_container"
android:layout_marginTop="@dimen/element_spacing_normal"
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:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"/>
</LinearLayout>
android:layout_gravity="center"
android:layout_margin="@dimen/element_spacing_large"/>
<org.mariotaku.twidere.view.CircularImageView
style="?profileImageStyle"
android:id="@+id/my_profile_image"
android:layout_width="@dimen/icon_size_card_list_item"
android:layout_height="@dimen/icon_size_card_list_item"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_weight="0"
android:contentDescription="@string/your_profile_image"
android:scaleType="fitCenter"/>
</LinearLayout>
</org.mariotaku.twidere.view.ImagePreviewContainer>
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="0.2dp"
android:background="#40808080"/>
<org.mariotaku.twidere.view.ImagePreviewContainer
android:id="@+id/image_preview_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone">
<org.mariotaku.twidere.view.HighlightImageView
android:id="@+id/image_preview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitCenter"/>
<ProgressBar
android:id="@+id/image_preview_progress"
style="?android:attr/progressBarStyleHorizontal"
<org.mariotaku.twidere.view.HandleSpanClickTextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="@dimen/element_spacing_large"/>
android:layout_alignLeft="@+id/profile_container"
android:layout_below="@id/media_preview_container"
android:layout_marginBottom="@dimen/element_spacing_normal"
android:layout_marginTop="@dimen/element_spacing_normal"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorPrimary"/>
<TextView
android:id="@+id/image_preview_count"
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_margin="@dimen/element_spacing_normal"
android:shadowColor="#000000"
android:shadowDx="0"
android:shadowDy="0"
android:shadowRadius="3.0"
android:textColor="#ffffff"/>
</org.mariotaku.twidere.view.ImagePreviewContainer>
android:layout_alignLeft="@+id/profile_container"
android:layout_below="@+id/text"
android:overScrollMode="never"
android:scrollbars="none">
<org.mariotaku.twidere.view.HandleSpanClickTextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/element_spacing_normal"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:paddingTop="@dimen/element_spacing_normal"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<org.mariotaku.twidere.view.themed.ThemedTextView
android:id="@+id/reply_retweet_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="@dimen/element_spacing_small"
android:paddingBottom="@dimen/element_spacing_normal"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:paddingTop="@dimen/element_spacing_small"
android:singleLine="true"
android:textColor="?android:attr/textColorSecondary"/>
<org.mariotaku.twidere.view.ActionIconTextView
android:id="@+id/reply_count"
style="?cardActionButtonStyle"
android:layout_width="wrap_content"
android:layout_height="@dimen/button_size_content_card"
android:layout_weight="0"
android:drawableLeft="@drawable/ic_action_reply"
android:gravity="center"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:textAppearance="?android:textAppearanceSmall"
app:activatedColor="@color/highlight_reply"/>
</org.mariotaku.twidere.view.CardItemLinearLayout>
<org.mariotaku.twidere.view.ActionIconTextView
android:id="@+id/retweet_count"
style="?cardActionButtonStyle"
android:layout_width="wrap_content"
android:layout_height="@dimen/button_size_content_card"
android:layout_weight="0"
android:drawableLeft="@drawable/ic_action_retweet"
android:gravity="center"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:textAppearance="?android:textAppearanceSmall"
app:activatedColor="@color/highlight_retweet"/>
<org.mariotaku.twidere.view.ActionIconTextView
android:id="@+id/favorite_count"
style="?cardActionButtonStyle"
android:layout_width="wrap_content"
android:layout_height="@dimen/button_size_content_card"
android:layout_weight="0"
android:drawableLeft="@drawable/ic_action_star"
android:gravity="center"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:textAppearance="?android:textAppearanceSmall"
app:activatedColor="@color/highlight_favorite"/>
</LinearLayout>
</HorizontalScrollView>
</RelativeLayout>
</android.support.v7.widget.CardView>

View File

@ -0,0 +1,155 @@
<?xml version="1.0" encoding="utf-8"?>
<org.mariotaku.twidere.view.CardItemLinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="@dimen/element_spacing_small"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:paddingTop="@dimen/element_spacing_small"
tools:context=".adapter.CursorStatusesAdapter">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingBottom="@dimen/element_spacing_normal"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_xlarge"
android:paddingTop="@dimen/element_spacing_normal">
<org.mariotaku.twidere.view.CircularImageView
style="?profileImageStyle"
android:id="@+id/profile_image"
android:layout_width="@dimen/icon_size_card_list_item"
android:layout_height="@dimen/icon_size_card_list_item"
android:layout_marginRight="@dimen/element_spacing_normal"
android:layout_weight="0"
android:contentDescription="@string/profile_image"
android:scaleType="centerCrop"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
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">
<org.mariotaku.twidere.view.HandleSpanClickTextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/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:drawablePadding="@dimen/element_spacing_small"
android:singleLine="true"
android:textColor="?android:attr/textColorSecondary"/>
</LinearLayout>
<org.mariotaku.twidere.view.HandleSpanClickTextView
android:id="@+id/screen_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"/>
</LinearLayout>
<org.mariotaku.twidere.view.CircularImageView
style="?profileImageStyle"
android:id="@+id/my_profile_image"
android:layout_width="@dimen/icon_size_card_list_item"
android:layout_height="@dimen/icon_size_card_list_item"
android:layout_marginLeft="@dimen/element_spacing_normal"
android:layout_weight="0"
android:contentDescription="@string/your_profile_image"
android:scaleType="fitCenter"/>
</LinearLayout>
<View
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="0.2dp"
android:background="#40808080"/>
<org.mariotaku.twidere.view.ImagePreviewContainer
android:id="@+id/image_preview_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone">
<org.mariotaku.twidere.view.HighlightImageView
android:id="@+id/image_preview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitCenter"/>
<ProgressBar
android:id="@+id/image_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"/>
<TextView
android:id="@+id/image_preview_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_margin="@dimen/element_spacing_normal"
android:shadowColor="#000000"
android:shadowDx="0"
android:shadowDy="0"
android:shadowRadius="3.0"
android:textColor="#ffffff"/>
</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:paddingBottom="@dimen/element_spacing_normal"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:paddingTop="@dimen/element_spacing_normal"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary"/>
<org.mariotaku.twidere.view.themed.ThemedTextView
android:id="@+id/reply_retweet_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="@dimen/element_spacing_small"
android:paddingBottom="@dimen/element_spacing_normal"
android:paddingLeft="@dimen/element_spacing_normal"
android:paddingRight="@dimen/element_spacing_normal"
android:paddingTop="@dimen/element_spacing_small"
android:singleLine="true"
android:textColor="?android:attr/textColorSecondary"/>
</org.mariotaku.twidere.view.CardItemLinearLayout>

View File

@ -4,6 +4,6 @@
android:layout_width="match_parent"
android:layout_height="wrap_content">
<include layout="@layout/card_item_status"/>
<include layout="@layout/card_item_status_deprecated"/>
</ScrollView>

View File

@ -0,0 +1,49 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ 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/>.
-->
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="beforeDescendants"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent">
<requestFocus/>
</android.support.v7.widget.RecyclerView>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:visibility="gone">
<org.mariotaku.twidere.view.themed.ThemedMultiAutoCompleteTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</RelativeLayout>
</FrameLayout>

View File

@ -15,12 +15,13 @@
app:cardElevation="@dimen/elevation_card">
<LinearLayout
android:id="@+id/card_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<org.mariotaku.twidere.view.themed.ThemedTextView
android:id="@+id/in_reply_to"
android:id="@+id/reply_retweet_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:selectableItemBackground"
@ -135,7 +136,7 @@
</org.mariotaku.twidere.view.ColorLabelRelativeLayout>
<include
layout="@layout/image_preview_grid"
layout="@layout/layout_media_preview"
android:visibility="gone"/>
<org.mariotaku.twidere.view.StatusTextView
@ -294,5 +295,7 @@
app:maxActionItems="@integer/max_action_buttons_bottom"/>
</LinearLayout>
<include layout="@layout/layout_content_fragment_common"/>
</android.support.v7.widget.CardView>
</FrameLayout>

View File

@ -302,6 +302,8 @@
android:layout_height="@dimen/icon_size_profile_type_user_profile"
android:layout_alignBottom="@id/profile_image"
android:layout_alignRight="@id/profile_image"
android:layout_marginRight="@dimen/element_spacing_minus_msmall"
android:layout_marginBottom="@dimen/element_spacing_minus_small"
android:scaleType="fitCenter"/>
<org.mariotaku.twidere.view.AssetFontTextView

View File

@ -1,18 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/image_preview"
android:id="@+id/media_preview"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/image_grid"
android:id="@+id/media_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"/>
<LinearLayout
android:id="@+id/load_images"
android:id="@+id/load_media"
android:layout_width="match_parent"
android:layout_height="@dimen/action_button_size"
android:background="?android:selectableItemBackground"
@ -23,14 +23,14 @@
<org.mariotaku.twidere.view.ActionIconView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="@string/load_images"
android:contentDescription="@string/load_media"
android:src="@drawable/ic_action_gallery"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/load_images"
android:text="@string/load_media"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textStyle="bold"/>
</LinearLayout>

View File

@ -4,6 +4,6 @@
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="@layout/card_item_status"/>
<include layout="@layout/card_item_status_deprecated"/>
</LinearLayout>

View File

@ -15,6 +15,7 @@
<dimen name="element_spacing_large">16dp</dimen>
<dimen name="element_spacing_xlarge">24dp</dimen>
<dimen name="element_spacing_minus_small">-4dp</dimen>
<dimen name="element_spacing_minus_msmall">-6dp</dimen>
<dimen name="element_spacing_minus_normal">-8dp</dimen>
<dimen name="element_spacing_minus_large">-16dp</dimen>
<dimen name="icon_size_list_item">56dp</dimen>
@ -80,9 +81,10 @@
<dimen name="unread_indicator_size">16dp</dimen>
<dimen name="account_selector_popup_width">180dp</dimen>
<dimen name="icon_size_status_profile_image">40dp</dimen>
<dimen name="icon_size_profile_type">18dp</dimen>
<dimen name="icon_size_profile_type_detail">24dp</dimen>
<dimen name="icon_size_profile_type_user_profile">32dp</dimen>
<dimen name="icon_size_profile_type">16dp</dimen>
<dimen name="icon_size_profile_type_detail">22dp</dimen>
<dimen name="icon_size_profile_type_user_profile">28dp</dimen>
<!-- Elevation values -->
<dimen name="elevation_card">2dp</dimen>

View File

@ -683,5 +683,6 @@
<string name="photo">Photo</string>
<string name="gallery">Gallery</string>
<string name="remove">Remove</string>
<string name="load_media">Load media</string>
</resources>