fixed media size json

fixed user list crashes
media timeline supports load more
This commit is contained in:
Mariotaku Lee 2015-10-26 16:10:37 +08:00
parent 413d256268
commit c25e6e5e07
45 changed files with 774 additions and 577 deletions

View File

@ -40,8 +40,8 @@ dependencies {
apt 'com.bluelinelabs:logansquare-compiler:1.1.0'
apt 'com.hannesdorfmann.parcelableplease:processor:1.0.1'
apt 'com.github.mariotaku.LoganSquareExtension:processor:b6f53c9a4d'
compile 'com.android.support:support-annotations:23.0.1'
compile 'com.android.support:support-v4:23.0.1'
compile 'com.android.support:support-annotations:23.1.0'
compile 'com.android.support:support-v4:23.1.0'
compile 'com.bluelinelabs:logansquare:1.1.0'
compile 'org.apache.commons:commons-lang3:3.4'
compile 'com.github.mariotaku:RestFu:0.9.2'

View File

@ -19,6 +19,7 @@
package org.mariotaku.twidere.api.twitter.model;
import org.mariotaku.library.logansquare.extension.annotation.EnumClass;
import org.mariotaku.library.logansquare.extension.annotation.Implementation;
import org.mariotaku.twidere.api.twitter.model.impl.UserListImpl;
@ -59,6 +60,7 @@ public interface UserList extends Comparable<UserList>, TwitterResponse {
boolean isFollowing();
@EnumClass
enum Mode {
PUBLIC("public"), PRIVATE("private");

View File

@ -22,12 +22,12 @@ package org.mariotaku.twidere.api.twitter.model.impl;
import com.bluelinelabs.logansquare.annotation.JsonField;
import com.bluelinelabs.logansquare.annotation.JsonObject;
import org.mariotaku.twidere.api.twitter.model.MediaEntity;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import org.mariotaku.twidere.api.twitter.model.MediaEntity;
/**
* Created by mariotaku on 15/3/31.
*/
@ -60,15 +60,87 @@ public class MediaEntityImpl implements MediaEntity {
long sourceUserId;
@JsonField(name = "video_info")
VideoInfo videoInfo;
@JsonField(name = "features")
HashMap<String, Feature> features;
@Override
public Map<String, Feature> getFeatures() {
return features;
}
@JsonField(name = "features")
HashMap<String, Feature> features;
@Override
public String toString() {
return "MediaEntityImpl{" +
"id=" + id +
", indices=" + indices +
", mediaUrl='" + mediaUrl + '\'' +
", mediaUrlHttps='" + mediaUrlHttps + '\'' +
", url='" + url + '\'' +
", displayUrl='" + displayUrl + '\'' +
", expandedUrl='" + expandedUrl + '\'' +
", type=" + type +
", sizes=" + sizes +
", sourceStatusId=" + sourceStatusId +
", sourceUserId=" + sourceUserId +
", videoInfo=" + videoInfo +
", features=" + features +
'}';
}
@Override
public String getMediaUrl() {
return mediaUrl;
}
@Override
public VideoInfo getVideoInfo() {
return videoInfo;
}
@Override
public String getMediaUrlHttps() {
return mediaUrlHttps;
}
@Override
public String getExpandedUrl() {
return expandedUrl;
}
@Override
public String getDisplayUrl() {
return displayUrl;
}
@Override
public String getUrl() {
return url;
}
@Override
public Type getType() {
return type;
}
@Override
public Map<String, Size> getSizes() {
return sizes;
}
@Override
public int getEnd() {
return indices.getEnd();
}
@Override
public int getStart() {
return indices.getStart();
}
@Override
public long getId() {
return id;
}
@JsonObject
public static class FeatureImpl implements Feature {
@ -126,83 +198,6 @@ public class MediaEntityImpl implements MediaEntity {
}
@Override
public String toString() {
return "MediaEntityImpl{" +
"id=" + id +
", indices=" + indices +
", mediaUrl='" + mediaUrl + '\'' +
", mediaUrlHttps='" + mediaUrlHttps + '\'' +
", url='" + url + '\'' +
", displayUrl='" + displayUrl + '\'' +
", expandedUrl='" + expandedUrl + '\'' +
", type=" + type +
", sizes=" + sizes +
", sourceStatusId=" + sourceStatusId +
", sourceUserId=" + sourceUserId +
", videoInfo=" + videoInfo +
", features=" + features +
'}';
}
@Override
public String getMediaUrl() {
return mediaUrl;
}
@Override
public VideoInfo getVideoInfo() {
return videoInfo;
}
@Override
public String getMediaUrlHttps() {
return mediaUrlHttps;
}
@Override
public String getExpandedUrl() {
return expandedUrl;
}
@Override
public String getDisplayUrl() {
return displayUrl;
}
@Override
public String getUrl() {
return url;
}
@Override
public Type getType() {
return type;
}
@Override
public Map<String, Size> getSizes() {
return sizes;
}
@Override
public int getEnd() {
return indices.getEnd();
}
@Override
public int getStart() {
return indices.getStart();
}
@Override
public long getId() {
return id;
}
@JsonObject
public static class VideoInfoImpl implements VideoInfo {
@ -276,9 +271,9 @@ public class MediaEntityImpl implements MediaEntity {
@JsonObject
public static class SizeImpl implements Size {
@JsonField(name = "width")
@JsonField(name = "w")
int width;
@JsonField(name = "height")
@JsonField(name = "h")
int height;
@JsonField(name = "resize")
String resize;

View File

@ -59,7 +59,6 @@ public class ParcelableMedia implements Parcelable {
return new ParcelableMedia[size];
}
};
@NonNull
@JsonField(name = "media_url")
public String media_url;
@Nullable

View File

@ -21,13 +21,17 @@ package org.mariotaku.twidere.util;
import android.graphics.Color;
import android.os.Bundle;
import android.util.JsonWriter;
import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
import org.mariotaku.restfu.Utils;
import org.mariotaku.twidere.TwidereConstants;
import org.mariotaku.twidere.constant.IntentConstants;
import java.io.IOException;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
@ -42,29 +46,41 @@ public final class ParseUtils {
public static String bundleToJSON(final Bundle args) {
final Set<String> keys = args.keySet();
final JSONObject json = new JSONObject();
for (final String key : keys) {
final Object value = args.get(key);
if (value == null) {
continue;
}
try {
if (value instanceof Boolean) {
json.put(key, args.getBoolean(key));
final StringWriter sw = new StringWriter();
final JsonWriter json = new JsonWriter(sw);
try {
json.beginObject();
for (final String key : keys) {
json.name(key);
final Object value = args.get(key);
if (value == null) {
json.nullValue();
} else if (value instanceof Boolean) {
json.value((Boolean) value);
} else if (value instanceof Integer) {
json.put(key, args.getInt(key));
json.value((Integer) value);
} else if (value instanceof Long) {
json.put(key, args.getLong(key));
json.value((Long) value);
} else if (value instanceof String) {
json.put(key, args.getString(key));
json.value((String) value);
} else if (value instanceof Float) {
json.value((Float) value);
} else if (value instanceof Double) {
json.value((Double) value);
} else {
Log.w(TwidereConstants.LOGTAG, "Unknown type " + value.getClass().getSimpleName() + " in arguments key " + key);
}
} catch (final JSONException e) {
e.printStackTrace();
}
json.endObject();
json.flush();
sw.flush();
return sw.toString();
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
Utils.closeSilently(json);
}
return json.toString();
}
public static Bundle jsonToBundle(final String string) {

View File

@ -14,7 +14,7 @@ android {
applicationId "org.mariotaku.twidere"
minSdkVersion 14
targetSdkVersion 23
versionCode 129
versionCode 130
versionName "0.3.0"
multiDexEnabled true
}
@ -60,15 +60,16 @@ dependencies {
apt 'com.hannesdorfmann.parcelableplease:processor:1.0.1'
apt 'com.google.dagger:dagger-compiler:2.0.1'
compile 'com.android.support:multidex:1.0.1'
compile 'com.android.support:support-v13:23.0.1'
compile 'com.android.support:appcompat-v7:23.0.1'
compile 'com.android.support:cardview-v7:23.0.1'
compile 'com.android.support:recyclerview-v7:23.0.1'
compile 'com.android.support:support-v13:23.1.0'
compile 'com.android.support:appcompat-v7:23.1.0'
compile 'com.android.support:cardview-v7:23.1.0'
compile 'com.android.support:recyclerview-v7:23.1.0'
compile 'com.twitter:twitter-text:1.12.1'
compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.4'
compile 'com.squareup:otto:1.3.8'
compile 'dnsjava:dnsjava:2.1.7'
compile 'com.commonsware.cwac:merge:1.1.1'
compile 'com.commonsware.cwac:layouts:0.4.2'
compile 'com.davemorrissey.labs:subsampling-scale-image-view:3.4.0'
compile 'com.rengwuxian.materialedittext:library:2.1.4'
compile 'com.pnikosis:materialish-progress:1.7'

View File

@ -28,6 +28,8 @@ import com.bluelinelabs.logansquare.annotation.JsonObject;
import com.hannesdorfmann.parcelableplease.annotation.ParcelablePlease;
import com.hannesdorfmann.parcelableplease.annotation.ParcelableThisPlease;
import org.mariotaku.twidere.BuildConfig;
import java.util.TimeZone;
import edu.tsinghua.hotmobi.HotMobiLogger;
@ -51,6 +53,9 @@ public class BaseEvent implements Parcelable {
}
};
@ParcelableThisPlease
@JsonField(name = "app_version")
int appVersion = BuildConfig.VERSION_CODE;
@ParcelableThisPlease
@JsonField(name = "start_time")
long startTime;

View File

@ -20,6 +20,7 @@
package edu.tsinghua.hotmobi.model;
import android.content.Context;
import android.media.AudioManager;
import android.os.Parcel;
import android.os.Parcelable;
@ -65,6 +66,9 @@ public class NotificationEvent extends BaseEvent implements Parcelable {
@ParcelableThisPlease
@JsonField(name = "action", typeConverter = Action.NotificationActionConverter.class)
Action action;
@ParcelableThisPlease
@JsonField(name = "ringer_mode")
int ringerMode;
public NotificationEvent() {
}
@ -81,6 +85,7 @@ public class NotificationEvent extends BaseEvent implements Parcelable {
event.setEndTime(respondTime);
event.setTimeOffset(TimeZone.getDefault().getOffset(postTime));
event.setLocation(HotMobiLogger.getCachedLatLng(context));
event.setRingerMode(((AudioManager) context.getSystemService(Context.AUDIO_SERVICE)).getRingerMode());
event.setType(type);
event.setAccountId(accountId);
event.setItemId(itemId);
@ -147,6 +152,26 @@ public class NotificationEvent extends BaseEvent implements Parcelable {
this.itemUserId = itemUserId;
}
public void setRingerMode(int ringerMode) {
this.ringerMode = ringerMode;
}
public int getRingerMode() {
return ringerMode;
}
public static boolean isSupported(String type) {
if (type == null) return false;
switch (type) {
case "status":
case "statuses":
case "mention":
case "mentions":
return true;
}
return false;
}
public enum Action {
OPEN("open"), DELETE("delete"), UNKNOWN("unknown");

View File

@ -54,6 +54,7 @@ import android.support.v4.util.LongSparseArray;
import android.support.v7.internal.view.SupportMenuInflater;
import android.support.v7.widget.ActionMenuView;
import android.support.v7.widget.ActionMenuView.OnMenuItemClickListener;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.FixedLinearLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
@ -615,46 +616,7 @@ public class ComposeActivity extends ThemedFragmentActivity implements LocationL
linearLayoutManager.setStackFromEnd(true);
mAccountSelector.setLayoutManager(linearLayoutManager);
mAccountSelector.addItemDecoration(new SpacingItemDecoration(this));
mAccountSelector.setItemAnimator(new RecyclerView.ItemAnimator() {
@Override
public void runPendingAnimations() {
}
@Override
public boolean animateRemove(ViewHolder holder) {
return false;
}
@Override
public boolean animateAdd(ViewHolder holder) {
return false;
}
@Override
public boolean animateMove(ViewHolder holder, int fromX, int fromY, int toX, int toY) {
return false;
}
@Override
public boolean animateChange(ViewHolder oldHolder, ViewHolder newHolder, int fromLeft, int fromTop, int toLeft, int toTop) {
return false;
}
@Override
public void endAnimation(ViewHolder item) {
}
@Override
public void endAnimations() {
}
@Override
public boolean isRunning() {
return false;
}
});
mAccountSelector.setItemAnimator(new DefaultItemAnimator());
mAccountsAdapter = new AccountIconsAdapter(this);
mAccountSelector.setAdapter(mAccountsAdapter);
mAccountsAdapter.setAccounts(ParcelableCredentials.getCredentialsArray(this, false, false));

View File

@ -52,13 +52,13 @@ import org.mariotaku.twidere.view.holder.GapViewHolder;
import org.mariotaku.twidere.view.holder.LoadIndicatorViewHolder;
import org.mariotaku.twidere.view.holder.StatusViewHolder;
import org.mariotaku.twidere.view.holder.StatusViewHolder.DummyStatusHolderAdapter;
import org.mariotaku.twidere.view.holder.StatusViewHolder.StatusClickListener;
import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder;
/**
* Created by mariotaku on 15/1/3.
*/
public abstract class AbsActivitiesAdapter<Data> extends LoadMoreSupportAdapter<ViewHolder> implements Constants,
IActivitiesAdapter<Data>, StatusClickListener, OnLinkClickListener, ActivityTitleSummaryViewHolder.ActivityClickListener {
IActivitiesAdapter<Data>, IStatusViewHolder.StatusClickListener, OnLinkClickListener, ActivityTitleSummaryViewHolder.ActivityClickListener {
private static final int ITEM_VIEW_TYPE_STUB = 0;
private static final int ITEM_VIEW_TYPE_GAP = 1;
@ -66,7 +66,6 @@ public abstract class AbsActivitiesAdapter<Data> extends LoadMoreSupportAdapter<
private static final int ITEM_VIEW_TYPE_TITLE_SUMMARY = 3;
private static final int ITEM_VIEW_TYPE_STATUS = 4;
private final Context mContext;
private final LayoutInflater mInflater;
private final MediaLoadingHandler mLoadingHandler;
private final int mCardBackgroundColor;
@ -82,7 +81,6 @@ public abstract class AbsActivitiesAdapter<Data> extends LoadMoreSupportAdapter<
protected AbsActivitiesAdapter(final Context context, boolean compact) {
super(context);
mContext = context;
mCardBackgroundColor = ThemeUtils.getCardBackgroundColor(context,
ThemeUtils.getThemeBackgroundOption(context),
ThemeUtils.getUserThemeBackgroundAlpha(context));
@ -117,12 +115,6 @@ public abstract class AbsActivitiesAdapter<Data> extends LoadMoreSupportAdapter<
return mMediaLoader;
}
@NonNull
@Override
public Context getContext() {
return mContext;
}
@Override
public MediaLoadingHandler getMediaLoadingHandler() {
return mLoadingHandler;
@ -167,7 +159,7 @@ public abstract class AbsActivitiesAdapter<Data> extends LoadMoreSupportAdapter<
}
@Override
public void onStatusClick(StatusViewHolder holder, int position) {
public void onStatusClick(IStatusViewHolder holder, int position) {
final ParcelableActivity activity = getActivity(position);
final ParcelableStatus status;
if (activity.action == Activity.ACTION_MENTION) {
@ -179,12 +171,12 @@ public abstract class AbsActivitiesAdapter<Data> extends LoadMoreSupportAdapter<
}
@Override
public void onMediaClick(StatusViewHolder holder, View view, ParcelableMedia media, int position) {
public void onMediaClick(IStatusViewHolder holder, View view, ParcelableMedia media, int position) {
}
@Override
public void onUserProfileClick(StatusViewHolder holder, int position) {
public void onUserProfileClick(IStatusViewHolder holder, int position) {
final Context context = getContext();
final ParcelableActivity activity = getActivity(position);
final ParcelableStatus status;
@ -264,8 +256,8 @@ public abstract class AbsActivitiesAdapter<Data> extends LoadMoreSupportAdapter<
} else {
status = activity.target_statuses[0];
}
final StatusViewHolder statusViewHolder = (StatusViewHolder) holder;
statusViewHolder.displayStatus(status, null, true, true);
final IStatusViewHolder IStatusViewHolder = (IStatusViewHolder) holder;
IStatusViewHolder.displayStatus(status, null, true, true);
break;
}
case ITEM_VIEW_TYPE_TITLE_SUMMARY: {
@ -280,7 +272,7 @@ public abstract class AbsActivitiesAdapter<Data> extends LoadMoreSupportAdapter<
}
@Override
public boolean onStatusLongClick(StatusViewHolder holder, int position) {
public boolean onStatusLongClick(IStatusViewHolder holder, int position) {
return false;
}

View File

@ -1,22 +1,38 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.adapter;
import android.content.Context;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.view.holder.StatusViewHolder;
import java.util.List;
/**
* Created by mariotaku on 14/11/19.
* Created by mariotaku on 15/10/26.
*/
public class ParcelableStatusesAdapter extends AbsStatusesAdapter<List<ParcelableStatus>> {
public abstract class AbsParcelableStatusesAdapter extends AbsStatusesAdapter<List<ParcelableStatus>> {
private List<ParcelableStatus> mData;
public ParcelableStatusesAdapter(Context context, boolean compact) {
public AbsParcelableStatusesAdapter(Context context, boolean compact) {
super(context, compact);
setHasStableIds(true);
}
@Override
@ -24,11 +40,6 @@ public class ParcelableStatusesAdapter extends AbsStatusesAdapter<List<Parcelabl
return getStatus(position).is_gap && position != getStatusesCount() - 1;
}
@Override
protected void bindStatus(StatusViewHolder holder, int position) {
holder.displayStatus(getStatus(position), isShowInReplyTo());
}
@Override
public ParcelableStatus getStatus(int position) {
if (position == getStatusesCount()) return null;
@ -41,7 +52,6 @@ public class ParcelableStatusesAdapter extends AbsStatusesAdapter<List<Parcelabl
return mData.size();
}
@Override
public long getItemId(int position) {
if (position == getStatusesCount()) return position;
@ -64,5 +74,4 @@ public class ParcelableStatusesAdapter extends AbsStatusesAdapter<List<Parcelabl
public List<ParcelableStatus> getData() {
return mData;
}
}

View File

@ -2,7 +2,6 @@ package org.mariotaku.twidere.adapter;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.CardView;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.view.LayoutInflater;
import android.view.View;
@ -26,7 +25,7 @@ import org.mariotaku.twidere.view.CardMediaContainer.PreviewStyle;
import org.mariotaku.twidere.view.ShapedImageView.ShapeStyle;
import org.mariotaku.twidere.view.holder.GapViewHolder;
import org.mariotaku.twidere.view.holder.LoadIndicatorViewHolder;
import org.mariotaku.twidere.view.holder.StatusViewHolder;
import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder;
/**
* Created by mariotaku on 14/11/19.
@ -36,13 +35,9 @@ public abstract class AbsStatusesAdapter<D> extends LoadMoreSupportAdapter<ViewH
public static final int ITEM_VIEW_TYPE_STATUS = 2;
private final Context mContext;
private final LayoutInflater mInflater;
private final MediaLoadingHandler mLoadingHandler;
private final TwidereLinkify mLinkify;
private StatusAdapterListener mStatusAdapterListener;
private final int mCardBackgroundColor;
private final int mTextSize;
@ShapeStyle
@ -51,23 +46,21 @@ public abstract class AbsStatusesAdapter<D> extends LoadMoreSupportAdapter<ViewH
private final int mMediaPreviewStyle;
@HighlightStyle
private final int mLinkHighlightingStyle;
private final boolean mCompactCards;
private final boolean mNameFirst;
private final boolean mDisplayMediaPreview;
private final boolean mDisplayProfileImage;
private final boolean mSensitiveContentEnabled;
private final boolean mHideCardActions;
private StatusAdapterListener mStatusAdapterListener;
private boolean mShowInReplyTo;
private boolean mShowAccountsColor;
public AbsStatusesAdapter(Context context, boolean compact) {
super(context);
mContext = context;
mCardBackgroundColor = ThemeUtils.getCardBackgroundColor(context, ThemeUtils.getThemeBackgroundOption(context), ThemeUtils.getUserThemeBackgroundAlpha(context));
mInflater = LayoutInflater.from(context);
mLoadingHandler = new MediaLoadingHandler(R.id.media_preview_progress);
mLoadingHandler = new MediaLoadingHandler(getProgressViewIds());
mTextSize = mPreferences.getInt(KEY_TEXT_SIZE, context.getResources().getInteger(R.integer.default_text_size));
mCompactCards = compact;
mProfileImageStyle = Utils.getProfileImageStyle(mPreferences.getString(KEY_PROFILE_IMAGE_STYLE, null));
@ -82,6 +75,8 @@ public abstract class AbsStatusesAdapter<D> extends LoadMoreSupportAdapter<ViewH
setShowInReplyTo(true);
}
protected abstract int[] getProgressViewIds();
public abstract D getData();
@Override
@ -98,12 +93,6 @@ public abstract class AbsStatusesAdapter<D> extends LoadMoreSupportAdapter<ViewH
return mMediaLoader;
}
@NonNull
@Override
public final Context getContext() {
return mContext;
}
@Override
public final MediaLoadingHandler getMediaLoadingHandler() {
return mLoadingHandler;
@ -172,24 +161,24 @@ public abstract class AbsStatusesAdapter<D> extends LoadMoreSupportAdapter<ViewH
}
@Override
public boolean onStatusLongClick(StatusViewHolder holder, int position) {
public boolean onStatusLongClick(IStatusViewHolder holder, int position) {
return mStatusAdapterListener != null && mStatusAdapterListener.onStatusLongClick(holder, position);
}
@Override
public final void onStatusClick(StatusViewHolder holder, int position) {
public final void onStatusClick(IStatusViewHolder holder, int position) {
if (mStatusAdapterListener == null) return;
mStatusAdapterListener.onStatusClick(holder, position);
}
@Override
public void onMediaClick(StatusViewHolder holder, View view, final ParcelableMedia media, int position) {
public void onMediaClick(IStatusViewHolder holder, View view, final ParcelableMedia media, int position) {
if (mStatusAdapterListener == null) return;
mStatusAdapterListener.onMediaClick(holder, view, media, position);
}
@Override
public void onUserProfileClick(final StatusViewHolder holder, final int position) {
public void onUserProfileClick(final IStatusViewHolder holder, final int position) {
if (mStatusAdapterListener == null) return;
final ParcelableStatus status = getStatus(position);
if (status == null) return;
@ -214,20 +203,7 @@ public abstract class AbsStatusesAdapter<D> extends LoadMoreSupportAdapter<ViewH
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case ITEM_VIEW_TYPE_STATUS: {
final View view;
if (mCompactCards) {
view = mInflater.inflate(R.layout.card_item_status_compact, parent, false);
final View itemContent = view.findViewById(R.id.item_content);
itemContent.setBackgroundColor(mCardBackgroundColor);
} else {
view = mInflater.inflate(R.layout.card_item_status, parent, false);
final CardView cardView = (CardView) view.findViewById(R.id.card);
cardView.setCardBackgroundColor(mCardBackgroundColor);
}
final StatusViewHolder holder = new StatusViewHolder(this, view);
holder.setOnClickListeners();
holder.setupViewOptions();
return holder;
return (ViewHolder) onCreateStatusViewHolder(parent, mCompactCards);
}
case ITEM_VIEW_TYPE_GAP: {
final View view = mInflater.inflate(R.layout.card_item_gap, parent, false);
@ -241,11 +217,22 @@ public abstract class AbsStatusesAdapter<D> extends LoadMoreSupportAdapter<ViewH
throw new IllegalStateException("Unknown view type " + viewType);
}
protected LayoutInflater getInflater() {
return mInflater;
}
protected int getCardBackgroundColor() {
return mCardBackgroundColor;
}
@NonNull
protected abstract IStatusViewHolder onCreateStatusViewHolder(ViewGroup parent, boolean compact);
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
switch (holder.getItemViewType()) {
case ITEM_VIEW_TYPE_STATUS: {
bindStatus(((StatusViewHolder) holder), position);
bindStatus(((IStatusViewHolder) holder), position);
break;
}
}
@ -275,13 +262,13 @@ public abstract class AbsStatusesAdapter<D> extends LoadMoreSupportAdapter<ViewH
@Override
public void onItemActionClick(ViewHolder holder, int id, int position) {
if (mStatusAdapterListener == null) return;
mStatusAdapterListener.onStatusActionClick((StatusViewHolder) holder, id, position);
mStatusAdapterListener.onStatusActionClick((IStatusViewHolder) holder, id, position);
}
@Override
public void onItemMenuClick(ViewHolder holder, View menuView, int position) {
if (mStatusAdapterListener == null) return;
mStatusAdapterListener.onStatusMenuClick((StatusViewHolder) holder, menuView, position);
mStatusAdapterListener.onStatusMenuClick((IStatusViewHolder) holder, menuView, position);
}
public void setListener(StatusAdapterListener listener) {
@ -294,22 +281,24 @@ public abstract class AbsStatusesAdapter<D> extends LoadMoreSupportAdapter<ViewH
notifyDataSetChanged();
}
protected abstract void bindStatus(StatusViewHolder holder, int position);
protected void bindStatus(IStatusViewHolder holder, int position) {
holder.displayStatus(getStatus(position), isShowInReplyTo());
}
public interface StatusAdapterListener {
void onGapClick(GapViewHolder holder, int position);
void onMediaClick(StatusViewHolder holder, View view, ParcelableMedia media, int position);
void onMediaClick(IStatusViewHolder holder, View view, ParcelableMedia media, int position);
void onStatusActionClick(StatusViewHolder holder, int id, int position);
void onStatusActionClick(IStatusViewHolder holder, int id, int position);
void onStatusClick(StatusViewHolder holder, int position);
void onStatusClick(IStatusViewHolder holder, int position);
boolean onStatusLongClick(StatusViewHolder holder, int position);
boolean onStatusLongClick(IStatusViewHolder holder, int position);
void onStatusMenuClick(StatusViewHolder holder, View menuView, int position);
void onStatusMenuClick(IStatusViewHolder holder, View menuView, int position);
void onUserProfileClick(StatusViewHolder holder, ParcelableStatus status, int position);
void onUserProfileClick(IStatusViewHolder holder, ParcelableStatus status, int position);
}
}

View File

@ -43,7 +43,6 @@ public abstract class AbsUserListsAdapter<D> extends LoadMoreSupportAdapter<View
public static final int ITEM_VIEW_TYPE_USER_LIST = 2;
private final Context mContext;
private final LayoutInflater mInflater;
private final int mCardBackgroundColor;
@ -56,7 +55,6 @@ public abstract class AbsUserListsAdapter<D> extends LoadMoreSupportAdapter<View
public AbsUserListsAdapter(final Context context, final boolean compact) {
super(context);
mContext = context;
mCardBackgroundColor = ThemeUtils.getCardBackgroundColor(context, ThemeUtils.getThemeBackgroundOption(context), ThemeUtils.getUserThemeBackgroundAlpha(context));
mInflater = LayoutInflater.from(context);
mTextSize = mPreferences.getInt(KEY_TEXT_SIZE, context.getResources().getInteger(R.integer.default_text_size));
@ -66,12 +64,6 @@ public abstract class AbsUserListsAdapter<D> extends LoadMoreSupportAdapter<View
mCompactCards = compact;
}
@NonNull
@Override
public Context getContext() {
return mContext;
}
@Override
public int getProfileImageStyle() {
return mProfileImageStyle;

View File

@ -43,7 +43,6 @@ public abstract class AbsUsersAdapter<D> extends LoadMoreSupportAdapter<ViewHold
public static final int ITEM_VIEW_TYPE_USER = 2;
private final Context mContext;
private final LayoutInflater mInflater;
private final int mCardBackgroundColor;
@ -54,7 +53,6 @@ public abstract class AbsUsersAdapter<D> extends LoadMoreSupportAdapter<ViewHold
public AbsUsersAdapter(final Context context, final boolean compact) {
super(context);
mContext = context;
mCardBackgroundColor = ThemeUtils.getCardBackgroundColor(context, ThemeUtils.getThemeBackgroundOption(context), ThemeUtils.getUserThemeBackgroundAlpha(context));
mInflater = LayoutInflater.from(context);
mTextSize = mPreferences.getInt(KEY_TEXT_SIZE, context.getResources().getInteger(R.integer.default_text_size));
@ -63,12 +61,6 @@ public abstract class AbsUsersAdapter<D> extends LoadMoreSupportAdapter<ViewHold
mCompactCards = compact;
}
@NonNull
@Override
public Context getContext() {
return mContext;
}
@Override
public int getProfileImageStyle() {
return mProfileImageStyle;

View File

@ -37,6 +37,8 @@ import javax.inject.Inject;
* Created by mariotaku on 15/10/5.
*/
public abstract class BaseRecyclerViewAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {
private final Context mContext;
@Inject
protected AsyncTwitterWrapper mTwitterWrapper;
@Inject
@ -49,12 +51,16 @@ public abstract class BaseRecyclerViewAdapter<VH extends RecyclerView.ViewHolder
protected UserColorNameManager mUserColorNameManager;
@Inject
protected SharedPreferencesWrapper mPreferences;
public BaseRecyclerViewAdapter(Context context) {
mContext = context;
//noinspection unchecked
DaggerGeneralComponent.builder()
.applicationModule(ApplicationModule.get(context))
.build()
.inject((BaseRecyclerViewAdapter<RecyclerView.ViewHolder>) this);
}
public final Context getContext() {
return mContext;
}
}

View File

@ -0,0 +1,49 @@
package org.mariotaku.twidere.adapter;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.CardView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.view.holder.StatusViewHolder;
import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder;
/**
* Created by mariotaku on 14/11/19.
*/
public class ListParcelableStatusesAdapter extends AbsParcelableStatusesAdapter {
public ListParcelableStatusesAdapter(Context context, boolean compact) {
super(context, compact);
setHasStableIds(true);
}
@Override
protected int[] getProgressViewIds() {
return new int[]{R.id.media_preview_progress};
}
@NonNull
@Override
protected IStatusViewHolder onCreateStatusViewHolder(ViewGroup parent, boolean compact) {
final View view;
final int backgroundColor = getCardBackgroundColor();
final LayoutInflater inflater = getInflater();
if (compact) {
view = inflater.inflate(R.layout.card_item_status_compact, parent, false);
final View itemContent = view.findViewById(R.id.item_content);
itemContent.setBackgroundColor(backgroundColor);
} else {
view = inflater.inflate(R.layout.card_item_status, parent, false);
final CardView cardView = (CardView) view.findViewById(R.id.card);
cardView.setCardBackgroundColor(backgroundColor);
}
final StatusViewHolder holder = new StatusViewHolder(this, view);
holder.setOnClickListeners();
holder.setupViewOptions();
return holder;
}
}

View File

@ -56,7 +56,6 @@ public class MessageConversationAdapter extends BaseRecyclerViewAdapter<ViewHold
private final int mProfileImageStyle;
private final int mMediaPreviewStyle;
private final Context mContext;
private final LayoutInflater mInflater;
private final MediaLoadingHandler mMediaLoadingHandler;
@ -66,7 +65,6 @@ public class MessageConversationAdapter extends BaseRecyclerViewAdapter<ViewHold
public MessageConversationAdapter(final Context context) {
super(context);
mContext = context;
mInflater = LayoutInflater.from(context);
mLinkify = new TwidereLinkify(new DirectMessageOnLinkClickHandler(context, null));
mDisplayProfileImage = mPreferences.getBoolean(KEY_DISPLAY_PROFILE_IMAGE, true);
@ -77,11 +75,6 @@ public class MessageConversationAdapter extends BaseRecyclerViewAdapter<ViewHold
mOutgoingMessageColor = ThemeUtils.getCardBackgroundColor(context, ThemeUtils.getThemeBackgroundOption(context), ThemeUtils.getUserThemeBackgroundAlpha(context));
}
public Context getContext() {
return mContext;
}
@Override
public MediaLoaderWrapper getMediaLoader() {
return mMediaLoader;
@ -172,7 +165,7 @@ public class MessageConversationAdapter extends BaseRecyclerViewAdapter<ViewHold
c.moveToPosition(position);
final long account_id = c.getLong(mIndices.account_id);
final long message_id = c.getLong(mIndices.message_id);
return Utils.findDirectMessageInDatabases(mContext, account_id, message_id);
return Utils.findDirectMessageInDatabases(getContext(), account_id, message_id);
}
@Override
@ -186,7 +179,7 @@ public class MessageConversationAdapter extends BaseRecyclerViewAdapter<ViewHold
final ParcelableDirectMessage message = getDirectMessage(position);
if (message == null || message.media == null) return;
final Bundle options = Utils.createMediaViewerActivityOption(view);
Utils.openMedia(mContext, message, null, options);
Utils.openMedia(getContext(), message, null, options);
}
}
}

View File

@ -33,7 +33,6 @@ import android.view.ViewGroup;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.iface.IContentCardAdapter;
import org.mariotaku.twidere.app.TwidereApplication;
import org.mariotaku.twidere.model.StringLongPair;
import org.mariotaku.twidere.provider.TwidereDataStore.DirectMessages.ConversationEntries;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
@ -50,7 +49,6 @@ public class MessageEntriesAdapter extends LoadMoreSupportAdapter<ViewHolder> im
public static final int ITEM_VIEW_TYPE_MESSAGE = 0;
public static final int ITEM_VIEW_TYPE_LOAD_INDICATOR = 1;
private final Context mContext;
private final LayoutInflater mInflater;
private final int mTextSize;
private final int mProfileImageStyle;
@ -65,9 +63,7 @@ public class MessageEntriesAdapter extends LoadMoreSupportAdapter<ViewHolder> im
public MessageEntriesAdapter(final Context context) {
super(context);
mContext = context;
mInflater = LayoutInflater.from(context);
final TwidereApplication app = TwidereApplication.getInstance(context);
mProfileImageStyle = Utils.getProfileImageStyle(mPreferences.getString(KEY_PROFILE_IMAGE_STYLE, null));
mMediaPreviewStyle = Utils.getMediaPreviewStyle(mPreferences.getString(KEY_MEDIA_PREVIEW_STYLE, null));
mDisplayProfileImage = mPreferences.getBoolean(KEY_DISPLAY_PROFILE_IMAGE, true);
@ -81,12 +77,6 @@ public class MessageEntriesAdapter extends LoadMoreSupportAdapter<ViewHolder> im
};
}
@NonNull
@Override
public Context getContext() {
return mContext;
}
@Override
public int getProfileImageStyle() {
return mProfileImageStyle;

View File

@ -0,0 +1,164 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.adapter;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import com.commonsware.cwac.layouts.AspectLockedFrameLayout;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.iface.IStatusesAdapter;
import org.mariotaku.twidere.api.twitter.model.TranslationResult;
import org.mariotaku.twidere.model.ParcelableMedia;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.util.MediaLoaderWrapper;
import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder;
/**
* Created by mariotaku on 14/11/19.
*/
public class StaggeredGridParcelableStatusesAdapter extends AbsParcelableStatusesAdapter {
public StaggeredGridParcelableStatusesAdapter(Context context, boolean compact) {
super(context, compact);
setHasStableIds(true);
}
@Override
protected int[] getProgressViewIds() {
return new int[]{R.id.media_image_progress};
}
@NonNull
@Override
protected IStatusViewHolder onCreateStatusViewHolder(ViewGroup parent, boolean compact) {
final View view = getInflater().inflate(R.layout.adapter_item_media_status, parent, false);
return new MediaTimelineViewHolder(this, view);
}
public static class MediaTimelineViewHolder extends RecyclerView.ViewHolder implements IStatusViewHolder {
private final SimpleAspectRatioSource aspectRatioSource = new SimpleAspectRatioSource();
private final AspectLockedFrameLayout mediaImageContainer;
private final ImageView mediaImageView;
private final ImageView mediaProfileImageView;
private final TextView mediaTextView;
private final IStatusesAdapter<?> adapter;
public MediaTimelineViewHolder(IStatusesAdapter<?> adapter, View itemView) {
super(itemView);
this.adapter = adapter;
mediaImageContainer = (AspectLockedFrameLayout) itemView.findViewById(R.id.media_image_container);
mediaImageContainer.setAspectRatioSource(aspectRatioSource);
mediaImageView = (ImageView) itemView.findViewById(R.id.media_image);
mediaProfileImageView = (ImageView) itemView.findViewById(R.id.media_profile_image);
mediaTextView = (TextView) itemView.findViewById(R.id.media_text);
}
@Override
public void displayStatus(ParcelableStatus status, boolean displayInReplyTo) {
final MediaLoaderWrapper loader = adapter.getMediaLoader();
final ParcelableMedia[] media = status.media;
if (media == null || media.length < 1) return;
final ParcelableMedia firstMedia = media[0];
if (status.text_plain.codePointCount(0, status.text_plain.length()) == firstMedia.end) {
mediaTextView.setText(status.text_unescaped.substring(0, firstMedia.start));
} else {
mediaTextView.setText(status.text_unescaped);
}
aspectRatioSource.setSize(firstMedia.width, firstMedia.height);
mediaImageContainer.requestLayout();
loader.displayProfileImage(mediaProfileImageView, status.user_profile_image_url);
loader.displayPreviewImageWithCredentials(mediaImageView, firstMedia.media_url,
status.account_id, adapter.getMediaLoadingHandler());
}
@Override
public void displayStatus(@NonNull ParcelableStatus status, @Nullable TranslationResult translation, boolean displayInReplyTo, boolean shouldDisplayExtraType) {
displayStatus(status, displayInReplyTo);
}
@Override
@Nullable
public ImageView getProfileImageView() {
return mediaProfileImageView;
}
@Override
@Nullable
public ImageView getProfileTypeView() {
return null;
}
@Override
public void onClick(View v) {
}
@Override
public boolean onLongClick(View v) {
return false;
}
@Override
public void onMediaClick(View view, ParcelableMedia media, long accountId) {
}
@Override
public void setStatusClickListener(StatusClickListener listener) {
}
@Override
public void setTextSize(float textSize) {
}
private static class SimpleAspectRatioSource implements AspectLockedFrameLayout.AspectRatioSource {
private int width, height;
@Override
public int getWidth() {
return width;
}
@Override
public int getHeight() {
return height;
}
public void setSize(int width, int height) {
this.width = width;
this.height = height;
}
}
}
}

View File

@ -4,12 +4,12 @@ import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.util.MediaLoadingHandler;
import org.mariotaku.twidere.util.TwidereLinkify;
import org.mariotaku.twidere.view.CardMediaContainer.PreviewStyle;
import org.mariotaku.twidere.view.holder.StatusViewHolder.StatusClickListener;
import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder;
/**
* Created by mariotaku on 14/11/18.
*/
public interface IStatusesAdapter<Data> extends IContentCardAdapter, StatusClickListener,
public interface IStatusesAdapter<Data> extends IContentCardAdapter, IStatusViewHolder.StatusClickListener,
IGapSupportedAdapter, ContentCardClickListener {
int getLinkHighlightingStyle();

View File

@ -1,70 +0,0 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2014 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.animation;
import android.support.v7.widget.RecyclerView.ItemAnimator;
import android.support.v7.widget.RecyclerView.ViewHolder;
/**
* Created by mariotaku on 14/11/23.
*/
public class CardItemAnimator extends ItemAnimator {
@Override
public void runPendingAnimations() {
}
@Override
public boolean animateRemove(ViewHolder holder) {
return false;
}
@Override
public boolean animateAdd(ViewHolder holder) {
return false;
}
@Override
public boolean animateMove(ViewHolder holder, int fromX, int fromY,
int toX, int toY) {
return false;
}
@Override
public boolean animateChange(ViewHolder oldHolder,
ViewHolder newHolder, int fromLeft, int fromTop, int toLeft, int toTop) {
return false;
}
@Override
public void endAnimation(ViewHolder holder) {
}
@Override
public void endAnimations() {
}
@Override
public boolean isRunning() {
return false;
}
}

View File

@ -47,7 +47,7 @@ import org.mariotaku.twidere.view.holder.GapViewHolder;
/**
* Created by mariotaku on 14/11/5.
*/
public abstract class AbsActivitiesFragment<Data> extends AbsContentRecyclerViewFragment<AbsActivitiesAdapter<Data>>
public abstract class AbsActivitiesFragment<Data> extends AbsContentListRecyclerViewFragment<AbsActivitiesAdapter<Data>>
implements LoaderCallbacks<Data>, OnRefreshListener, DrawerCallback, RefreshScrollTopInterface,
ActivityAdapterListener, KeyboardShortcutsHandler.KeyboardShortcutCallback {

View File

@ -0,0 +1,80 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.fragment.support;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.FixedLinearLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import org.mariotaku.twidere.adapter.LoadMoreSupportAdapter;
import org.mariotaku.twidere.adapter.decorator.DividerItemDecoration;
/**
* Comment, blah, blah, blah.
* Created by mariotaku on 15/4/16.
*/
public abstract class AbsContentListRecyclerViewFragment<A extends LoadMoreSupportAdapter>
extends AbsContentRecyclerViewFragment<A, LinearLayoutManager> {
private DividerItemDecoration mItemDecoration;
@Override
protected void setupRecyclerView(Context context, boolean compact) {
if (compact) {
mItemDecoration = new DividerItemDecoration(context, getLayoutManager().getOrientation());
getRecyclerView().addItemDecoration(mItemDecoration);
}
}
@Override
public void setLoadMoreIndicatorVisible(boolean visible) {
if (mItemDecoration != null) {
mItemDecoration.setDecorationEndOffset(visible ? 1 : 0);
}
super.setLoadMoreIndicatorVisible(visible);
}
@Override
protected void scrollToPositionWithOffset(int position, int offset) {
getLayoutManager().scrollToPositionWithOffset(0, 0);
}
@NonNull
@Override
protected LinearLayoutManager onCreateLayoutManager(Context context) {
return new FixedLinearLayoutManager(context, LinearLayoutManager.VERTICAL, false);
}
@Override
public int[] findLastVisibleItemPositions() {
return new int[]{getLayoutManager().findLastVisibleItemPosition()};
}
@Override
public int[] findFirstVisibleItemPositions() {
return new int[]{getLayoutManager().findFirstVisibleItemPosition()};
}
@Override
public int getItemCount() {
return getLayoutManager().getItemCount();
}
}

View File

@ -247,4 +247,19 @@ public abstract class AbsContentListViewFragment<A extends ListAdapter> extends
final int swipeDistance = Math.round(64 * density);
mSwipeRefreshLayout.setProgressViewOffset(false, swipeStart, swipeStart + swipeDistance);
}
@Override
public int[] findLastVisibleItemPositions() {
return new int[]{mListView.getLastVisiblePosition()};
}
@Override
public int[] findFirstVisibleItemPositions() {
return new int[]{mListView.getFirstVisiblePosition()};
}
@Override
public int getItemCount() {
return mListView.getCount();
}
}

View File

@ -1,5 +1,5 @@
/*
* Twidere - Twitter client for Android
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
@ -26,9 +26,6 @@ import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener;
import android.support.v7.widget.FixedLinearLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@ -40,27 +37,23 @@ import android.widget.TextView;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.iface.IControlBarActivity;
import org.mariotaku.twidere.activity.iface.IControlBarActivity.ControlBarOffsetListener;
import org.mariotaku.twidere.adapter.LoadMoreSupportAdapter;
import org.mariotaku.twidere.adapter.decorator.DividerItemDecoration;
import org.mariotaku.twidere.fragment.iface.RefreshScrollTopInterface;
import org.mariotaku.twidere.util.ContentListScrollListener;
import org.mariotaku.twidere.util.ContentListScrollListener.ContentListSupport;
import org.mariotaku.twidere.util.SimpleDrawerCallback;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.TwidereColorUtils;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.HeaderDrawerLayout.DrawerCallback;
import org.mariotaku.twidere.view.HeaderDrawerLayout;
import org.mariotaku.twidere.view.iface.IExtendedView;
import org.mariotaku.twidere.view.themed.AccentSwipeRefreshLayout;
/**
* Comment, blah, blah, blah.
* Created by mariotaku on 15/4/16.
* Created by mariotaku on 15/10/26.
*/
public abstract class AbsContentRecyclerViewFragment<A extends LoadMoreSupportAdapter> extends BaseSupportFragment
implements OnRefreshListener, DrawerCallback, RefreshScrollTopInterface, ControlBarOffsetListener,
ContentListSupport, IControlBarActivity.ControlBarShowHideHelper.ControlBarAnimationListener {
public abstract class AbsContentRecyclerViewFragment<A extends LoadMoreSupportAdapter, L extends RecyclerView.LayoutManager> extends BaseSupportFragment
implements SwipeRefreshLayout.OnRefreshListener, HeaderDrawerLayout.DrawerCallback, RefreshScrollTopInterface, IControlBarActivity.ControlBarOffsetListener,
ContentListScrollListener.ContentListSupport, IControlBarActivity.ControlBarShowHideHelper.ControlBarAnimationListener {
private View mProgressContainer;
private SwipeRefreshLayout mSwipeRefreshLayout;
@ -69,7 +62,7 @@ public abstract class AbsContentRecyclerViewFragment<A extends LoadMoreSupportAd
private ImageView mErrorIconView;
private TextView mErrorTextView;
private LinearLayoutManager mLayoutManager;
private L mLayoutManager;
private A mAdapter;
// Callbacks and listeners
@ -78,7 +71,6 @@ public abstract class AbsContentRecyclerViewFragment<A extends LoadMoreSupportAd
// Data fields
private Rect mSystemWindowsInsets = new Rect();
private DividerItemDecoration mItemDecoration;
@Override
public boolean canScroll(float dy) {
@ -123,12 +115,14 @@ public abstract class AbsContentRecyclerViewFragment<A extends LoadMoreSupportAd
@Override
public boolean scrollToStart() {
mLayoutManager.scrollToPositionWithOffset(0, 0);
scrollToPositionWithOffset(0, 0);
mRecyclerView.stopScroll();
setControlVisible(true);
return true;
}
protected abstract void scrollToPositionWithOffset(int position, int offset);
@Override
public void onControlBarVisibleAnimationFinish(boolean visible) {
updateRefreshProgressOffset();
@ -160,7 +154,7 @@ public abstract class AbsContentRecyclerViewFragment<A extends LoadMoreSupportAd
@Override
public abstract boolean isRefreshing();
public LinearLayoutManager getLayoutManager() {
public L getLayoutManager() {
return mLayoutManager;
}
@ -212,8 +206,7 @@ public abstract class AbsContentRecyclerViewFragment<A extends LoadMoreSupportAd
mSwipeRefreshLayout.setOnRefreshListener(this);
mSwipeRefreshLayout.setProgressBackgroundColorSchemeResource(colorRes);
mAdapter = onCreateAdapter(context, compact);
mLayoutManager = new FixedLinearLayoutManager(context);
mLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
mLayoutManager = onCreateLayoutManager(context);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setHasFixedSize(true);
if (mSwipeRefreshLayout instanceof AccentSwipeRefreshLayout) {
@ -238,16 +231,18 @@ public abstract class AbsContentRecyclerViewFragment<A extends LoadMoreSupportAd
});
}
if (compact) {
mItemDecoration = new DividerItemDecoration(context, mLayoutManager.getOrientation());
mRecyclerView.addItemDecoration(mItemDecoration);
}
setupRecyclerView(context, compact);
mRecyclerView.setAdapter(mAdapter);
mScrollListener = new ContentListScrollListener(this);
mScrollListener.setTouchSlop(ViewConfiguration.get(context).getScaledTouchSlop());
}
protected abstract void setupRecyclerView(Context context, boolean compact);
@NonNull
protected abstract L onCreateLayoutManager(Context context);
@Override
public void onStart() {
super.onStart();
@ -297,9 +292,6 @@ public abstract class AbsContentRecyclerViewFragment<A extends LoadMoreSupportAd
}
public void setLoadMoreIndicatorVisible(boolean visible) {
if (mItemDecoration != null) {
mItemDecoration.setDecorationEndOffset(visible ? 1 : 0);
}
mAdapter.setLoadMoreIndicatorVisible(visible);
}

View File

@ -40,7 +40,7 @@ import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.imageloader.PauseRecyclerViewOnScrollListener;
import org.mariotaku.twidere.util.message.StatusListChangedEvent;
import org.mariotaku.twidere.view.holder.GapViewHolder;
import org.mariotaku.twidere.view.holder.StatusViewHolder;
import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder;
import java.io.File;
import java.util.ArrayList;
@ -57,7 +57,7 @@ import static org.mariotaku.twidere.util.Utils.setMenuForStatus;
/**
* Created by mariotaku on 14/11/5.
*/
public abstract class AbsStatusesFragment<Data> extends AbsContentRecyclerViewFragment<AbsStatusesAdapter<Data>>
public abstract class AbsStatusesFragment<Data> extends AbsContentListRecyclerViewFragment<AbsStatusesAdapter<Data>>
implements LoaderCallbacks<Data>, StatusAdapterListener, KeyboardShortcutCallback {
private final Object mStatusesBusCallback;
@ -312,7 +312,7 @@ public abstract class AbsStatusesFragment<Data> extends AbsContentRecyclerViewFr
}
@Override
public void onMediaClick(StatusViewHolder holder, View view, ParcelableMedia media, int position) {
public void onMediaClick(IStatusViewHolder holder, View view, ParcelableMedia media, int position) {
final AbsStatusesAdapter<Data> adapter = getAdapter();
final ParcelableStatus status = adapter.getStatus(position);
if (status == null) return;
@ -326,7 +326,7 @@ public abstract class AbsStatusesFragment<Data> extends AbsContentRecyclerViewFr
}
@Override
public void onStatusActionClick(StatusViewHolder holder, int id, int position) {
public void onStatusActionClick(IStatusViewHolder holder, int id, int position) {
final AbsStatusesAdapter<Data> adapter = getAdapter();
final ParcelableStatus status = adapter.getStatus(position);
if (status == null) return;
@ -357,19 +357,19 @@ public abstract class AbsStatusesFragment<Data> extends AbsContentRecyclerViewFr
}
@Override
public void onStatusClick(StatusViewHolder holder, int position) {
public void onStatusClick(IStatusViewHolder holder, int position) {
final AbsStatusesAdapter<Data> adapter = getAdapter();
Utils.openStatus(getActivity(), adapter.getStatus(position), null);
}
@Override
public boolean onStatusLongClick(StatusViewHolder holder, int position) {
public boolean onStatusLongClick(IStatusViewHolder holder, int position) {
//TODO handle long click event
return true;
}
@Override
public void onStatusMenuClick(StatusViewHolder holder, View menuView, int position) {
public void onStatusMenuClick(IStatusViewHolder holder, View menuView, int position) {
if (mPopupMenu != null) {
mPopupMenu.dismiss();
}
@ -386,7 +386,7 @@ public abstract class AbsStatusesFragment<Data> extends AbsContentRecyclerViewFr
}
@Override
public void onUserProfileClick(StatusViewHolder holder, ParcelableStatus status, int position) {
public void onUserProfileClick(IStatusViewHolder holder, ParcelableStatus status, int position) {
final FragmentActivity activity = getActivity();
final View profileImageView = holder.getProfileImageView();
final View profileTypeView = holder.getProfileTypeView();

View File

@ -40,7 +40,7 @@ import org.mariotaku.twidere.util.RecyclerViewNavigationHelper;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.holder.UserListViewHolder;
abstract class AbsUserListsFragment<Data> extends AbsContentRecyclerViewFragment<AbsUserListsAdapter<Data>>
abstract class AbsUserListsFragment<Data> extends AbsContentListRecyclerViewFragment<AbsUserListsAdapter<Data>>
implements LoaderCallbacks<Data>, AbsUserListsAdapter.UserListAdapterListener, KeyboardShortcutCallback {
private RecyclerViewNavigationHelper mNavigationHelper;

View File

@ -42,7 +42,7 @@ import org.mariotaku.twidere.util.RecyclerViewNavigationHelper;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.holder.UserViewHolder;
abstract class AbsUsersFragment<Data> extends AbsContentRecyclerViewFragment<AbsUsersAdapter<Data>>
abstract class AbsUsersFragment<Data> extends AbsContentListRecyclerViewFragment<AbsUsersAdapter<Data>>
implements LoaderCallbacks<Data>, UserAdapterListener, KeyboardShortcutCallback {
private RecyclerViewNavigationHelper mNavigationHelper;

View File

@ -40,7 +40,7 @@ import org.mariotaku.sqliteqb.library.RawItemArray;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.activity.support.HomeActivity;
import org.mariotaku.twidere.adapter.AbsStatusesAdapter;
import org.mariotaku.twidere.adapter.ParcelableStatusesAdapter;
import org.mariotaku.twidere.adapter.ListParcelableStatusesAdapter;
import org.mariotaku.twidere.loader.support.ObjectCursorLoader;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.provider.TwidereDataStore.Accounts;
@ -207,8 +207,8 @@ public abstract class CursorStatusesFragment extends AbsStatusesFragment<List<Pa
@NonNull
@Override
protected ParcelableStatusesAdapter onCreateAdapter(final Context context, final boolean compact) {
return new ParcelableStatusesAdapter(context, compact);
protected ListParcelableStatusesAdapter onCreateAdapter(final Context context, final boolean compact) {
return new ListParcelableStatusesAdapter(context, compact);
}
@Override

View File

@ -70,7 +70,7 @@ import java.util.Set;
import static org.mariotaku.twidere.util.Utils.openMessageConversation;
public class DirectMessagesFragment extends AbsContentRecyclerViewFragment<MessageEntriesAdapter>
public class DirectMessagesFragment extends AbsContentListRecyclerViewFragment<MessageEntriesAdapter>
implements LoaderCallbacks<Cursor>, MessageEntriesAdapterListener, KeyboardShortcutCallback {
// Listeners

View File

@ -25,7 +25,7 @@ import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.v4.app.FragmentActivity;
import org.mariotaku.twidere.adapter.ParcelableStatusesAdapter;
import org.mariotaku.twidere.adapter.ListParcelableStatusesAdapter;
import org.mariotaku.twidere.provider.TwidereDataStore.Mentions;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
@ -41,8 +41,8 @@ public class MentionsTimelineFragment extends CursorStatusesFragment {
@NonNull
@Override
protected ParcelableStatusesAdapter onCreateAdapter(Context context, boolean compact) {
final ParcelableStatusesAdapter adapter = super.onCreateAdapter(context, compact);
protected ListParcelableStatusesAdapter onCreateAdapter(Context context, boolean compact) {
final ListParcelableStatusesAdapter adapter = super.onCreateAdapter(context, compact);
adapter.setShowInReplyTo(false);
return adapter;
}

View File

@ -26,7 +26,7 @@ import android.support.v4.app.LoaderManager;
import com.squareup.otto.Subscribe;
import org.mariotaku.twidere.adapter.ParcelableStatusesAdapter;
import org.mariotaku.twidere.adapter.ListParcelableStatusesAdapter;
import org.mariotaku.twidere.adapter.iface.IStatusesAdapter;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.util.message.FavoriteCreatedEvent;
@ -107,8 +107,8 @@ public abstract class ParcelableStatusesFragment extends AbsStatusesFragment<Lis
@NonNull
@Override
protected ParcelableStatusesAdapter onCreateAdapter(final Context context, final boolean compact) {
return new ParcelableStatusesAdapter(context, compact);
protected ListParcelableStatusesAdapter onCreateAdapter(final Context context, final boolean compact) {
return new ListParcelableStatusesAdapter(context, compact);
}
@Override

View File

@ -42,19 +42,18 @@ import android.widget.EditText;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.constant.SharedPreferenceConstants;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.util.AsyncTwitterWrapper;
import org.mariotaku.twidere.util.EditTextEnterHandler;
import org.mariotaku.twidere.util.LinkCreator;
import org.mariotaku.twidere.util.MenuUtils;
import org.mariotaku.twidere.util.SharedPreferencesWrapper;
import org.mariotaku.twidere.util.ThemeUtils;
import org.mariotaku.twidere.util.TwidereValidator;
import org.mariotaku.twidere.view.ComposeMaterialEditText;
import org.mariotaku.twidere.view.StatusTextCountView;
import org.mariotaku.twidere.view.holder.StatusViewHolder;
import org.mariotaku.twidere.view.holder.StatusViewHolder.DummyStatusHolderAdapter;
import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder;
import static org.mariotaku.twidere.util.Utils.isMyRetweet;
@ -101,7 +100,7 @@ public class RetweetQuoteDialogFragment extends BaseSupportDialogFragment implem
@SuppressLint("InflateParams") final View view = inflater.inflate(R.layout.dialog_status_quote_retweet, null);
final DummyStatusHolderAdapter adapter = new DummyStatusHolderAdapter(context);
adapter.setShouldShowAccountsColor(true);
final StatusViewHolder holder = new StatusViewHolder(adapter, view.findViewById(R.id.item_content));
final IStatusViewHolder holder = new StatusViewHolder(adapter, view.findViewById(R.id.item_content));
final ParcelableStatus status = getStatus();
assert status != null;

View File

@ -42,7 +42,7 @@ import java.util.List;
/**
* Created by mariotaku on 15/7/10.
*/
public class ScheduledStatusesFragment extends AbsContentRecyclerViewFragment<ScheduledStatusesFragment.ScheduledStatusesAdapter>
public class ScheduledStatusesFragment extends AbsContentListRecyclerViewFragment<ScheduledStatusesFragment.ScheduledStatusesAdapter>
implements LoaderManager.LoaderCallbacks<List<ScheduledStatus>> {
@Override

View File

@ -123,6 +123,7 @@ import org.mariotaku.twidere.view.TwitterCardContainer;
import org.mariotaku.twidere.view.holder.GapViewHolder;
import org.mariotaku.twidere.view.holder.LoadIndicatorViewHolder;
import org.mariotaku.twidere.view.holder.StatusViewHolder;
import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder;
import java.util.ArrayList;
import java.util.List;
@ -324,7 +325,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
}
@Override
public void onMediaClick(StatusViewHolder holder, View view, ParcelableMedia media, int position) {
public void onMediaClick(IStatusViewHolder holder, View view, ParcelableMedia media, int position) {
final ParcelableStatus status = mStatusAdapter.getStatus(position);
if (status == null) return;
final Bundle options = Utils.createMediaViewerActivityOption(view);
@ -336,7 +337,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
}
@Override
public void onStatusActionClick(StatusViewHolder holder, int id, int position) {
public void onStatusActionClick(IStatusViewHolder holder, int id, int position) {
final ParcelableStatus status = mStatusAdapter.getStatus(position);
if (status == null) return;
switch (id) {
@ -366,17 +367,17 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
}
@Override
public void onStatusClick(StatusViewHolder holder, int position) {
public void onStatusClick(IStatusViewHolder holder, int position) {
Utils.openStatus(getActivity(), mStatusAdapter.getStatus(position), null);
}
@Override
public boolean onStatusLongClick(StatusViewHolder holder, int position) {
public boolean onStatusLongClick(IStatusViewHolder holder, int position) {
return false;
}
@Override
public void onStatusMenuClick(StatusViewHolder holder, View menuView, int position) {
public void onStatusMenuClick(IStatusViewHolder holder, View menuView, int position) {
//TODO show status menu
if (mPopupMenu != null) {
mPopupMenu.dismiss();
@ -393,7 +394,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
}
@Override
public void onUserProfileClick(StatusViewHolder holder, ParcelableStatus status, int position) {
public void onUserProfileClick(IStatusViewHolder holder, ParcelableStatus status, int position) {
final FragmentActivity activity = getActivity();
final View profileImageView = holder.getProfileImageView();
final View profileTypeView = holder.getProfileTypeView();
@ -1119,7 +1120,6 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
private static final int ITEM_IDX_REPLY_ERROR = 6;
private static final int ITEM_IDX_SPACE = 7;
private static final int ITEM_TYPES_SUM = 8;
private final Context mContext;
private final StatusFragment mFragment;
private final LayoutInflater mInflater;
private final MediaLoadingHandler mMediaLoadingHandler;
@ -1158,7 +1158,6 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
// There's always a space at the end of the list
mItemCounts[ITEM_IDX_SPACE] = 1;
mFragment = fragment;
mContext = context;
mInflater = LayoutInflater.from(context);
mMediaLoadingHandler = new MediaLoadingHandler(R.id.media_preview_progress);
mCardBackgroundColor = ThemeUtils.getCardBackgroundColor(context, ThemeUtils.getThemeBackgroundOption(context), ThemeUtils.getUserThemeBackgroundAlpha(context));
@ -1197,12 +1196,6 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
return RecyclerView.NO_POSITION;
}
@NonNull
@Override
public Context getContext() {
return mContext;
}
@Override
public int getProfileImageStyle() {
return mProfileImageStyle;
@ -1439,7 +1432,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
return new LoadIndicatorViewHolder(view);
}
case VIEW_TYPE_SPACE: {
return new SpaceViewHolder(new Space(mContext));
return new SpaceViewHolder(new Space(getContext()));
}
case VIEW_TYPE_REPLY_ERROR: {
final View view = mInflater.inflate(R.layout.adapter_item_status_error, parent,
@ -1463,7 +1456,7 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
}
case VIEW_TYPE_LIST_STATUS: {
final ParcelableStatus status = getStatus(position);
final StatusViewHolder statusHolder = (StatusViewHolder) holder;
final IStatusViewHolder statusHolder = (IStatusViewHolder) holder;
// Display 'in reply to' for first item
// useful to indicate whether first tweet has reply or not
// We only display that indicator for first conversation item
@ -1552,38 +1545,38 @@ public class StatusFragment extends BaseSupportFragment implements LoaderCallbac
@Override
public void onItemActionClick(ViewHolder holder, int id, int position) {
if (mStatusAdapterListener != null) {
mStatusAdapterListener.onStatusActionClick((StatusViewHolder) holder, id, position);
mStatusAdapterListener.onStatusActionClick((IStatusViewHolder) holder, id, position);
}
}
@Override
public void onItemMenuClick(ViewHolder holder, View itemView, int position) {
if (mStatusAdapterListener != null) {
mStatusAdapterListener.onStatusMenuClick((StatusViewHolder) holder, itemView, position);
mStatusAdapterListener.onStatusMenuClick((IStatusViewHolder) holder, itemView, position);
}
}
@Override
public void onMediaClick(StatusViewHolder holder, View view, ParcelableMedia media, int position) {
public void onMediaClick(IStatusViewHolder holder, View view, ParcelableMedia media, int position) {
if (mStatusAdapterListener != null) {
mStatusAdapterListener.onMediaClick(holder, view, media, position);
}
}
@Override
public final void onStatusClick(StatusViewHolder holder, int position) {
public final void onStatusClick(IStatusViewHolder holder, int position) {
if (mStatusAdapterListener != null) {
mStatusAdapterListener.onStatusClick(holder, position);
}
}
@Override
public boolean onStatusLongClick(StatusViewHolder holder, int position) {
public boolean onStatusLongClick(IStatusViewHolder holder, int position) {
return false;
}
@Override
public void onUserProfileClick(StatusViewHolder holder, int position) {
public void onUserProfileClick(IStatusViewHolder holder, int position) {
final Context context = getContext();
final ParcelableStatus status = getStatus(position);
final View profileImageView = holder.getProfileImageView();

View File

@ -44,11 +44,12 @@ import org.mariotaku.twidere.util.TwitterAPIFactory;
import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.view.holder.StatusViewHolder;
import org.mariotaku.twidere.view.holder.StatusViewHolder.DummyStatusHolderAdapter;
import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder;
public class StatusTranslateDialogFragment extends BaseSupportDialogFragment implements
LoaderCallbacks<SingleResponse<TranslationResult>> {
private StatusViewHolder mHolder;
private IStatusViewHolder mHolder;
private View mProgress;
private TextView mMessageView;

View File

@ -1,130 +1,82 @@
package org.mariotaku.twidere.fragment.support;
import android.content.Context;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.OnScrollListener;
import android.support.v7.widget.RecyclerView.ViewHolder;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.BaseRecyclerViewAdapter;
import org.mariotaku.twidere.adapter.StaggeredGridParcelableStatusesAdapter;
import org.mariotaku.twidere.adapter.iface.IStatusesAdapter;
import org.mariotaku.twidere.loader.iface.IExtendedLoader;
import org.mariotaku.twidere.loader.support.MediaTimelineLoader;
import org.mariotaku.twidere.model.ParcelableMedia;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.util.MediaLoaderWrapper;
import org.mariotaku.twidere.util.MediaLoadingHandler;
import org.mariotaku.twidere.util.SimpleDrawerCallback;
import org.mariotaku.twidere.view.HeaderDrawerLayout.DrawerCallback;
import org.mariotaku.twidere.view.MediaSizeImageView;
import java.util.List;
/**
* Created by mariotaku on 14/11/5.
*/
public class UserMediaTimelineFragment extends BaseSupportFragment
public class UserMediaTimelineFragment extends AbsContentRecyclerViewFragment<StaggeredGridParcelableStatusesAdapter, StaggeredGridLayoutManager>
implements LoaderCallbacks<List<ParcelableStatus>>, DrawerCallback {
private View mProgressContainer;
private RecyclerView mRecyclerView;
private MediaTimelineAdapter mAdapter;
@Override
public void fling(float velocity) {
mDrawerCallback.fling(velocity);
protected void scrollToPositionWithOffset(int position, int offset) {
getLayoutManager().scrollToPositionWithOffset(position, offset);
}
@Override
public void scrollBy(float dy) {
mDrawerCallback.scrollBy(dy);
public boolean isRefreshing() {
//TODO detect loader refreshing
return false;
}
@Override
public boolean shouldLayoutHeaderBottom() {
return mDrawerCallback.shouldLayoutHeaderBottom();
}
@Override
public boolean canScroll(float dy) {
return mDrawerCallback.canScroll(dy);
}
@Override
public boolean isScrollContent(float x, float y) {
return mDrawerCallback.isScrollContent(x, y);
}
@Override
public void cancelTouch() {
mDrawerCallback.cancelTouch();
}
@Override
public void topChanged(int offset) {
mDrawerCallback.topChanged(offset);
}
private SimpleDrawerCallback mDrawerCallback;
private final 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();
if (view == null) throw new AssertionError();
final Context context = view.getContext();
mAdapter = new MediaTimelineAdapter(context);
final StaggeredGridLayoutManager layoutManager = new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
mDrawerCallback = new SimpleDrawerCallback(mRecyclerView);
mRecyclerView.setLayoutManager(layoutManager);
mRecyclerView.setAdapter(mAdapter);
mRecyclerView.setOnScrollListener(mOnScrollListener);
getLoaderManager().initLoader(0, getArguments(), this);
setListShown(false);
final Bundle loaderArgs = new Bundle(getArguments());
loaderArgs.putBoolean(EXTRA_FROM_USER, true);
getLoaderManager().initLoader(0, loaderArgs, this);
showProgress();
}
public void setListShown(boolean shown) {
mRecyclerView.setVisibility(shown ? View.VISIBLE : View.GONE);
mProgressContainer.setVisibility(shown ? View.GONE : View.VISIBLE);
@Override
protected void setupRecyclerView(Context context, boolean compact) {
}
@NonNull
@Override
protected StaggeredGridLayoutManager onCreateLayoutManager(Context context) {
return new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.VERTICAL);
}
public int getStatuses(final long maxId, final long sinceId) {
final Bundle args = new Bundle(getArguments());
args.putBoolean(EXTRA_MAKE_GAP, false);
args.putLong(EXTRA_MAX_ID, maxId);
args.putLong(EXTRA_SINCE_ID, sinceId);
args.putBoolean(EXTRA_FROM_USER, true);
getLoaderManager().restartLoader(0, args, this);
return -1;
}
@Override
public void onBaseViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onBaseViewCreated(view, savedInstanceState);
mProgressContainer = view.findViewById(R.id.progress_container);
mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
}
@NonNull
@Override
protected void fitSystemWindows(Rect insets) {
if (mRecyclerView != null) {
mRecyclerView.setClipToPadding(false);
mRecyclerView.setPadding(insets.left, insets.top, insets.right, insets.bottom);
}
protected StaggeredGridParcelableStatusesAdapter onCreateAdapter(Context context, boolean compact) {
return new StaggeredGridParcelableStatusesAdapter(context, compact);
}
@Override
@ -141,82 +93,56 @@ public class UserMediaTimelineFragment extends BaseSupportFragment
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 MediaTimelineLoader(context, accountId, userId, screenName, sinceId, maxId, null,
null, tabPosition, true);
final boolean fromUser = args.getBoolean(EXTRA_FROM_USER);
return new MediaTimelineLoader(context, accountId, userId, screenName, sinceId, maxId,
getAdapter().getData(), null, tabPosition, fromUser);
}
@Override
public void onLoadFinished(Loader<List<ParcelableStatus>> loader, List<ParcelableStatus> data) {
mAdapter.setData(data);
setListShown(true);
final StaggeredGridParcelableStatusesAdapter adapter = getAdapter();
adapter.setData(data);
if (!(loader instanceof IExtendedLoader) || ((IExtendedLoader) loader).isFromUser()) {
adapter.setLoadMoreSupported(hasMoreData(data));
}
if (loader instanceof IExtendedLoader) {
((IExtendedLoader) loader).setFromUser(false);
}
showContent();
setLoadMoreIndicatorVisible(false);
}
private boolean hasMoreData(List<ParcelableStatus> data) {
return true;
}
@Override
public void onLoaderReset(Loader<List<ParcelableStatus>> loader) {
mAdapter.setData(null);
getAdapter().setData(null);
}
private static class MediaTimelineAdapter extends BaseRecyclerViewAdapter<MediaTimelineViewHolder> {
private final LayoutInflater mInflater;
private final MediaLoadingHandler mLoadingHandler;
private List<ParcelableStatus> mData;
MediaTimelineAdapter(Context context) {
super(context);
mInflater = LayoutInflater.from(context);
mLoadingHandler = new MediaLoadingHandler(R.id.media_image_progress);
}
@Override
public MediaTimelineViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final View view = mInflater.inflate(R.layout.adapter_item_media_status, parent, false);
return new MediaTimelineViewHolder(view);
}
@Override
public void onBindViewHolder(MediaTimelineViewHolder holder, int position) {
if (mData == null) return;
holder.setMedia(mMediaLoader, mLoadingHandler, mData.get(position));
}
public void setData(List<ParcelableStatus> data) {
mData = data;
notifyDataSetChanged();
}
@Override
public int getItemCount() {
if (mData == null) return 0;
return mData.size();
}
@Override
public int[] findLastVisibleItemPositions() {
return getLayoutManager().findLastVisibleItemPositions(null);
}
private static class MediaTimelineViewHolder extends ViewHolder {
@Override
public int[] findFirstVisibleItemPositions() {
return getLayoutManager().findFirstVisibleItemPositions(null);
}
private final MediaSizeImageView mediaImageView;
private final ImageView mediaProfileImageView;
private final TextView mediaTextView;
@Override
public int getItemCount() {
return getLayoutManager().getItemCount();
}
public MediaTimelineViewHolder(View itemView) {
super(itemView);
mediaImageView = (MediaSizeImageView) itemView.findViewById(R.id.media_image);
mediaProfileImageView = (ImageView) itemView.findViewById(R.id.media_profile_image);
mediaTextView = (TextView) itemView.findViewById(R.id.media_text);
}
public void setMedia(MediaLoaderWrapper loader, MediaLoadingHandler loadingHandler, ParcelableStatus status) {
final ParcelableMedia[] media = status.media;
if (media == null || media.length < 1) return;
final ParcelableMedia firstMedia = media[0];
if (status.text_plain.codePointCount(0, status.text_plain.length()) == firstMedia.end) {
mediaTextView.setText(status.text_unescaped.substring(0, firstMedia.start));
} else {
mediaTextView.setText(status.text_unescaped);
}
loader.displayProfileImage(mediaProfileImageView, status.user_profile_image_url);
mediaImageView.setMediaSize(firstMedia.width, firstMedia.height);
loader.displayPreviewImageWithCredentials(mediaImageView, firstMedia.media_url, status.account_id, loadingHandler);
}
@Override
public void onLoadMoreContents(boolean fromStart) {
if (fromStart) return;
//noinspection ConstantConditions
super.onLoadMoreContents(fromStart);
final IStatusesAdapter<List<ParcelableStatus>> adapter = getAdapter();
final long maxId = adapter.getStatusId(adapter.getStatusesCount() - 1);
getStatuses(maxId, -1);
}
}

View File

@ -30,6 +30,7 @@ import org.mariotaku.twidere.R;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.view.holder.StatusViewHolder;
import org.mariotaku.twidere.view.holder.StatusViewHolder.DummyStatusHolderAdapter;
import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder;
/**
* Created by mariotaku on 15/3/17.
@ -37,7 +38,7 @@ import org.mariotaku.twidere.view.holder.StatusViewHolder.DummyStatusHolderAdapt
public class ViewStatusDialogFragment extends BaseSupportDialogFragment {
private DummyStatusHolderAdapter mAdapter;
private StatusViewHolder mHolder;
private IStatusViewHolder mHolder;
private View mStatusContainer;
public ViewStatusDialogFragment() {

View File

@ -1377,8 +1377,8 @@ public final class TwidereDataProvider extends ContentProvider implements Consta
homeLinkBuilder.authority(AUTHORITY_STATUS);
homeLinkBuilder.appendQueryParameter(QUERY_PARAM_ACCOUNT_ID, String.valueOf(accountId));
homeLinkBuilder.appendQueryParameter(QUERY_PARAM_STATUS_ID, String.valueOf(statusId));
homeLinkBuilder.appendQueryParameter(QUERY_PARAM_EXTRA, "item_id=" + String.valueOf(statusId));
homeLinkBuilder.appendQueryParameter(QUERY_PARAM_EXTRA, "item_user_id=" + String.valueOf(userId));
UriExtraUtils.addExtra(homeLinkBuilder, "item_id", statusId);
UriExtraUtils.addExtra(homeLinkBuilder, "item_user_id", userId);
homeLinkBuilder.appendQueryParameter(QUERY_PARAM_FROM_NOTIFICATION, String.valueOf(true));
homeLinkBuilder.appendQueryParameter(QUERY_PARAM_TIMESTAMP, String.valueOf(System.currentTimeMillis()));
homeLinkBuilder.appendQueryParameter(QUERY_PARAM_NOTIFICATION_TYPE, type);

View File

@ -20,10 +20,10 @@
package org.mariotaku.twidere.util;
import android.support.annotation.NonNull;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.OnScrollListener;
import org.apache.commons.lang3.ArrayUtils;
import org.mariotaku.twidere.adapter.iface.ILoadMoreSupportAdapter;
/**
@ -44,7 +44,7 @@ public class ContentListScrollListener extends OnScrollListener {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
if (mScrollState != RecyclerView.SCROLL_STATE_IDLE) {
notifyScrollStateChanged(recyclerView);
notifyScrollStateChanged();
}
mScrollState = newState;
}
@ -61,7 +61,7 @@ public class ContentListScrollListener extends OnScrollListener {
mScrollSum = 0;
}
if (recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_IDLE) {
notifyScrollStateChanged(recyclerView);
notifyScrollStateChanged();
}
}
@ -69,21 +69,28 @@ public class ContentListScrollListener extends OnScrollListener {
mTouchSlop = touchSlop;
}
private void notifyScrollStateChanged(RecyclerView recyclerView) {
private void notifyScrollStateChanged() {
final Object adapter = mContentListSupport.getAdapter();
if (!(adapter instanceof ILoadMoreSupportAdapter)) return;
final ILoadMoreSupportAdapter loadMoreAdapter = (ILoadMoreSupportAdapter) adapter;
final LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
if (!mContentListSupport.isRefreshing() && loadMoreAdapter.isLoadMoreSupported()
&& !loadMoreAdapter.isLoadMoreIndicatorVisible()) {
if (layoutManager.findLastVisibleItemPosition() == layoutManager.getItemCount() - 1) {
if (reachedEnd()) {
mContentListSupport.onLoadMoreContents(false);
} else if (layoutManager.findFirstVisibleItemPosition() == 0) {
} else if (reachedStart()) {
mContentListSupport.onLoadMoreContents(true);
}
}
}
private boolean reachedStart() {
return ArrayUtils.contains(mContentListSupport.findFirstVisibleItemPositions(), 0);
}
private boolean reachedEnd() {
return ArrayUtils.contains(mContentListSupport.findLastVisibleItemPositions(), mContentListSupport.getItemCount() - 1);
}
public interface ContentListSupport {
Object getAdapter();
@ -94,5 +101,10 @@ public class ContentListScrollListener extends OnScrollListener {
void setControlVisible(boolean visible);
int[] findLastVisibleItemPositions();
int[] findFirstVisibleItemPositions();
int getItemCount();
}
}

View File

@ -40,9 +40,10 @@ public class UriExtraUtils implements Constants {
public static String getExtra(List<String> extras, String key) {
for (String extra : extras) {
final int i = extra.indexOf(key + "=");
final String prefix = key + "=";
final int i = extra.indexOf(prefix);
if (i == 0) {
return extra.substring(i);
return extra.substring(prefix.length());
}
}
return null;

View File

@ -3950,7 +3950,8 @@ public final class Utils implements Constants {
final long itemId = ParseUtils.parseLong(UriExtraUtils.getExtra(uri, "item_id"), -1);
final long itemUserId = ParseUtils.parseLong(UriExtraUtils.getExtra(uri, "item_user_id"), -1);
final long timestamp = ParseUtils.parseLong(uri.getQueryParameter(QUERY_PARAM_TIMESTAMP), -1);
if (!AUTHORITY_STATUS.equals(type) || accountId < 0 || itemId < 0 || timestamp < 0) return;
if (!NotificationEvent.isSupported(type) || accountId < 0 || itemId < 0 || timestamp < 0)
return;
final ApplicationModule module = ApplicationModule.get(context);
final HotMobiLogger logger = module.getHotMobiLogger();
logger.log(accountId, NotificationEvent.open(context, timestamp, type, accountId, itemId, itemUserId));

View File

@ -16,7 +16,6 @@ import android.widget.TextView;
import org.apache.commons.lang3.ArrayUtils;
import org.mariotaku.twidere.Constants;
import org.mariotaku.twidere.R;
import org.mariotaku.twidere.adapter.iface.ContentCardClickListener;
import org.mariotaku.twidere.adapter.iface.IStatusesAdapter;
import org.mariotaku.twidere.api.twitter.model.TranslationResult;
import org.mariotaku.twidere.app.TwidereApplication;
@ -34,10 +33,10 @@ import org.mariotaku.twidere.util.Utils;
import org.mariotaku.twidere.util.dagger.ApplicationModule;
import org.mariotaku.twidere.util.dagger.DaggerGeneralComponent;
import org.mariotaku.twidere.view.CardMediaContainer;
import org.mariotaku.twidere.view.CardMediaContainer.OnMediaClickListener;
import org.mariotaku.twidere.view.ForegroundColorView;
import org.mariotaku.twidere.view.NameView;
import org.mariotaku.twidere.view.ShortTimeView;
import org.mariotaku.twidere.view.holder.iface.IStatusViewHolder;
import org.mariotaku.twidere.view.iface.IColorLabelView;
import java.util.Locale;
@ -53,7 +52,7 @@ import static org.mariotaku.twidere.util.Utils.getUserTypeIconRes;
* Created by mariotaku on 14/11/19.
*/
public class StatusViewHolder extends ViewHolder implements Constants, OnClickListener,
OnMediaClickListener, OnLongClickListener {
OnLongClickListener, IStatusViewHolder {
@NonNull
private final IStatusesAdapter<?> adapter;
@ -129,10 +128,12 @@ public class StatusViewHolder extends ViewHolder implements Constants, OnClickLi
extraTypeView.setImageResource(R.drawable.ic_action_gallery);
}
@Override
public void displayStatus(final ParcelableStatus status, final boolean displayInReplyTo) {
displayStatus(status, null, displayInReplyTo, true);
}
@Override
public void displayStatus(@NonNull final ParcelableStatus status, @Nullable final TranslationResult translation,
final boolean displayInReplyTo, final boolean shouldDisplayExtraType) {
final MediaLoaderWrapper loader = adapter.getMediaLoader();
@ -309,10 +310,12 @@ public class StatusViewHolder extends ViewHolder implements Constants, OnClickLi
quotedNameView.updateText();
}
@Override
public ImageView getProfileImageView() {
return profileImageView;
}
@Override
public ImageView getProfileTypeView() {
return profileTypeView;
}
@ -366,6 +369,7 @@ public class StatusViewHolder extends ViewHolder implements Constants, OnClickLi
setStatusClickListener(adapter);
}
@Override
public void setStatusClickListener(StatusClickListener listener) {
statusClickListener = listener;
((View) itemContent).setOnClickListener(this);
@ -378,6 +382,7 @@ public class StatusViewHolder extends ViewHolder implements Constants, OnClickLi
favoriteCountView.setOnClickListener(this);
}
@Override
public void setTextSize(final float textSize) {
nameView.setPrimaryTextSize(textSize);
quotedNameView.setPrimaryTextSize(textSize);
@ -438,17 +443,6 @@ public class StatusViewHolder extends ViewHolder implements Constants, OnClickLi
return false;
}
public interface StatusClickListener extends ContentCardClickListener {
void onMediaClick(StatusViewHolder holder, View view, ParcelableMedia media, int position);
void onStatusClick(StatusViewHolder holder, int position);
boolean onStatusLongClick(StatusViewHolder holder, int position);
void onUserProfileClick(StatusViewHolder holder, int position);
}
public static final class DummyStatusHolderAdapter implements IStatusesAdapter<Object> {
private final Context context;
@ -631,22 +625,22 @@ public class StatusViewHolder extends ViewHolder implements Constants, OnClickLi
}
@Override
public void onStatusClick(StatusViewHolder holder, int position) {
public void onStatusClick(IStatusViewHolder holder, int position) {
}
@Override
public boolean onStatusLongClick(StatusViewHolder holder, int position) {
public boolean onStatusLongClick(IStatusViewHolder holder, int position) {
return false;
}
@Override
public void onMediaClick(StatusViewHolder holder, View view, ParcelableMedia media, int position) {
public void onMediaClick(IStatusViewHolder holder, View view, ParcelableMedia media, int position) {
}
@Override
public void onUserProfileClick(StatusViewHolder holder, int position) {
public void onUserProfileClick(IStatusViewHolder holder, int position) {
}

View File

@ -0,0 +1,69 @@
/*
* Twidere - Twitter client for Android
*
* Copyright (C) 2012-2015 Mariotaku Lee <mariotaku.lee@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mariotaku.twidere.view.holder.iface;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.View;
import android.widget.ImageView;
import org.mariotaku.twidere.adapter.iface.ContentCardClickListener;
import org.mariotaku.twidere.api.twitter.model.TranslationResult;
import org.mariotaku.twidere.model.ParcelableMedia;
import org.mariotaku.twidere.model.ParcelableStatus;
import org.mariotaku.twidere.view.CardMediaContainer;
/**
* Created by mariotaku on 15/10/26.
*/
public interface IStatusViewHolder extends CardMediaContainer.OnMediaClickListener {
void displayStatus(ParcelableStatus status, boolean displayInReplyTo);
void displayStatus(@NonNull ParcelableStatus status, @Nullable TranslationResult translation,
boolean displayInReplyTo, boolean shouldDisplayExtraType);
@Nullable
ImageView getProfileImageView();
@Nullable
ImageView getProfileTypeView();
void onClick(View v);
boolean onLongClick(View v);
@Override
void onMediaClick(View view, ParcelableMedia media, long accountId);
void setStatusClickListener(StatusClickListener listener);
void setTextSize(float textSize);
interface StatusClickListener extends ContentCardClickListener {
void onMediaClick(IStatusViewHolder holder, View view, ParcelableMedia media, int position);
void onStatusClick(IStatusViewHolder holder, int position);
boolean onStatusLongClick(IStatusViewHolder holder, int position);
void onUserProfileClick(IStatusViewHolder holder, int position);
}
}

View File

@ -33,14 +33,16 @@
android:layout_height="wrap_content"
android:orientation="vertical">
<FrameLayout
<com.commonsware.cwac.layouts.AspectLockedFrameLayout
android:id="@+id/media_image_container"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<org.mariotaku.twidere.view.MediaSizeImageView
<ImageView
android:id="@+id/media_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:contentDescription="@string/media"
android:scaleType="centerCrop" />
<ProgressBar
@ -50,7 +52,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="@dimen/element_spacing_small" />
</FrameLayout>
</com.commonsware.cwac.layouts.AspectLockedFrameLayout>
<org.mariotaku.twidere.view.ColorLabelRelativeLayout
android:id="@+id/media_info_container"