Add favorite

This commit is contained in:
seven332 committed 2015-08-26 13:08:33 +08:00
1 parent 59c14245ee
commit ee7a3ac3b3
15 files changed
+855 -159

No files matched your search

@@ -226,6 +226,35 @@ public final class EhClient {
*/
public static final int METHOD_RATE_GALLERY = 7;
/**
* Get favorite
*
* <table>
* <tr>
* <th>param</th>
* <th>info</th>
* </tr>
* <tr>
* <td>cat</td>
* <td>favorite category, -1 for all</td>
* </tr>
* <tr>
* <td>page</td>
* <td>the page index</td>
* </tr>
* <tr>
* <td>source</td>
* <td>the source, one of {@link EhUrl#SOURCE_G},
* {@link EhUrl#SOURCE_EX} and {@link EhUrl#SOURCE_LOFI}</td>
* </tr>
* <tr>
* <td>listener</td>
* <td>the listener for callback</td>
* </tr>
* </table>
*/
public static final int METHOD_GET_FAVORITE = 8;
private final ThreadPoolExecutor mRequestThreadPool;
private final HttpClient mHttpClient;
@@ -352,6 +381,8 @@ public final class EhClient {
return EhEngine.getPreviewSet(mHttpClient, mEhHttpRequest, (String) params[0], (Integer) params[1]);
case METHOD_RATE_GALLERY:
return EhEngine.rateGallery(mHttpClient, mEhHttpRequest, (Integer) params[0], (String) params[1], (Float) params[2], (Integer) params[3]);
case METHOD_GET_FAVORITE:
return EhEngine.getFavorite(mHttpClient, mEhHttpRequest, (Integer) params[0], (Integer) params[1], (Integer) params[2]);
default:
return new IllegalStateException("Can't detect method");
}
@@ -81,6 +81,14 @@ class EhEngine {
}
}
/**
* @param cat -1 for all
*/
public static GalleryListParser.Result getFavorite(HttpClient httpClient,
HttpRequest httpRequest, int cat, int page, int source) throws Exception {
return getGalleryList(httpClient, httpRequest, EhUrl.getFavoriteUrl(source, cat, page), source);
}
public static PopularParser.Result getPopular(HttpClient httpClient,
HttpRequest httpRequest) throws Exception {
try {
@@ -83,4 +83,15 @@ public class EhUrl {
public static String getPageUrl(int source, int gid, String token, int pageIndex) {
return getUrlHeader(source) + "s/" + token + '/' + gid + '-' + (pageIndex + 1);
}
/**
* @param cat -1 for all
*/
public static String getFavoriteUrl(int source, int cat, int pageIndex) {
if (cat == -1) {
return getUrlHeader(source) + "favorites.php?page=" + pageIndex;
} else {
return getUrlHeader(source) + "favorites.php?favcat=" + cat + "&page=" + pageIndex;
}
}
}
@@ -0,0 +1,84 @@
/*
* Copyright 2015 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.client.data;
import android.text.TextUtils;
import com.hippo.ehviewer.client.EhUrl;
import com.hippo.network.UrlBuilder;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
public class FavoriteUrlBuilder implements Cloneable {
public static final int FAV_CAT_LOCAL = -2;
public static final int FAV_CAT_ALL = -1;
private int mCat = -1;
private String mKeyword = null;
public int getCat() {
return mCat;
}
public void setCat(int cat) {
mCat = cat;
}
public String getKeyword() {
return mKeyword;
}
public void setKeyword(String keyword) {
mKeyword = keyword;
}
public boolean isLocal() {
return mCat == FAV_CAT_LOCAL;
}
public String build(int source, int page) {
UrlBuilder ub = new UrlBuilder(EhUrl.getUrlHeader(source) + "favorites.php");
if (mCat != FAV_CAT_ALL) {
ub.addQuery("favcat", mCat);
}
if (!TextUtils.isEmpty(mKeyword)) {
try {
ub.addQuery("f_search", URLEncoder.encode(mKeyword, "UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
ub.addQuery("f_apply", "Search+Favorites");
}
ub.addQuery("page", page);
return ub.build();
}
@Override
protected FavoriteUrlBuilder clone() {
try {
return (FavoriteUrlBuilder) super.clone();
} catch (CloneNotSupportedException e) {
throw new IllegalStateException(e);
}
}
}
@@ -94,6 +94,15 @@ public class EhHttpClient extends HttpClient {
protected void fillCookie(URL url, Cookie cookie) {
cookie.putRaw(mCookieManager.getCookie(url.toString()));
// Load these from config
cookie.remove(KEY_IPD_MEMBER_ID);
cookie.remove(KEY_IPD_MEMBER_ID);
cookie.remove(KEY_IGNEOUS);
cookie.remove(KEY_YAY);
cookie.remove(EhConfig.KEY_UCONFIG);
cookie.remove(EhConfig.KEY_LOFI_RESOLUTION);
cookie.remove(EhConfig.KEY_CONTENT_WARNING);
if (Utilities.contain(EHENTAI_DOMAIN, getDomain(url))) {
if (Settings.getSignIn()) {
// Put login info
@@ -33,6 +33,7 @@ import com.hippo.ehviewer.R;
import com.hippo.ehviewer.service.DownloadService;
import com.hippo.ehviewer.ui.scene.DownloadScene;
import com.hippo.ehviewer.ui.scene.DrawerProvider;
import com.hippo.ehviewer.ui.scene.FavoriteScene;
import com.hippo.ehviewer.ui.scene.GalleryListScene;
import com.hippo.ehviewer.ui.scene.HistoryScene;
import com.hippo.ehviewer.ui.scene.MainSettingsScene;
@@ -100,6 +101,7 @@ public final class ContentActivity extends StageActivity
startScene(HistoryScene.class);
break;
case DRAWER_LIST_FAVORITE:
startScene(FavoriteScene.class);
break;
case DRAWER_LIST_DOWNLOAD:
startScene(DownloadScene.class);
@@ -162,8 +162,8 @@ public abstract class AbsDragSortScene extends AppbarScene {
}
@Override
protected void onDetachFromeStage() {
super.onDetachFromeStage();
protected void onDetachedFromeWindow() {
super.onDetachedFromeWindow();
if (mRecyclerViewDragDropManager != null) {
mRecyclerViewDragDropManager.release();
@@ -0,0 +1,519 @@
/*
* Copyright 2015 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.ui.scene;
import android.animation.Animator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.hippo.animation.SimpleAnimatorListener;
import com.hippo.conaco.Conaco;
import com.hippo.drawable.DrawerArrowDrawable;
import com.hippo.ehviewer.EhApplication;
import com.hippo.ehviewer.EhCacheKeyFactory;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.client.EhClient;
import com.hippo.ehviewer.client.EhRequest;
import com.hippo.ehviewer.client.GalleryListParser;
import com.hippo.ehviewer.client.data.FavoriteUrlBuilder;
import com.hippo.ehviewer.client.data.GalleryBase;
import com.hippo.ehviewer.client.data.GalleryInfo;
import com.hippo.ehviewer.util.EhUtils;
import com.hippo.ehviewer.util.Settings;
import com.hippo.ehviewer.widget.ContentLayout;
import com.hippo.ehviewer.widget.LoadImageView;
import com.hippo.ehviewer.widget.OffsetLayout;
import com.hippo.ehviewer.widget.SearchBar;
import com.hippo.ehviewer.widget.SimpleRatingView;
import com.hippo.scene.Scene;
import com.hippo.widget.recyclerview.EasyRecyclerView;
import com.hippo.yorozuya.LayoutUtils;
import com.hippo.yorozuya.MathUtils;
import com.hippo.yorozuya.SimpleHandler;
import com.hippo.yorozuya.ViewUtils;
public class FavoriteScene extends Scene implements SearchBar.Helper, SearchBar.OnStateChangeListener {
private static final long ANIMATE_TIME = 300l;
private static final int STATE_NORMAL = 0;
private static final int STATE_SEARCH = 1;
private FavoriteUrlBuilder mUrlBuilder;
private ContentLayout mContentLayout;
private EasyRecyclerView mRecyclerView;
private SearchBar mSearchBar;
private DrawerArrowDrawable mLeftDrawable;
private FavoriteHelper mFavoriteHelper;
private FavoriteAdapter mFavoriteAdapter;
private int mSearchBarOriginalTop;
private int mSearchBarOriginalBottom;
private ValueAnimator mSearchBarMoveAnimator;
private int mState = STATE_NORMAL;
private EhRequest mEhRequest;
private int mFavCat = -1;
@Override
protected void onInit() {
super.onInit();
mUrlBuilder = new FavoriteUrlBuilder();
mFavoriteHelper = new FavoriteHelper();
}
@Override
protected void onDie() {
super.onDie();
if (mEhRequest != null) {
mEhRequest.cancel();
mEhRequest = null;
}
}
@Override
protected void onCreate(boolean rebirth) {
super.onCreate(rebirth);
setContentView(R.layout.scene_favorite);
Resources resources = getResources();
mContentLayout = (ContentLayout) findViewById(R.id.content_layout);
mSearchBar = (SearchBar) findViewById(R.id.search_bar);
mRecyclerView = mContentLayout.getRecyclerView();
ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) mSearchBar.getLayoutParams();
ViewUtils.measureView(mSearchBar, 200, ViewGroup.LayoutParams.WRAP_CONTENT);
int fitPaddingTop = mSearchBar.getMeasuredHeight() + lp.topMargin;
mContentLayout.setFitPaddingTop(fitPaddingTop);
mSearchBarOriginalTop = lp.topMargin;
mSearchBarOriginalBottom = lp.topMargin + mSearchBar.getMeasuredHeight();
mFavoriteAdapter = new FavoriteAdapter();
mContentLayout.setHelper(mFavoriteHelper);
mContentLayout.setAdapter(mFavoriteAdapter);
mRecyclerView.addOnScrollListener(new SearchBarMoveHelper());
mLeftDrawable = new DrawerArrowDrawable(getContext());
mSearchBar.setLeftDrawable(mLeftDrawable);
mSearchBar.setRightIconVisibility(View.GONE);
mSearchBar.setOnStateChangeListener(this);
mSearchBar.setTitle(resources.getString(R.string.favorite));
mSearchBar.setHelper(this);
mSearchBar.setEditTextMargin(LayoutUtils.dp2pix(getContext(), 56), LayoutUtils.dp2pix(getContext(), 16));
}
@Override
protected void onBind() {
super.onBind();
mFavoriteHelper.firstRefresh();
}
@Override
protected void onRestore() {
super.onRestore();
int state = mState;
// Reset state for set state
mState = STATE_NORMAL;
setState(state, false);
}
@Override
protected void onGetFitPaddingBottom(int b) {
mContentLayout.setFitPaddingBottom(b);
}
@Override
public void onBackPressed() {
switch (mState) {
case STATE_SEARCH:
setState(STATE_NORMAL);
break;
default:
case STATE_NORMAL:
super.onBackPressed();
break;
}
}
private void setState(int state) {
setState(state, true);
}
private void setState(int state, boolean animation) {
if (mState != state) {
mState = state;
if (state == STATE_SEARCH) {
// STATE_NORMAL => STATE_SEARCH
mSearchBar.setState(SearchBar.STATE_SEARCH_LIST, animation);
} else {
// STATE_SEARCH => STATE_NORMAL
mSearchBar.setState(SearchBar.STATE_NORMAL, animation);
}
}
}
@Override
public void onClickTitle() {
setState(STATE_SEARCH, true);
}
@Override
public void onClickLeftIcon() {
}
@Override
public void onClickRightIcon() {
}
@Override
public void onSearchEditTextClick() {
}
@Override
public void onApplySearch(String query) {
mUrlBuilder.setKeyword(query);
mFavoriteHelper.refresh();
}
private void showSearchBar(boolean animation) {
if (mSearchBar.isLayoutRequested()) {
return;
}
// Cancel old animator
if (mSearchBarMoveAnimator != null) {
mSearchBarMoveAnimator.cancel();
}
int offset = mSearchBarOriginalTop - mSearchBar.getTop();
if (offset != 0) {
if (animation) {
final boolean needRequestLayout = mSearchBar.getBottom() <= 0 && offset > 0;
final ValueAnimator va = ValueAnimator.ofInt(0, offset);
va.setDuration(ANIMATE_TIME);
va.addListener(new SimpleAnimatorListener() {
@Override
public void onAnimationEnd(Animator animation) {
mSearchBarMoveAnimator = null;
}
});
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
int lastValue;
boolean hasRequestLayout;
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (Integer) animation.getAnimatedValue();
int offsetStep = value - lastValue;
lastValue = value;
mSearchBar.offsetTopAndBottom(offsetStep);
((OffsetLayout.LayoutParams) mSearchBar.getLayoutParams()).offsetY += offsetStep;
if (!hasRequestLayout && needRequestLayout && mSearchBar.getBottom() > 0) {
hasRequestLayout = true;
mSearchBar.requestLayout();
}
}
});
if (mSearchBarMoveAnimator != null) {
mSearchBarMoveAnimator.cancel();
}
mSearchBarMoveAnimator = va;
va.start();
} else {
mSearchBar.offsetTopAndBottom(offset);
((OffsetLayout.LayoutParams) mSearchBar.getLayoutParams()).offsetY += offset;
}
}
}
private void returnSearchBarPosition() {
// Avoid weird shake
if (mSearchBar.isLayoutRequested()) {
return;
}
boolean show;
if (mState == STATE_SEARCH) {
show = true;
} else {
RecyclerView recyclerView = mContentLayout.getRecyclerView();
if (!recyclerView.isShown()) {
show = true;
} else if (recyclerView.computeVerticalScrollOffset() < mSearchBarOriginalBottom){
show = true;
} else {
show = mSearchBar.getBottom() > (mSearchBarOriginalBottom - mSearchBarOriginalTop) / 2;
}
}
int offset;
if (show) {
offset = mSearchBarOriginalTop - mSearchBar.getTop();
} else {
offset = -mSearchBar.getBottom();
}
if (offset != 0) {
final boolean needRequestLayout = mSearchBar.getBottom() <= 0 && offset > 0;
final ValueAnimator va = ValueAnimator.ofInt(0, offset);
va.setDuration(ANIMATE_TIME);
va.addListener(new SimpleAnimatorListener() {
@Override
public void onAnimationEnd(Animator animation) {
mSearchBarMoveAnimator = null;
}
});
va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
int lastValue;
boolean hasRequestLayout;
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int value = (Integer) animation.getAnimatedValue();
int offsetStep = value - lastValue;
lastValue = value;
mSearchBar.offsetTopAndBottom(offsetStep);
((OffsetLayout.LayoutParams) mSearchBar.getLayoutParams()).offsetY += offsetStep;
if (!hasRequestLayout && needRequestLayout && mSearchBar.getBottom() > 0) {
hasRequestLayout = true;
mSearchBar.requestLayout();
}
}
});
if (mSearchBarMoveAnimator != null) {
mSearchBarMoveAnimator.cancel();
}
mSearchBarMoveAnimator = va;
va.start();
}
}
@Override
public void onStateChange(int newState, int oldState, boolean animation) {
switch (oldState) {
default:
case SearchBar.STATE_NORMAL:
mLeftDrawable.setArrow(animation ? ANIMATE_TIME : 0);
break;
case SearchBar.STATE_SEARCH:
if (newState == SearchBar.STATE_NORMAL) {
mLeftDrawable.setMenu(animation ? ANIMATE_TIME : 0);
}
break;
case SearchBar.STATE_SEARCH_LIST:
if (newState == STATE_NORMAL) {
mLeftDrawable.setMenu(animation ? ANIMATE_TIME : 0);
}
break;
}
}
private class SearchBarMoveHelper extends RecyclerView.OnScrollListener {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState){
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
returnSearchBarPosition();
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
int oldBottom = mSearchBar.getBottom();
int offsetYStep = MathUtils.clamp(-dy, -mSearchBar.getBottom(), mSearchBarOriginalTop - mSearchBar.getTop());
mSearchBar.offsetTopAndBottom(offsetYStep);
((OffsetLayout.LayoutParams) mSearchBar.getLayoutParams()).offsetY += offsetYStep;
int newBottom = mSearchBar.getBottom();
// Sometimes if it is out of screen than go into again, it do not show,
// so I need to requestLayout
if (oldBottom <= 0 && newBottom > 0) {
mSearchBar.requestLayout();
}
}
}
private class FavoriteHolder extends RecyclerView.ViewHolder {
public LoadImageView thumb;
public TextView title;
public TextView uploader;
public SimpleRatingView rating;
public TextView category;
public TextView posted;
public TextView simpleLanguage;
public FavoriteHolder(View itemView) {
super(itemView);
thumb = (LoadImageView) itemView.findViewById(R.id.thumb);
title = (TextView) itemView.findViewById(R.id.title);
uploader = (TextView) itemView.findViewById(R.id.uploader);
rating = (SimpleRatingView) itemView.findViewById(R.id.rating);
category = (TextView) itemView.findViewById(R.id.category);
posted = (TextView) itemView.findViewById(R.id.posted);
simpleLanguage = (TextView) itemView.findViewById(R.id.simple_language);
}
}
private class FavoriteAdapter extends RecyclerView.Adapter<FavoriteHolder> {
@Override
public FavoriteHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = getStageActivity().getLayoutInflater().inflate(R.layout.item_gallery_list_detail, parent, false);
return new FavoriteHolder(view);
}
@Override
public void onBindViewHolder(FavoriteHolder holder, int position) {
GalleryBase gb = mFavoriteHelper.getDataAt(position);
Conaco conaco = EhApplication.getConaco(getStageActivity());
holder.thumb.load(conaco, EhCacheKeyFactory.getThumbKey(gb.gid), gb.thumb);
holder.title.setText(EhUtils.getSuitableTitle(gb));
holder.uploader.setText(gb.uploader);
holder.rating.setRating(gb.rating);
TextView category = holder.category;
String newCategoryText = EhUtils.getCategory(gb.category);
if (!newCategoryText.equals(category.getText())) {
category.setText(newCategoryText);
category.setBackgroundColor(EhUtils.getCategoryColor(gb.category));
}
holder.posted.setText(gb.posted);
holder.simpleLanguage.setText(gb.simpleLanguage);
}
@Override
public int getItemCount() {
return mFavoriteHelper.size();
}
}
private class FavoriteHelper extends ContentLayout.ContentHelper<GalleryInfo> {
private Runnable mSearchBarPositionTask = new Runnable() {
@Override
public void run() {
returnSearchBarPosition();
}
};
@Override
protected Context getContext() {
return getStageActivity();
}
@Override
protected RecyclerView.LayoutManager generateLayoutManager() {
return new StaggeredGridLayoutManager(1, StaggeredGridLayoutManager.VERTICAL);
}
@Override
protected void onScrollToPosition() {
SimpleHandler.getInstance().post(mSearchBarPositionTask);
}
@Override
protected void onShowProgress() {
showSearchBar(true);
}
@Override
protected void onShowText() {
showSearchBar(true);
}
@Override
protected void getPageData(int taskId, int type, int page) {
EhClient client = EhApplication.getEhClient(getStageActivity());
int source = Settings.getEhSource();
FavoriteListener listener = new FavoriteListener(taskId);
EhRequest request = new EhRequest();
request.setMethod(Settings.getJpnTitle() ? EhClient.METHOD_GET_GALLERY_LIST_JPN :
EhClient.METHOD_GET_GALLERY_LIST);
request.setEhListener(listener);
request.setArgs(mUrlBuilder.build(source, page), source, listener);
client.execute(request);
mEhRequest = request;
}
@Override
protected void notifyDataSetChanged() {
mFavoriteAdapter.notifyDataSetChanged();
}
@Override
protected void notifyItemRangeRemoved(int positionStart, int itemCount) {
mFavoriteAdapter.notifyItemRangeRemoved(positionStart, itemCount);
}
@Override
protected void notifyItemRangeInserted(int positionStart, int itemCount) {
mFavoriteAdapter.notifyItemRangeInserted(positionStart, itemCount);
}
}
private class FavoriteListener extends EhClient.EhListener<GalleryListParser.Result> {
private int mTaskId;
public FavoriteListener(int taskId) {
mTaskId = taskId;
}
@Override
public void onSuccess(GalleryListParser.Result result) {
mEhRequest = null;
mFavoriteHelper.setPageCount(result.pages);
mFavoriteHelper.onGetPageData(mTaskId, result.galleryInfos);
}
@Override
public void onFailure(Exception e) {
mEhRequest = null;
mFavoriteHelper.onGetPageData(mTaskId, e);
}
@Override
public void onCanceled() {
mEhRequest = null;
}
}
}
@@ -127,6 +127,7 @@ public final class GalleryListScene extends Scene implements ListSearchBar.Helpe
private ViewTransition mViewTransition;
private GalleryAdapter mAdapter;
private GalleryListHelper mGalleryListHelper;
private int mSearchBarOriginalTop;
@@ -156,6 +157,8 @@ public final class GalleryListScene extends Scene implements ListSearchBar.Helpe
private DrawerArrowDrawable mLeftDrawable;
private AddDeleteDrawable mRightDrawable;
private EhRequest mEhRequest;
private SimpleDialog.OnCreateCustomViewListener mGoToCreateCustomViewListener =
new SimpleDialog.OnCreateCustomViewListener() {
@Override
@@ -258,13 +261,6 @@ public final class GalleryListScene extends Scene implements ListSearchBar.Helpe
handleAnnouncer(announcer);
}
@Override
protected void onRebirth() {
super.onRebirth();
mGalleryListHelper = new GalleryListHelper(getStageActivity(), mGalleryListHelper);
}
@SuppressWarnings("deprecation")
@Override
protected void onCreate(boolean rebirth) {
@@ -289,6 +285,7 @@ public final class GalleryListScene extends Scene implements ListSearchBar.Helpe
mViewTransition = new ViewTransition(mContentLayout, mSearchLayout);
// Init
mSearchBar.setTitle(mResources.getString(R.string.app_name));
mSearchBar.setHelper(this);
ViewUtils.measureView(mSearchBar, ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
SearchBarMoveHelper sbmHelper = new SearchBarMoveHelper();
@@ -313,11 +310,8 @@ public final class GalleryListScene extends Scene implements ListSearchBar.Helpe
mSearchBarOriginalBottom = lp.topMargin + mSearchBar.getMeasuredHeight();
// Content Layout
// onRebirth may create new GalleryListHelper
if (mGalleryListHelper == null) {
mGalleryListHelper = new GalleryListHelper(mActivity);
}
mAdapter = new GalleryAdapter();
mContentLayout.setAdapter(mAdapter);
mContentLayout.setHelper(mGalleryListHelper);
mContentRecyclerView.setOnItemClickListener(this);
@@ -373,6 +367,8 @@ public final class GalleryListScene extends Scene implements ListSearchBar.Helpe
mJpnTitle = Settings.getJpnTitle();
Messenger.getInstance().register(Constants.MESSENGER_ID_JPN_TITLE, this);
Messenger.getInstance().register(Constants.MESSENGER_ID_UPDATE_QUICK_SEARCH, this);
mGalleryListHelper = new GalleryListHelper();
}
@Override
@@ -382,9 +378,9 @@ public final class GalleryListScene extends Scene implements ListSearchBar.Helpe
Messenger.getInstance().unregister(Constants.MESSENGER_ID_JPN_TITLE, this);
Messenger.getInstance().unregister(Constants.MESSENGER_ID_UPDATE_QUICK_SEARCH, this);
// Avoid memory leak
if (mGalleryListHelper.mListener != null) {
mGalleryListHelper.mListener.setGalleryListHelper(null);
if (mEhRequest != null) {
mEhRequest.cancel();
mEhRequest = null;
}
}
@@ -1069,9 +1065,46 @@ public final class GalleryListScene extends Scene implements ListSearchBar.Helpe
}
}
private class GalleryListHelper extends ContentLayout.ContentHelper<GalleryInfo, GalleryHolder> {
private class GalleryAdapter extends RecyclerView.Adapter<GalleryHolder> {
private GalleryListHelperSettable mListener;
@Override
public GalleryHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mActivity.getLayoutInflater().inflate(R.layout.item_gallery_list_detail, parent, false);
return new GalleryHolder(view);
}
@Override
public void onBindViewHolder(GalleryHolder holder, int position) {
GalleryInfo gi = mGalleryListHelper.getDataAt(position);
Conaco conaco = EhApplication.getConaco(getStageActivity());
holder.thumb.load(conaco, EhCacheKeyFactory.getThumbKey(gi.gid), gi.thumb);
String title;
if (mJpnTitle) {
title = TextUtils.isEmpty(gi.titleJpn) ? gi.title : gi.titleJpn;
} else {
title = gi.title;
}
holder.title.setText(title);
holder.uploader.setText(gi.uploader);
holder.rating.setRating(gi.rating);
TextView category = holder.category;
String newCategoryText = EhUtils.getCategory(gi.category);
if (!newCategoryText.equals(category.getText())) {
category.setText(newCategoryText);
category.setBackgroundColor(EhUtils.getCategoryColor(gi.category));
}
holder.posted.setText(gi.posted);
holder.simpleLanguage.setText(gi.simpleLanguage);
}
@Override
public int getItemCount() {
return mGalleryListHelper.size();
}
}
private class GalleryListHelper extends ContentLayout.ContentHelper<GalleryInfo> {
private Runnable mSearchBarPositionTask = new Runnable() {
@Override
@@ -1080,24 +1113,10 @@ public final class GalleryListScene extends Scene implements ListSearchBar.Helpe
}
};
public GalleryListHelper(Context context) {
super(context);
}
public GalleryListHelper(Context context, GalleryListHelper older) {
super(context, older);
// Update gallery listener
mListener = older.mListener;
if (mListener != null) {
mListener.setGalleryListHelper(this);
older.mListener = null;
}
}
private void clearLastGalleryListHelperSettable(GalleryListHelperSettable listener) {
if (mListener == listener) {
mListener = null;
}
@Override
protected Context getContext() {
// TODO it may raise exception
return getStageActivity();
}
@Override
@@ -1121,6 +1140,21 @@ public final class GalleryListScene extends Scene implements ListSearchBar.Helpe
showSearchBar(true);
}
@Override
protected void notifyDataSetChanged() {
mAdapter.notifyDataSetChanged();
}
@Override
protected void notifyItemRangeRemoved(int positionStart, int itemCount) {
mAdapter.notifyItemRangeRemoved(positionStart, itemCount);
}
@Override
protected void notifyItemRangeInserted(int positionStart, int itemCount) {
mAdapter.notifyItemRangeInserted(positionStart, itemCount);
}
@Override
protected void getPageData(int taskId, int type, int page) {
EhClient client = EhApplication.getEhClient(getStageActivity());
@@ -1129,78 +1163,41 @@ public final class GalleryListScene extends Scene implements ListSearchBar.Helpe
int mode = mListUrlBuilder.getMode();
if (mode == ListUrlBuilder.MODE_POPULAR) {
PopularListener listener = new PopularListener(taskId);
listener.setGalleryListHelper(this);
mListener = listener;
EhRequest request = new EhRequest();
request.setMethod(mJpnTitle ?
EhClient.METHOD_GET_POPULAR_JPN : EhClient.METHOD_GET_POPULAR);
request.setEhListener(listener);
request.setArgs(source);
client.execute(request);
mEhRequest = request;
} else {
try {
mListUrlBuilder.setPageIndex(page);
String url = mListUrlBuilder.build(source);
GalleryListListener listener = new GalleryListListener(taskId,
type, page, source);
listener.setGalleryListHelper(this);
mListener = listener;
EhRequest request = new EhRequest();
request.setMethod(mJpnTitle ?
EhClient.METHOD_GET_GALLERY_LIST_JPN : EhClient.METHOD_GET_GALLERY_LIST);
request.setEhListener(listener);
request.setArgs(url, source);
client.execute(request);
mEhRequest = request;
} catch (UnsupportedSearchException e) {
onGetPageData(taskId, e);
}
}
}
@Override
public GalleryHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mActivity.getLayoutInflater().inflate(R.layout.item_gallery_list_detail, parent, false);
return new GalleryHolder(view);
}
@Override
public void onBindViewHolder(GalleryHolder holder, int position) {
GalleryInfo gi = getDataAt(position);
Conaco conaco = EhApplication.getConaco(getStageActivity());
holder.thumb.load(conaco, EhCacheKeyFactory.getThumbKey(gi.gid), gi.thumb);
String title;
if (mJpnTitle) {
title = TextUtils.isEmpty(gi.titleJpn) ? gi.title : gi.titleJpn;
} else {
title = gi.title;
}
holder.title.setText(title);
holder.uploader.setText(gi.uploader);
holder.rating.setRating(gi.rating);
TextView category = holder.category;
String newCategoryText = EhUtils.getCategory(gi.category);
if (!newCategoryText.equals(category.getText())) {
category.setText(newCategoryText);
category.setBackgroundColor(EhUtils.getCategoryColor(gi.category));
}
holder.posted.setText(gi.posted);
holder.simpleLanguage.setText(gi.simpleLanguage);
}
}
private static class GalleryListListener extends EhClient.EhListener<GalleryListParser.Result>
implements GalleryListHelperSettable {
private class GalleryListListener extends EhClient.EhListener<GalleryListParser.Result> {
private int mTaskId;
private int mTaskType;
private int mTargetPage;
private int mSource;
private GalleryListHelper mHelper;
public GalleryListListener(int taskId, int taskType, int targetPage, int source) {
mTaskId = taskId;
mTaskType = taskType;
@@ -1208,88 +1205,64 @@ public final class GalleryListScene extends Scene implements ListSearchBar.Helpe
mSource = source;
}
@Override
public void setGalleryListHelper(GalleryListHelper helper) {
mHelper = helper;
}
@Override
public void onSuccess(GalleryListParser.Result result) {
if (mHelper != null) {
if (mSource == EhUrl.SOURCE_LOFI) {
if (result.pages == GalleryListParser.Result.CURRENT_PAGE_IS_LAST) {
mHelper.setPageCount(mTargetPage);
} else if (mTaskType == ContentLayout.ContentHelper.TYPE_REFRESH) {
mHelper.setPageCount(Integer.MAX_VALUE);
}
} else {
mHelper.setPageCount(result.pages);
}
mHelper.onGetPageData(mTaskId, result.galleryInfos);
mEhRequest = null;
mHelper.clearLastGalleryListHelperSettable(this);
if (mSource == EhUrl.SOURCE_LOFI) {
if (result.pages == GalleryListParser.Result.CURRENT_PAGE_IS_LAST) {
mGalleryListHelper.setPageCount(mTargetPage);
} else if (mTaskType == ContentLayout.ContentHelper.TYPE_REFRESH) {
mGalleryListHelper.setPageCount(Integer.MAX_VALUE);
}
} else {
mGalleryListHelper.setPageCount(result.pages);
}
mGalleryListHelper.onGetPageData(mTaskId, result.galleryInfos);
}
@Override
public void onFailure(Exception e) {
if (mHelper != null) {
mHelper.onGetPageData(mTaskId, e);
mEhRequest = null;
mHelper.clearLastGalleryListHelperSettable(this);
}
mGalleryListHelper.onGetPageData(mTaskId, e);
}
@Override
public void onCanceled() {
mEhRequest = null;
}
}
private static class PopularListener extends EhClient.EhListener<PopularParser.Result>
implements GalleryListHelperSettable {
private class PopularListener extends EhClient.EhListener<PopularParser.Result> {
private int mTaskId;
private GalleryListHelper mHelper;
public PopularListener(int taskId) {
mTaskId = taskId;
}
@Override
public void setGalleryListHelper(GalleryListHelper helper) {
mHelper = helper;
}
@Override
public void onSuccess(PopularParser.Result result) {
if (mHelper != null) {
mHelper.setPageCount(1);
mHelper.onGetPageData(mTaskId, result.galleryInfos);
mEhRequest = null;
mHelper.clearLastGalleryListHelperSettable(this);
}
mGalleryListHelper.setPageCount(1);
mGalleryListHelper.onGetPageData(mTaskId, result.galleryInfos);
}
@Override
public void onFailure(Exception e) {
if (mHelper != null) {
mHelper.onGetPageData(mTaskId, e);
mEhRequest = null;
mHelper.clearLastGalleryListHelperSettable(this);
}
mGalleryListHelper.onGetPageData(mTaskId, e);
}
@Override
public void onCanceled() {
mEhRequest = null;
}
}
private interface GalleryListHelperSettable {
void setGalleryListHelper(GalleryListHelper helper);
}
private class SimpleHolder extends RecyclerView.ViewHolder {
public SimpleHolder(View itemView) {
@@ -47,6 +47,7 @@ import com.hippo.yorozuya.Messenger;
import java.util.List;
// TODO Avoid get history in UI thread
public class HistoryScene extends AppbarScene implements EasyRecyclerView.OnItemClickListener,
Messenger.Receiver {
@@ -133,8 +134,8 @@ public class HistoryScene extends AppbarScene implements EasyRecyclerView.OnItem
}
@Override
protected void onDetachFromeStage() {
super.onDetachFromeStage();
protected void onDetachedFromeWindow() {
super.onDetachedFromeWindow();
if (mRecyclerViewSwipeManager != null) {
mRecyclerViewSwipeManager.release();
@@ -106,6 +106,10 @@ public class ContentLayout extends FrameLayout {
return mRecyclerView;
}
public void setAdapter(RecyclerView.Adapter adapter) {
mRecyclerView.setAdapter(adapter);
}
public void setHelper(ContentHelper helper) {
mContentHelper = helper;
helper.init(this);
@@ -135,8 +139,7 @@ public class ContentLayout extends FrameLayout {
super.onRestoreInstanceState(mContentHelper.onRestoreInstanceState(state));
}
public abstract static class ContentHelper<E, VH extends RecyclerView.ViewHolder>
extends EasyRecyclerView.Adapter<VH>
public abstract static class ContentHelper<E>
implements RefreshLayout.OnHeaderRefreshListener,
RefreshLayout.OnFooterRefreshListener, View.OnClickListener {
@@ -163,8 +166,6 @@ public class ContentLayout extends FrameLayout {
public static final int TYPE_NEXT_PAGE_KEEP_POS = 4;
public static final int TYPE_SOMEWHERE = 5;
private Context mContext;
private ProgressView mProgressView;
private ViewGroup mTipView;
private RefreshLayout mRefreshLayout;
@@ -253,29 +254,11 @@ public class ContentLayout extends FrameLayout {
}
};
public ContentHelper(Context context) {
mContext = context;
public ContentHelper() {
mData = new ArrayList<>();
mIdGenerator = new IdIntGenerator();
}
@SuppressWarnings("unchecked")
protected ContentHelper(Context context, ContentHelper older) {
this(context);
mData.addAll(older.mData);
mFirstPage = older.mFirstPage;
mLastPage = older.mLastPage;
mFirstIndex = older.mFirstIndex;
mLastIndex = older.mLastIndex;
mPageCount = older.mPageCount;
mCurrentPage = older.mCurrentPage;
mPageVolume = older.mPageVolume;
mCurrentTaskId = older.mCurrentTaskId;
mCurrentTaskType = older.mCurrentTaskType;
mCurrentTaskPage = older.mCurrentTaskPage;
}
private void init(ContentLayout contentLayout) {
mProgressView = contentLayout.mProgressView;
mTipView = contentLayout.mTipView;
@@ -289,7 +272,6 @@ public class ContentLayout extends FrameLayout {
mViewTransition.showView(2, false);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(this);
mRecyclerView.addOnScrollListener(mOnScrollListener);
mRefreshLayout.setOnHeaderRefreshListener(this);
mRefreshLayout.setOnFooterRefreshListener(this);
@@ -297,6 +279,8 @@ public class ContentLayout extends FrameLayout {
mTipView.setOnClickListener(this);
}
protected abstract Context getContext();
protected abstract RecyclerView.LayoutManager generateLayoutManager();
protected abstract void onScrollToPosition();
@@ -305,6 +289,12 @@ public class ContentLayout extends FrameLayout {
protected abstract void onShowText();
protected abstract void notifyDataSetChanged();
protected abstract void notifyItemRangeRemoved(int positionStart, int itemCount);
protected abstract void notifyItemRangeInserted(int positionStart, int itemCount);
public void showContent() {
mViewTransition.showView(0);
}
@@ -390,7 +380,7 @@ public class ContentLayout extends FrameLayout {
mLastIndex += pageVolume;
mRecyclerView.stopScroll();
LayoutManagerUtils.scrollToPositionProperly(mLayoutManager, mContext, mFirstIndex - 1, mOnScrollToPositionListener);
LayoutManagerUtils.scrollToPositionProperly(mLayoutManager, getContext(), mFirstIndex - 1, mOnScrollToPositionListener);
} else {
mCurrentPage = mFirstPage;
mFirstIndex = 0;
@@ -445,13 +435,13 @@ public class ContentLayout extends FrameLayout {
mRefreshLayout.setHeaderRefreshing(false);
mRefreshLayout.setFooterRefreshing(false);
Say.d(TAG, "Get page data failed " + e.getClass().getName() + " " + e.getMessage());
String readableError = ExceptionUtils.getReadableString(mContext, e);
String reason = ExceptionUtils.getReasonString(mContext, e);
String readableError = ExceptionUtils.getReadableString(getContext(), e);
String reason = ExceptionUtils.getReasonString(getContext(), e);
if (reason != null) {
readableError += '\n' + reason;
}
if (mViewTransition.getShownViewIndex() == 0) {
Toast.makeText(mContext, readableError, Toast.LENGTH_SHORT).show();
Toast.makeText(getContext(), readableError, Toast.LENGTH_SHORT).show();
} else {
showText(readableError);
}
@@ -515,7 +505,7 @@ public class ContentLayout extends FrameLayout {
// Go to top
mRecyclerView.stopScroll();
LayoutManagerUtils.scrollToPositionProperly(mLayoutManager,
mContext, 0, mOnScrollToPositionListener);
getContext(), 0, mOnScrollToPositionListener);
// Show header refresh
mRefreshLayout.setFooterRefreshing(false);
mRefreshLayout.setHeaderRefreshing(true);
@@ -591,8 +581,7 @@ public class ContentLayout extends FrameLayout {
onScrollToPosition();
}
@Override
public int getItemCount() {
public int size() {
return mData.size();
}
+11 -4
View File
@@ -211,6 +211,7 @@ public abstract class Scene {
// Not call setContentView in onCreate, create scene view by ourself
mSceneView = createSceneView(getStageActivity());
}
mSceneView.setScene(this);
mSceneView.setBackgroundColor(mBackgroundColor);
@@ -429,17 +430,23 @@ public abstract class Scene {
return getStageActivity().getStageLayout();
}
protected void onAttachToStage() {
protected void onAttachedToWindow() {
}
protected void onDetachFromeStage() {
protected void onDetachedFromeWindow() {
}
protected void onAttachedToStage() {
}
protected void onDetachedFromeStage() {
}
// Add scene view to stage layout
void attachToStage() {
if (mSceneView != null && !isInStage()) {
doAttachToStage();
onAttachToStage();
onAttachedToStage();
}
}
@@ -447,7 +454,7 @@ public abstract class Scene {
void detachFromeStage() {
if (mSceneView != null && isInStage()) {
doDetachFromeStage();
onDetachFromeStage();
onDetachedFromeStage();
}
}
@@ -35,6 +35,8 @@ public class SceneView extends AbsoluteLayout {
private float mStartX = -1f;
private float mStartY = -1f;
private Scene mScene;
public SceneView(Context context) {
super(context);
init();
@@ -55,6 +57,29 @@ public class SceneView extends AbsoluteLayout {
mPath = new Path();
}
public void setScene(Scene scene) {
mScene = scene;
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (mScene != null) {
mScene.onAttachedToWindow();
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mScene != null) {
mScene.onDetachedFromeWindow();
mScene = null;
}
}
public void setEnableTouch(boolean enableTouch) {
mEnableTouch = enableTouch;
}
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright 2015 Hippo Seven
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<com.hippo.ehviewer.widget.OffsetLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:auto="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.hippo.ehviewer.widget.ContentLayout
android:id="@+id/content_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<com.hippo.ehviewer.widget.SearchBar
android:id="@+id/search_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/search_bar_padding_horizontal"
android:layout_marginRight="@dimen/search_bar_padding_horizontal"
android:layout_marginTop="@dimen/search_bar_padding_vertical"
auto:cardElevation="4dp"
auto:forceNoElevation="true"/>
</com.hippo.ehviewer.widget.OffsetLayout>
@@ -41,7 +41,6 @@
android:layout_marginLeft="56dp"
android:layout_marginRight="56dp"
android:gravity="center_vertical"
android:text="@string/app_name"
android:textSize="@dimen/text_large"
android:textColor="@color/secondary_text_light"/>