From 55e7ef7c73cda26def4e49506663b42fcdcc0e43 Mon Sep 17 00:00:00 2001 From: seven332 Date: Fri, 11 Mar 2016 01:49:08 +0800 Subject: [PATCH] Add History --- .../main/java/com/hippo/ehviewer/EhDB.java | 26 ++ .../com/hippo/ehviewer/ui/MainActivity.java | 4 +- .../ehviewer/ui/scene/GalleryDetailScene.java | 9 +- .../hippo/ehviewer/ui/scene/HistoryScene.java | 312 ++++++++++++++++++ app/src/main/res/layout/scene_history.xml | 70 ++++ app/src/main/res/values/strings.xml | 3 + 6 files changed, 422 insertions(+), 2 deletions(-) create mode 100644 app/src/main/java/com/hippo/ehviewer/ui/scene/HistoryScene.java create mode 100644 app/src/main/res/layout/scene_history.xml diff --git a/app/src/main/java/com/hippo/ehviewer/EhDB.java b/app/src/main/java/com/hippo/ehviewer/EhDB.java index b70df4514..e9403e827 100644 --- a/app/src/main/java/com/hippo/ehviewer/EhDB.java +++ b/app/src/main/java/com/hippo/ehviewer/EhDB.java @@ -45,10 +45,14 @@ import com.hippo.yorozuya.sparse.SparseJLArray; import java.util.ArrayList; import java.util.List; +import de.greenrobot.dao.query.LazyList; + public class EhDB { private static final String TAG = EhDB.class.getSimpleName(); + private static final int MAX_HISTORY_COUNT = 100; + private static DaoSession sDaoSession; private static boolean sHasOldDB; @@ -502,4 +506,26 @@ public class EhDB { dao.updateInTx(list); } + + public static synchronized LazyList getHistoryLazyList() { + return sDaoSession.getHistoryDao().queryBuilder().orderDesc(HistoryDao.Properties.Time).listLazy(); + } + + public static synchronized void putHistoryInfo(GalleryInfo galleryInfo) { + HistoryDao dao = sDaoSession.getHistoryDao(); + HistoryInfo info = dao.load(galleryInfo.gid); + if (null != info) { + // Update time + info.time = System.currentTimeMillis(); + dao.update(info); + } else { + // New history + info = new HistoryInfo(galleryInfo); + info.time = System.currentTimeMillis(); + dao.insert(info); + List list = dao.queryBuilder().orderDesc(HistoryDao.Properties.Time) + .limit(-1).offset(MAX_HISTORY_COUNT).list(); + dao.deleteInTx(list); + } + } } diff --git a/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.java b/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.java index 229e3d9d5..d50c98701 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/MainActivity.java @@ -51,6 +51,7 @@ import com.hippo.ehviewer.ui.scene.GalleryDetailScene; import com.hippo.ehviewer.ui.scene.GalleryInfoScene; import com.hippo.ehviewer.ui.scene.GalleryListScene; import com.hippo.ehviewer.ui.scene.GalleryPreviewsScene; +import com.hippo.ehviewer.ui.scene.HistoryScene; import com.hippo.ehviewer.ui.scene.ProgressScene; import com.hippo.ehviewer.ui.scene.QuickSearchScene; import com.hippo.ehviewer.ui.scene.SignInScene; @@ -108,6 +109,7 @@ public final class MainActivity extends StageActivity registerLaunchMode(DownloadsScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK); registerLaunchMode(DownloadLabelScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK); registerLaunchMode(FavoritesScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TASK); + registerLaunchMode(HistoryScene.class, SceneFragment.LAUNCH_MODE_SINGLE_TOP); registerLaunchMode(ProgressScene.class, SceneFragment.LAUNCH_MODE_STANDARD); } @@ -434,7 +436,7 @@ public final class MainActivity extends StageActivity } else if (id == R.id.nav_favourite) { startScene(new Announcer(FavoritesScene.class)); } else if (id == R.id.nav_history) { - + startScene(new Announcer(HistoryScene.class)); } else if (id == R.id.nav_downloads) { startScene(new Announcer(DownloadsScene.class)); } else if (id == R.id.nav_settings) { diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.java index eb804e8e1..6f2dc4dac 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/GalleryDetailScene.java @@ -285,6 +285,10 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene mAction = action; if (ACTION_GALLERY_INFO.equals(action)) { mGalleryInfo = args.getParcelable(KEY_GALLERY_INFO); + // Add history + if (null != mGalleryInfo) { + EhDB.putHistoryInfo(mGalleryInfo); + } } else if (ACTION_GID_TOKEN.equals(action)) { mGid = args.getLong(KEY_GID); mToken = args.getString(KEY_TOKEN); @@ -1263,7 +1267,7 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene public boolean onTransition(Context context, FragmentTransaction transaction, Fragment exit, Fragment enter) { if (!(enter instanceof GalleryListScene) && !(enter instanceof DownloadsScene) && - !(enter instanceof FavoritesScene)) { + !(enter instanceof FavoritesScene) && !(enter instanceof HistoryScene)) { return false; } @@ -1488,6 +1492,9 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene EhCacheKeyFactory.getLargePreviewSetKey(result.gid, 0), result.previewSet); EhApplication.getPreviewPagesCache(getApplication()).put(result.gid, result.previewPages); + // Add history + EhDB.putHistoryInfo(result); + // Notify success GalleryDetailScene scene = getScene(); if (scene != null) { diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/HistoryScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/HistoryScene.java new file mode 100644 index 000000000..994bd6750 --- /dev/null +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/HistoryScene.java @@ -0,0 +1,312 @@ +/* + * Copyright 2016 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.annotation.TargetApi; +import android.content.Context; +import android.content.DialogInterface; +import android.content.res.Resources; +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentTransaction; +import android.support.v7.app.AlertDialog; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; +import android.transition.TransitionInflater; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.hippo.easyrecyclerview.EasyRecyclerView; +import com.hippo.easyrecyclerview.FastScroller; +import com.hippo.easyrecyclerview.HandlerDrawable; +import com.hippo.ehviewer.EhDB; +import com.hippo.ehviewer.R; +import com.hippo.ehviewer.client.EhCacheKeyFactory; +import com.hippo.ehviewer.client.EhUtils; +import com.hippo.ehviewer.client.data.GalleryInfo; +import com.hippo.ehviewer.dao.HistoryInfo; +import com.hippo.ehviewer.ui.CommonOperations; +import com.hippo.ehviewer.widget.SimpleRatingView; +import com.hippo.rippleold.RippleSalon; +import com.hippo.scene.Announcer; +import com.hippo.scene.SceneFragment; +import com.hippo.scene.StageActivity; +import com.hippo.scene.TransitionHelper; +import com.hippo.util.ApiHelper; +import com.hippo.view.ViewTransition; +import com.hippo.widget.LoadImageView; +import com.hippo.yorozuya.ResourcesUtils; +import com.hippo.yorozuya.ViewUtils; + +import de.greenrobot.dao.query.LazyList; + +public class HistoryScene extends ToolbarScene + implements EasyRecyclerView.OnItemClickListener, + EasyRecyclerView.OnItemLongClickListener{ + + /*--------------- + View life cycle + ---------------*/ + @Nullable + private EasyRecyclerView mRecyclerView; + @Nullable + private ViewTransition mViewTransition; + @Nullable + private HistoryAdapter mAdapter; + @Nullable + private LazyList mList; + + @Override + public int getNavCheckedItem() { + return R.id.nav_history; + } + + @Nullable + @Override + public View onCreateView2(LayoutInflater inflater, + @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.scene_history, container, false); + View content = ViewUtils.$$(view, R.id.content); + mRecyclerView = (EasyRecyclerView) ViewUtils.$$(content, R.id.recycler_view); + FastScroller fastScroller = (FastScroller) ViewUtils.$$(content, R.id.fast_scroller); + View tip = ViewUtils.$$(view, R.id.tip); + mViewTransition = new ViewTransition(content, tip); + + Resources resources = getResources(); + + mList = EhDB.getHistoryLazyList(); + mAdapter = new HistoryAdapter(); + mRecyclerView.setAdapter(mAdapter); + mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext())); + mRecyclerView.setSelector(RippleSalon.generateRippleDrawable(false)); + mRecyclerView.setDrawSelectorOnTop(true); + mRecyclerView.hasFixedSize(); + mRecyclerView.setClipToPadding(false); + mRecyclerView.setOnItemClickListener(this); + mRecyclerView.setOnItemLongClickListener(this); + int paddingH = resources.getDimensionPixelOffset(R.dimen.list_content_margin_h); + int paddingV = resources.getDimensionPixelOffset(R.dimen.list_content_margin_v); + mRecyclerView.setPadding(paddingV, paddingH, paddingV, paddingH); + + fastScroller.attachToRecyclerView(mRecyclerView); + HandlerDrawable drawable = new HandlerDrawable(); + drawable.setColor(ResourcesUtils.getAttrColor(getContext(), R.attr.colorAccent)); + fastScroller.setHandlerDrawable(drawable); + + if (null != mList && mList.size() > 0) { + mViewTransition.showView(0); + } else { + mViewTransition.showView(1); + } + + return view; + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + setTitle(R.string.history); + setNavigationIcon(R.drawable.v_arrow_left_dark_x24); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + + mRecyclerView = null; + mViewTransition = null; + mAdapter = null; + if (null != mList) { + mList.close(); + mList = null; + } + } + + @Override + public boolean onItemClick(EasyRecyclerView parent, View view, int position, long id) { + if (null == mList || null == mRecyclerView) { + return false; + } + + Bundle args = new Bundle(); + args.putString(GalleryDetailScene.KEY_ACTION, GalleryDetailScene.ACTION_GALLERY_INFO); + args.putParcelable(GalleryDetailScene.KEY_GALLERY_INFO, mList.get(position)); + Announcer announcer = new Announcer(GalleryDetailScene.class).setArgs(args); + if (ApiHelper.SUPPORT_TRANSITION) { + HistoryHolder holder = (HistoryHolder) mRecyclerView.getChildViewHolder(view); + announcer.setTranHelper(new EnterGalleryDetailTransaction(holder)); + } + startScene(announcer); + return true; + } + + @Override + public boolean onItemLongClick(EasyRecyclerView parent, View view, int position, long id) { + if (null == mList) { + return false; + } + + final GalleryInfo gi = mList.get(position); + new AlertDialog.Builder(getContext()) + .setTitle(EhUtils.getSuitableTitle(gi)) + .setItems(R.array.gallery_list_menu_entries, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + switch (which) { + case 0: // Download + CommonOperations.startDownload(getActivity(), gi); + break; + case 1: // Favorites + CommonOperations.addToFavorites(getActivity(), gi, + new addToFavoriteListener(getContext(), + ((StageActivity) getActivity()).getStageId(), getTag())); + break; + } + } + }).show(); + return true; + } + + private class HistoryHolder extends RecyclerView.ViewHolder { + + private final LoadImageView thumb; + private final TextView title; + private final TextView uploader; + private final SimpleRatingView rating; + private final TextView category; + private final TextView posted; + private final TextView simpleLanguage; + + public HistoryHolder(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 HistoryAdapter extends RecyclerView.Adapter { + + @Override + public HistoryHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new HistoryHolder(getActivity().getLayoutInflater() + .inflate(R.layout.item_gallery_list, parent, false)); + } + + @Override + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + public void onBindViewHolder(HistoryHolder holder, int position) { + if (null == mList) { + return; + } + + GalleryInfo gi = mList.get(position); + holder.thumb.load(EhCacheKeyFactory.getThumbKey(gi.gid), gi.thumb, true); + holder.title.setText(EhUtils.getSuitableTitle(gi)); + 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); + + // Update transition name + if (ApiHelper.SUPPORT_TRANSITION) { + long gid = gi.gid; + holder.thumb.setTransitionName(TransitionNameFactory.getThumbTransitionName(gid)); + holder.title.setTransitionName(TransitionNameFactory.getTitleTransitionName(gid)); + holder.uploader.setTransitionName(TransitionNameFactory.getUploaderTransitionName(gid)); + holder.category.setTransitionName(TransitionNameFactory.getCategoryTransitionName(gid)); + } + } + + @Override + public int getItemCount() { + return mList != null ? mList.size() : 0; + } + } + + private static class EnterGalleryDetailTransaction implements TransitionHelper { + + private final HistoryHolder mHolder; + + public EnterGalleryDetailTransaction(HistoryHolder holder) { + mHolder = holder; + } + + @TargetApi(Build.VERSION_CODES.LOLLIPOP) + @Override + public boolean onTransition(Context context, FragmentTransaction transaction, + Fragment exit, Fragment enter) { + if (mHolder == null || !(enter instanceof GalleryDetailScene)) { + return false; + } + + exit.setSharedElementReturnTransition( + TransitionInflater.from(context).inflateTransition(R.transition.trans_move)); + exit.setExitTransition( + TransitionInflater.from(context).inflateTransition(android.R.transition.fade)); + enter.setSharedElementEnterTransition( + TransitionInflater.from(context).inflateTransition(R.transition.trans_move)); + enter.setEnterTransition( + TransitionInflater.from(context).inflateTransition(android.R.transition.fade)); + transaction.addSharedElement(mHolder.thumb, mHolder.thumb.getTransitionName()); + transaction.addSharedElement(mHolder.title, mHolder.title.getTransitionName()); + transaction.addSharedElement(mHolder.uploader, mHolder.uploader.getTransitionName()); + transaction.addSharedElement(mHolder.category, mHolder.category.getTransitionName()); + return true; + } + } + + private static class addToFavoriteListener extends EhCallback { + + public addToFavoriteListener(Context context, int stageId, String sceneTag) { + super(context, stageId, sceneTag); + } + + @Override + public void onSuccess(Void result) { + showTip(R.string.add_to_favorite_success, LENGTH_SHORT); + } + + @Override + public void onFailure(Exception e) { + showTip(R.string.add_to_favorite_failure, LENGTH_SHORT); + } + + @Override + public void onCancel() {} + + @Override + public boolean isInstance(SceneFragment scene) { + return scene instanceof HistoryScene; + } + } +} diff --git a/app/src/main/res/layout/scene_history.xml b/app/src/main/res/layout/scene_history.xml new file mode 100644 index 000000000..0d874ee3c --- /dev/null +++ b/app/src/main/res/layout/scene_history.xml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index eb8781d83..de063ffa2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -295,6 +295,9 @@ Delete label Delete \"%s\"? + + Viewed galleries will be shown here + Page %d @string/refresh