From 1c38f77b5c4df92221b6350372bf3e8e9041a198 Mon Sep 17 00:00:00 2001 From: tarsin Date: Fri, 12 Aug 2022 15:29:04 +0800 Subject: [PATCH] Refactor history with room paging --- .../main/java/com/hippo/ehviewer/EhDB.java | 7 +- .../com/hippo/ehviewer/dao/HistoryDao.java | 4 + .../hippo/ehviewer/ui/scene/HistoryScene.kt | 936 ++++++++---------- 3 files changed, 399 insertions(+), 548 deletions(-) diff --git a/app/src/main/java/com/hippo/ehviewer/EhDB.java b/app/src/main/java/com/hippo/ehviewer/EhDB.java index e610ed890..062cd2548 100644 --- a/app/src/main/java/com/hippo/ehviewer/EhDB.java +++ b/app/src/main/java/com/hippo/ehviewer/EhDB.java @@ -22,6 +22,7 @@ import android.net.Uri; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.paging.PagingSource; import androidx.room.Room; import com.hippo.ehviewer.client.data.GalleryInfo; @@ -326,10 +327,14 @@ public class EhDB { dao.update(list); } - public static synchronized List getHistoryLazyList() { + public static synchronized List getHistoryList() { return db.historyDao().list(); } + public static synchronized PagingSource getHistoryLazyList() { + return db.historyDao().listLazy(); + } + public static synchronized void putHistoryInfo(GalleryInfo galleryInfo) { HistoryDao dao = db.historyDao(); HistoryInfo info = dao.load(galleryInfo.gid); diff --git a/app/src/main/java/com/hippo/ehviewer/dao/HistoryDao.java b/app/src/main/java/com/hippo/ehviewer/dao/HistoryDao.java index fafef1844..da78e07fb 100644 --- a/app/src/main/java/com/hippo/ehviewer/dao/HistoryDao.java +++ b/app/src/main/java/com/hippo/ehviewer/dao/HistoryDao.java @@ -1,5 +1,6 @@ package com.hippo.ehviewer.dao; +import androidx.paging.PagingSource; import androidx.room.Dao; import androidx.room.Delete; import androidx.room.Insert; @@ -19,6 +20,9 @@ public interface HistoryDao extends BasicDao { @Query("SELECT * FROM HISTORY ORDER BY TIME DESC LIMIT :limit OFFSET :offset") List list(int offset, int limit); + @Query("SELECT * FROM HISTORY ORDER BY TIME DESC") + PagingSource listLazy(); + @Update void update(HistoryInfo historyInfo); diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/HistoryScene.kt b/app/src/main/java/com/hippo/ehviewer/ui/scene/HistoryScene.kt index 8f69b5756..452739419 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/HistoryScene.kt +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/HistoryScene.kt @@ -13,635 +13,477 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +package com.hippo.ehviewer.ui.scene -package com.hippo.ehviewer.ui.scene; +import android.annotation.SuppressLint +import android.content.Context +import android.content.DialogInterface +import android.content.Intent +import android.os.Bundle +import android.text.TextUtils +import android.view.* +import android.widget.ImageView +import android.widget.TextView +import androidx.core.content.ContextCompat +import androidx.core.view.ViewCompat +import androidx.lifecycle.lifecycleScope +import androidx.paging.Pager +import androidx.paging.PagingConfig +import androidx.paging.PagingDataAdapter +import androidx.paging.cachedIn +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.StaggeredGridLayoutManager +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.hippo.easyrecyclerview.EasyRecyclerView +import com.hippo.easyrecyclerview.FastScroller +import com.hippo.easyrecyclerview.HandlerDrawable +import com.hippo.easyrecyclerview.MarginItemDecoration +import com.hippo.ehviewer.* +import com.hippo.ehviewer.client.EhCacheKeyFactory +import com.hippo.ehviewer.client.EhUtils +import com.hippo.ehviewer.client.data.GalleryInfo +import com.hippo.ehviewer.dao.DownloadInfo +import com.hippo.ehviewer.dao.HistoryInfo +import com.hippo.ehviewer.download.DownloadManager +import com.hippo.ehviewer.download.DownloadManager.DownloadInfoListener +import com.hippo.ehviewer.ui.CommonOperations +import com.hippo.ehviewer.ui.GalleryActivity +import com.hippo.ehviewer.ui.dialog.SelectItemWithIconAdapter +import com.hippo.ehviewer.widget.SimpleRatingView +import com.hippo.scene.Announcer +import com.hippo.scene.SceneFragment +import com.hippo.view.ViewTransition +import com.hippo.widget.LoadImageView +import com.hippo.widget.recyclerview.AutoStaggeredGridLayoutManager +import com.hippo.yorozuya.ViewUtils +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch +import rikka.core.res.resolveColor -import android.annotation.SuppressLint; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.res.Resources; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.text.TextUtils; -import android.view.Gravity; -import android.view.LayoutInflater; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.TextView; +class HistoryScene : ToolbarScene() { + private var mRecyclerView: EasyRecyclerView? = null + private var mViewTransition: ViewTransition? = null + private var mAdapter: HistoryAdapter? = null + private var mDownloadManager: DownloadManager? = null + private var mDownloadInfoListener: DownloadInfoListener? = null + private var mFavouriteStatusRouter: FavouriteStatusRouter? = null + private var mFavouriteStatusRouterListener: FavouriteStatusRouter.Listener? = null -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.content.ContextCompat; -import androidx.core.view.ViewCompat; -import androidx.recyclerview.widget.ItemTouchHelper; -import androidx.recyclerview.widget.RecyclerView; -import androidx.recyclerview.widget.StaggeredGridLayoutManager; - -import com.google.android.material.dialog.MaterialAlertDialogBuilder; -import com.hippo.easyrecyclerview.EasyRecyclerView; -import com.hippo.easyrecyclerview.FastScroller; -import com.hippo.easyrecyclerview.HandlerDrawable; -import com.hippo.easyrecyclerview.MarginItemDecoration; -import com.hippo.ehviewer.EhApplication; -import com.hippo.ehviewer.EhDB; -import com.hippo.ehviewer.FavouriteStatusRouter; -import com.hippo.ehviewer.R; -import com.hippo.ehviewer.Settings; -import com.hippo.ehviewer.client.EhCacheKeyFactory; -import com.hippo.ehviewer.client.EhUtils; -import com.hippo.ehviewer.client.data.GalleryInfo; -import com.hippo.ehviewer.dao.DownloadInfo; -import com.hippo.ehviewer.dao.DownloadLabel; -import com.hippo.ehviewer.dao.HistoryInfo; -import com.hippo.ehviewer.download.DownloadManager; -import com.hippo.ehviewer.ui.CommonOperations; -import com.hippo.ehviewer.ui.GalleryActivity; -import com.hippo.ehviewer.ui.MainActivity; -import com.hippo.ehviewer.ui.dialog.SelectItemWithIconAdapter; -import com.hippo.ehviewer.widget.SimpleRatingView; -import com.hippo.scene.Announcer; -import com.hippo.scene.SceneFragment; -import com.hippo.view.ViewTransition; -import com.hippo.widget.LoadImageView; -import com.hippo.widget.recyclerview.AutoStaggeredGridLayoutManager; -import com.hippo.yorozuya.AssertUtils; -import com.hippo.yorozuya.ViewUtils; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import rikka.core.res.ResourcesKt; - -public class HistoryScene extends ToolbarScene { - - /*--------------- - View life cycle - ---------------*/ - @Nullable - private TextView mTip; - @Nullable - private FastScroller mFastScroller; - @Nullable - private EasyRecyclerView mRecyclerView; - @Nullable - private ViewTransition mViewTransition; - @Nullable - private RecyclerView.Adapter mAdapter; - @Nullable - private List mLazyList; - - private DownloadManager mDownloadManager; - private DownloadManager.DownloadInfoListener mDownloadInfoListener; - private FavouriteStatusRouter mFavouriteStatusRouter; - private FavouriteStatusRouter.Listener mFavouriteStatusRouterListener; - - @Override - public void onDestroy() { - super.onDestroy(); - - mDownloadManager.removeDownloadInfoListener(mDownloadInfoListener); - mFavouriteStatusRouter.removeListener(mFavouriteStatusRouterListener); + override fun onDestroy() { + super.onDestroy() + mDownloadManager!!.removeDownloadInfoListener(mDownloadInfoListener) + mFavouriteStatusRouter!!.removeListener(mFavouriteStatusRouterListener) } - @Override - public int getNavCheckedItem() { - return R.id.nav_history; + override fun getNavCheckedItem(): Int { + return R.id.nav_history } - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - Context context = getContext(); - assert context != null; - mDownloadManager = EhApplication.getDownloadManager(context); - mDownloadManager = EhApplication.getDownloadManager(context); - mFavouriteStatusRouter = EhApplication.getFavouriteStatusRouter(context); - - mDownloadInfoListener = new DownloadManager.DownloadInfoListener() { - @Override - public void onAdd(@NonNull DownloadInfo info, @NonNull List list, int position) { - if (mAdapter != null) { - mAdapter.notifyDataSetChanged(); - } + @SuppressLint("NotifyDataSetChanged") + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + val context = requireContext() + mDownloadManager = EhApplication.getDownloadManager(context) + mFavouriteStatusRouter = EhApplication.getFavouriteStatusRouter(context) + mDownloadInfoListener = object : DownloadInfoListener { + override fun onAdd(info: DownloadInfo, list: List, position: Int) { + mAdapter?.notifyDataSetChanged() } - @Override - public void onUpdate(@NonNull DownloadInfo info, @NonNull List list) { + override fun onUpdate(info: DownloadInfo, list: List) {} + override fun onUpdateAll() {} + override fun onReload() { + mAdapter?.notifyDataSetChanged() } - @Override - public void onUpdateAll() { + override fun onChange() { + mAdapter?.notifyDataSetChanged() } - @Override - public void onReload() { - if (mAdapter != null) { - mAdapter.notifyDataSetChanged(); - } + override fun onRenameLabel(from: String, to: String) {} + override fun onRemove(info: DownloadInfo, list: List, position: Int) { + mAdapter?.notifyDataSetChanged() } - @Override - public void onChange() { - if (mAdapter != null) { - mAdapter.notifyDataSetChanged(); - } - } - - @Override - public void onRenameLabel(String from, String to) { - } - - @Override - public void onRemove(@NonNull DownloadInfo info, @NonNull List list, int position) { - if (mAdapter != null) { - mAdapter.notifyDataSetChanged(); - } - } - - @Override - public void onUpdateLabels() { - } - }; - mDownloadManager.addDownloadInfoListener(mDownloadInfoListener); - - mFavouriteStatusRouterListener = (gid, slot) -> { - if (mAdapter != null) { - mAdapter.notifyDataSetChanged(); - } - }; - mFavouriteStatusRouter.addListener(mFavouriteStatusRouterListener); + override fun onUpdateLabels() {} + } + mDownloadManager!!.addDownloadInfoListener(mDownloadInfoListener) + mFavouriteStatusRouterListener = FavouriteStatusRouter.Listener { _: Long, _: Int -> + mAdapter?.notifyDataSetChanged() + } + mFavouriteStatusRouter!!.addListener(mFavouriteStatusRouterListener) } - @Nullable - @Override - public View onCreateViewWithToolbar(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); - mFastScroller = (FastScroller) ViewUtils.$$(content, R.id.fast_scroller); - mTip = (TextView) ViewUtils.$$(view, R.id.tip); - mViewTransition = new ViewTransition(content, mTip); + override fun onCreateViewWithToolbar( + inflater: LayoutInflater, + container: ViewGroup?, savedInstanceState: Bundle? + ): View? { + val view = inflater.inflate(R.layout.scene_history, container, false) + val content = ViewUtils.`$$`(view, R.id.content) + val recyclerView = ViewUtils.`$$`(content, R.id.recycler_view) as EasyRecyclerView + val mFastScroller = ViewUtils.`$$`(content, R.id.fast_scroller) as FastScroller + val mTip = ViewUtils.`$$`(view, R.id.tip) as TextView + mViewTransition = ViewTransition(content, mTip) + val resources = requireContext().resources + val drawable = ContextCompat.getDrawable(requireContext(), R.drawable.big_history) + drawable!!.setBounds(0, 0, drawable.intrinsicWidth, drawable.intrinsicHeight) + mTip.setCompoundDrawables(null, drawable, null, null) + val historyData = Pager( + PagingConfig(20) + ) { + EhDB.getHistoryLazyList() + }.flow.cachedIn(viewLifecycleOwner.lifecycleScope) + mAdapter = HistoryAdapter(object : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: HistoryInfo, newItem: HistoryInfo): Boolean { + return oldItem.gid == newItem.gid + } - Context context = getContext(); - AssertUtils.assertNotNull(context); - Resources resources = context.getResources(); - - Drawable drawable = ContextCompat.getDrawable(context, R.drawable.big_history); - drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); - mTip.setCompoundDrawables(null, drawable, null, null); - - mAdapter = new HistoryAdapter(); - mAdapter.setHasStableIds(true); - mRecyclerView.setAdapter(mAdapter); - AutoStaggeredGridLayoutManager layoutManager = new AutoStaggeredGridLayoutManager( - 0, StaggeredGridLayoutManager.VERTICAL); - layoutManager.setColumnSize(resources.getDimensionPixelOffset(Settings.getDetailSizeResId())); - layoutManager.setStrategy(AutoStaggeredGridLayoutManager.STRATEGY_MIN_SIZE); - mRecyclerView.setLayoutManager(layoutManager); - mRecyclerView.setClipToPadding(false); - mRecyclerView.setClipChildren(false); - int interval = resources.getDimensionPixelOffset(R.dimen.gallery_list_interval); - int paddingH = resources.getDimensionPixelOffset(R.dimen.gallery_list_margin_h); - int paddingV = resources.getDimensionPixelOffset(R.dimen.gallery_list_margin_v); - MarginItemDecoration decoration = new MarginItemDecoration(interval, paddingH, paddingV, paddingH, paddingV); - mRecyclerView.addItemDecoration(decoration); - ItemTouchHelper itemTouchHelper = new ItemTouchHelper(new HistoryItemTouchHelperCallback()); - itemTouchHelper.attachToRecyclerView(mRecyclerView); - mFastScroller.attachToRecyclerView(mRecyclerView); - HandlerDrawable handlerDrawable = new HandlerDrawable(); - handlerDrawable.setColor(ResourcesKt.resolveColor(getTheme(), com.google.android.material.R.attr.colorPrimary)); - mFastScroller.setHandlerDrawable(handlerDrawable); - - updateLazyList(); - updateView(false); - - return view; - } - - @Override - public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - setTitle(R.string.history); - setNavigationIcon(R.drawable.ic_baseline_menu_24); - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - - if (null != mLazyList) { - mLazyList = null; - if (mAdapter != null) { - mAdapter.notifyDataSetChanged(); + override fun areContentsTheSame(oldItem: HistoryInfo, newItem: HistoryInfo): Boolean { + return oldItem.gid == newItem.gid + } + }) + recyclerView.adapter = mAdapter + val layoutManager = AutoStaggeredGridLayoutManager( + 0, StaggeredGridLayoutManager.VERTICAL + ) + layoutManager.setColumnSize(resources.getDimensionPixelOffset(Settings.getDetailSizeResId())) + layoutManager.setStrategy(AutoStaggeredGridLayoutManager.STRATEGY_MIN_SIZE) + recyclerView.layoutManager = layoutManager + recyclerView.clipToPadding = false + recyclerView.clipChildren = false + val interval = resources.getDimensionPixelOffset(R.dimen.gallery_list_interval) + val paddingH = resources.getDimensionPixelOffset(R.dimen.gallery_list_margin_h) + val paddingV = resources.getDimensionPixelOffset(R.dimen.gallery_list_margin_v) + val decoration = MarginItemDecoration(interval, paddingH, paddingV, paddingH, paddingV) + recyclerView.addItemDecoration(decoration) + val itemTouchHelper = ItemTouchHelper(HistoryItemTouchHelperCallback()) + itemTouchHelper.attachToRecyclerView(recyclerView) + mFastScroller.attachToRecyclerView(recyclerView) + mRecyclerView = recyclerView + val handlerDrawable = HandlerDrawable() + handlerDrawable.setColor(theme.resolveColor(com.google.android.material.R.attr.colorPrimary)) + mFastScroller.setHandlerDrawable(handlerDrawable) + viewLifecycleOwner.lifecycleScope.launch { + historyData.collectLatest { value -> + mAdapter!!.submitData( + value + ) } } - if (null != mRecyclerView) { - mRecyclerView.stopScroll(); - mRecyclerView = null; - } - - mViewTransition = null; - mAdapter = null; + return view } - // Remember to notify - private void updateLazyList() { - mLazyList = EhDB.getHistoryLazyList(); + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setTitle(R.string.history) + setNavigationIcon(R.drawable.ic_baseline_menu_24) } - private void updateView(boolean animation) { - if (null == mAdapter || null == mViewTransition) { - return; - } - - if (mAdapter.getItemCount() == 0) { - mViewTransition.showView(1, animation); - } else { - mViewTransition.showView(0, animation); - } + override fun onDestroyView() { + super.onDestroyView() + mRecyclerView?.stopScroll() + mRecyclerView = null + mViewTransition = null + mAdapter = null } @SuppressLint("RtlHardcoded") - @Override - public void onNavigationClick() { - toggleDrawer(Gravity.LEFT); + override fun onNavigationClick() { + toggleDrawer(Gravity.LEFT) } - @Override - public int getMenuResId() { - return R.menu.scene_history; + override fun getMenuResId(): Int { + return R.menu.scene_history } - private void showClearAllDialog() { - new MaterialAlertDialogBuilder(requireContext()) - .setMessage(R.string.clear_all_history) - .setPositiveButton(R.string.clear_all, (dialog, which) -> { - if (DialogInterface.BUTTON_POSITIVE != which || null == mAdapter) { - return; - } - - EhDB.clearHistoryInfo(); - updateLazyList(); - mAdapter.notifyDataSetChanged(); - updateView(true); - }) - .setNegativeButton(android.R.string.cancel, null) - .show(); + @SuppressLint("NotifyDataSetChanged") + private fun showClearAllDialog() { + MaterialAlertDialogBuilder(requireContext()) + .setMessage(R.string.clear_all_history) + .setPositiveButton(R.string.clear_all) { _: DialogInterface?, which: Int -> + if (DialogInterface.BUTTON_POSITIVE != which || null == mAdapter) { + return@setPositiveButton + } + EhDB.clearHistoryInfo() + mAdapter!!.refresh() + mAdapter!!.notifyDataSetChanged() + } + .setNegativeButton(android.R.string.cancel, null) + .show() } - @Override - public boolean onMenuItemClick(MenuItem item) { + override fun onMenuItemClick(item: MenuItem): Boolean { // Skip when in choice mode - Context context = getContext(); - if (null == context) { - return false; - } - - int id = item.getItemId(); + context ?: return false + val id = item.itemId if (id == R.id.action_clear_all) { - showClearAllDialog(); - return true; + showClearAllDialog() + return true } - return false; + return false } - public boolean onItemClick(View view, int position) { - if (null == mLazyList) { - return false; - } - - Bundle args = new Bundle(); - args.putString(GalleryDetailScene.KEY_ACTION, GalleryDetailScene.ACTION_GALLERY_INFO); - args.putParcelable(GalleryDetailScene.KEY_GALLERY_INFO, mLazyList.get(position)); - Announcer announcer = new Announcer(GalleryDetailScene.class).setArgs(args); - startScene(announcer); - return true; + fun onItemClick(position: Int): Boolean { + val args = Bundle() + args.putString(GalleryDetailScene.KEY_ACTION, GalleryDetailScene.ACTION_GALLERY_INFO) + args.putParcelable(GalleryDetailScene.KEY_GALLERY_INFO, mAdapter?.peek(position)) + val announcer = Announcer(GalleryDetailScene::class.java).setArgs(args) + startScene(announcer) + return true } - public boolean onItemLongClick(int position) { - final Context context = getContext(); - final MainActivity activity = getMainActivity(); - if (null == context || null == activity || null == mLazyList) { - return false; - } - - final GalleryInfo gi = mLazyList.get(position); - - if (gi == null) { - return true; - } - - boolean downloaded = mDownloadManager.getDownloadState(gi.gid) != DownloadInfo.STATE_INVALID; - boolean favourited = gi.favoriteSlot != -2; - - CharSequence[] items = downloaded ? new CharSequence[]{ - context.getString(R.string.read), - context.getString(R.string.delete_downloads), - context.getString(favourited ? R.string.remove_from_favourites : R.string.add_to_favourites), - context.getString(R.string.delete), - context.getString(R.string.download_move_dialog_title), - } : new CharSequence[]{ - context.getString(R.string.read), - context.getString(R.string.download), - context.getString(favourited ? R.string.remove_from_favourites : R.string.add_to_favourites), - context.getString(R.string.delete), - }; - - int[] icons = downloaded ? new int[]{ - R.drawable.v_book_open_x24, - R.drawable.v_delete_x24, - favourited ? R.drawable.v_heart_broken_x24 : R.drawable.v_heart_x24, - R.drawable.v_delete_x24, - R.drawable.v_folder_move_x24, - } : new int[]{ - R.drawable.v_book_open_x24, - R.drawable.v_download_x24, - favourited ? R.drawable.v_heart_broken_x24 : R.drawable.v_heart_x24, - R.drawable.v_delete_x24, - }; - - new MaterialAlertDialogBuilder(context) - .setTitle(EhUtils.getSuitableTitle(gi)) - .setAdapter(new SelectItemWithIconAdapter(context, items, icons), (dialog, which) -> { - switch (which) { - case 0: // Read - Intent intent = new Intent(activity, GalleryActivity.class); - intent.setAction(GalleryActivity.ACTION_EH); - intent.putExtra(GalleryActivity.KEY_GALLERY_INFO, gi); - startActivity(intent); - break; - case 1: // Download - if (downloaded) { - new MaterialAlertDialogBuilder(context) - .setTitle(R.string.download_remove_dialog_title) - .setMessage(getString(R.string.download_remove_dialog_message, gi.title)) - .setPositiveButton(android.R.string.ok, (dialog1, which1) -> mDownloadManager.deleteDownload(gi.gid)) - .show(); - } else { - CommonOperations.startDownload(activity, gi, false); - } - break; - case 2: // Favorites - if (favourited) { - CommonOperations.removeFromFavorites(activity, gi, new RemoveFromFavoriteListener(context, activity.getStageId(), getTag())); - } else { - CommonOperations.addToFavorites(activity, gi, new AddToFavoriteListener(context, activity.getStageId(), getTag())); - } - break; - case 3: // Delete - if (null == mLazyList || null == mAdapter) { - return; - } - - HistoryInfo info = mLazyList.get(position); - EhDB.deleteHistoryInfo(info); - updateLazyList(); - mAdapter.notifyDataSetChanged(); - updateView(true); - break; - case 4: // Move - List labelRawList = EhApplication.getDownloadManager(context).getLabelList(); - List labelList = new ArrayList<>(labelRawList.size() + 1); - labelList.add(getString(R.string.default_download_label_name)); - for (int i = 0, n = labelRawList.size(); i < n; i++) { - labelList.add(labelRawList.get(i).getLabel()); - } - String[] labels = labelList.toArray(new String[0]); - - MoveDialogHelper helper = new MoveDialogHelper(labels, gi); - - new MaterialAlertDialogBuilder(context) - .setTitle(R.string.download_move_dialog_title) - .setItems(labels, helper) - .show(); - break; + fun onItemLongClick(position: Int): Boolean { + val context = requireContext() + val activity = mainActivity ?: return false + val gi: GalleryInfo = mAdapter?.peek(position) ?: return true + val downloaded = mDownloadManager!!.getDownloadState(gi.gid) != DownloadInfo.STATE_INVALID + val favourited = gi.favoriteSlot != -2 + val items = if (downloaded) arrayOf( + context.getString(R.string.read), + context.getString(R.string.delete_downloads), + context.getString(if (favourited) R.string.remove_from_favourites else R.string.add_to_favourites), + context.getString(R.string.download_move_dialog_title) + ) else arrayOf( + context.getString(R.string.read), + context.getString(R.string.download), + context.getString(if (favourited) R.string.remove_from_favourites else R.string.add_to_favourites), + ) + val icons = if (downloaded) intArrayOf( + R.drawable.v_book_open_x24, + R.drawable.v_delete_x24, + if (favourited) R.drawable.v_heart_broken_x24 else R.drawable.v_heart_x24, + R.drawable.v_folder_move_x24 + ) else intArrayOf( + R.drawable.v_book_open_x24, + R.drawable.v_download_x24, + if (favourited) R.drawable.v_heart_broken_x24 else R.drawable.v_heart_x24, + ) + MaterialAlertDialogBuilder(context) + .setTitle(EhUtils.getSuitableTitle(gi)) + .setAdapter( + SelectItemWithIconAdapter( + context, + items, + icons + ) + ) { _: DialogInterface?, which: Int -> + when (which) { + 0 -> { + val intent = Intent(activity, GalleryActivity::class.java) + intent.action = GalleryActivity.ACTION_EH + intent.putExtra(GalleryActivity.KEY_GALLERY_INFO, gi) + startActivity(intent) } - }).show(); - return true; + 1 -> if (downloaded) { + MaterialAlertDialogBuilder(context) + .setTitle(R.string.download_remove_dialog_title) + .setMessage( + getString( + R.string.download_remove_dialog_message, + gi.title + ) + ) + .setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int -> + mDownloadManager!!.deleteDownload( + gi.gid + ) + } + .show() + } else { + CommonOperations.startDownload(activity, gi, false) + } + 2 -> if (favourited) { + CommonOperations.removeFromFavorites( + activity, + gi, + RemoveFromFavoriteListener(context, activity.stageId, tag) + ) + } else { + CommonOperations.addToFavorites( + activity, + gi, + AddToFavoriteListener(context, activity.stageId, tag) + ) + } + 3 -> { + val labelRawList = EhApplication.getDownloadManager(context).labelList + val labelList: MutableList = ArrayList(labelRawList.size + 1) + labelList.add(getString(R.string.default_download_label_name)) + var i = 0 + val n = labelRawList.size + while (i < n) { + labelList.add(labelRawList[i].label) + i++ + } + val labels = labelList.toTypedArray() + val helper = MoveDialogHelper(labels, gi) + MaterialAlertDialogBuilder(context) + .setTitle(R.string.download_move_dialog_title) + .setItems(labels, helper) + .show() + } + } + }.show() + return true } - private static class AddToFavoriteListener extends EhCallback { - - public AddToFavoriteListener(Context context, int stageId, String sceneTag) { - super(context, stageId, sceneTag); + private class AddToFavoriteListener(context: Context?, stageId: Int, sceneTag: String?) : + EhCallback(context, stageId, sceneTag) { + override fun onSuccess(result: Void?) { + showTip(R.string.add_to_favorite_success, LENGTH_SHORT) } - @Override - public void onSuccess(Void result) { - showTip(R.string.add_to_favorite_success, LENGTH_SHORT); + override fun onFailure(e: Exception) { + showTip(R.string.add_to_favorite_failure, LENGTH_LONG) } - @Override - public void onFailure(Exception e) { - showTip(R.string.add_to_favorite_failure, LENGTH_LONG); - } - - @Override - public void onCancel() { - } - - @Override - public boolean isInstance(SceneFragment scene) { - return scene instanceof GalleryListScene; + override fun onCancel() {} + override fun isInstance(scene: SceneFragment): Boolean { + return scene is GalleryListScene } } - private static class RemoveFromFavoriteListener extends EhCallback { - - public RemoveFromFavoriteListener(Context context, int stageId, String sceneTag) { - super(context, stageId, sceneTag); + private class RemoveFromFavoriteListener(context: Context?, stageId: Int, sceneTag: String?) : + EhCallback(context, stageId, sceneTag) { + override fun onSuccess(result: Void?) { + showTip(R.string.remove_from_favorite_success, LENGTH_SHORT) } - @Override - public void onSuccess(Void result) { - showTip(R.string.remove_from_favorite_success, LENGTH_SHORT); + override fun onFailure(e: Exception) { + showTip(R.string.remove_from_favorite_failure, LENGTH_LONG) } - @Override - public void onFailure(Exception e) { - showTip(R.string.remove_from_favorite_failure, LENGTH_LONG); - } - - @Override - public void onCancel() { - } - - @Override - public boolean isInstance(SceneFragment scene) { - return scene instanceof GalleryListScene; + override fun onCancel() {} + override fun isInstance(scene: SceneFragment): Boolean { + return scene is GalleryListScene } } - private static class HistoryHolder extends RecyclerView.ViewHolder { + private class HistoryHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { + val card: View + val thumb: LoadImageView + val title: TextView + val uploader: TextView + val rating: SimpleRatingView + val category: TextView + val posted: TextView + val simpleLanguage: TextView + val pages: TextView + val downloaded: ImageView - public final View card; - public final LoadImageView thumb; - public final TextView title; - public final TextView uploader; - public final SimpleRatingView rating; - public final TextView category; - public final TextView posted; - public final TextView simpleLanguage; - public final TextView pages; - public final ImageView downloaded; - - public HistoryHolder(View itemView) { - super(itemView); - - card = itemView.findViewById(R.id.card); - thumb = itemView.findViewById(R.id.thumb); - title = itemView.findViewById(R.id.title); - uploader = itemView.findViewById(R.id.uploader); - rating = itemView.findViewById(R.id.rating); - category = itemView.findViewById(R.id.category); - posted = itemView.findViewById(R.id.posted); - simpleLanguage = itemView.findViewById(R.id.simple_language); - pages = itemView.findViewById(R.id.pages); - downloaded = itemView.findViewById(R.id.downloaded); + init { + card = itemView.findViewById(R.id.card) + thumb = itemView.findViewById(R.id.thumb) + title = itemView.findViewById(R.id.title) + uploader = itemView.findViewById(R.id.uploader) + rating = itemView.findViewById(R.id.rating) + category = itemView.findViewById(R.id.category) + posted = itemView.findViewById(R.id.posted) + simpleLanguage = itemView.findViewById(R.id.simple_language) + pages = itemView.findViewById(R.id.pages) + downloaded = itemView.findViewById(R.id.downloaded) } } - private class MoveDialogHelper implements DialogInterface.OnClickListener { - - private final String[] mLabels; - private final GalleryInfo mGi; - - public MoveDialogHelper(String[] labels, GalleryInfo gi) { - mLabels = labels; - mGi = gi; - } - - @Override - public void onClick(DialogInterface dialog, int which) { - // Cancel check mode - Context context = getContext(); - if (null == context) { - return; - } - if (null != mRecyclerView) { - mRecyclerView.outOfCustomChoiceMode(); - } - - DownloadManager downloadManager = EhApplication.getDownloadManager(context); - DownloadInfo downloadInfo = downloadManager.getDownloadInfo(mGi.gid); - if (downloadInfo == null) { - return; - } - - String label = which == 0 ? null : mLabels[which]; - - downloadManager.changeLabel(Collections.singletonList(downloadInfo), label); + private inner class MoveDialogHelper( + private val mLabels: Array, + private val mGi: GalleryInfo + ) : DialogInterface.OnClickListener { + override fun onClick(dialog: DialogInterface, which: Int) { + mRecyclerView?.outOfCustomChoiceMode() + val downloadManager = EhApplication.getDownloadManager(requireContext()) + val downloadInfo = downloadManager.getDownloadInfo(mGi.gid) ?: return + val label = if (which == 0) null else mLabels[which] + downloadManager.changeLabel(listOf(downloadInfo), label) } } - private class HistoryAdapter extends RecyclerView.Adapter { + private inner class HistoryAdapter(diffCallback: DiffUtil.ItemCallback) : + PagingDataAdapter(diffCallback) { + private val mInflater: LayoutInflater = layoutInflater + private val mListThumbWidth: Int + private val mListThumbHeight: Int - private final LayoutInflater mInflater; - private final int mListThumbWidth; - private final int mListThumbHeight; - - public HistoryAdapter() { - mInflater = getLayoutInflater(); - - @SuppressLint("InflateParams") View calculator = mInflater.inflate(R.layout.item_gallery_list_thumb_height, null); - ViewUtils.measureView(calculator, 1024, ViewGroup.LayoutParams.WRAP_CONTENT); - mListThumbHeight = calculator.getMeasuredHeight(); - mListThumbWidth = mListThumbHeight * 2 / 3; + init { + @SuppressLint("InflateParams") val calculator = + mInflater.inflate(R.layout.item_gallery_list_thumb_height, null) + ViewUtils.measureView(calculator, 1024, ViewGroup.LayoutParams.WRAP_CONTENT) + mListThumbHeight = calculator.measuredHeight + mListThumbWidth = mListThumbHeight * 2 / 3 } - @Override - public long getItemId(int position) { - if (null == mLazyList) { - return super.getItemId(position); - } else { - return mLazyList.get(position).gid; - } + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HistoryHolder { + val holder = HistoryHolder(mInflater.inflate(R.layout.item_history, parent, false)) + val lp = holder.thumb.layoutParams + lp.width = mListThumbWidth + lp.height = mListThumbHeight + holder.thumb.layoutParams = lp + return holder } - @NonNull - @Override - public HistoryHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - HistoryHolder holder = new HistoryHolder(mInflater.inflate(R.layout.item_history, parent, false)); - - ViewGroup.LayoutParams lp = holder.thumb.getLayoutParams(); - lp.width = mListThumbWidth; - lp.height = mListThumbHeight; - holder.thumb.setLayoutParams(lp); - - return holder; - } - - @Override - public void onBindViewHolder(@NonNull HistoryHolder holder, int position) { - if (null == mLazyList) { - return; + override fun onBindViewHolder(holder: HistoryHolder, position: Int) { + val gi: GalleryInfo? = getItem(position) + gi ?: return + holder.thumb.load(EhCacheKeyFactory.getThumbKey(gi.gid), gi.thumb) + holder.title.text = EhUtils.getSuitableTitle(gi) + holder.uploader.text = gi.uploader + holder.rating.rating = gi.rating + val category = holder.category + val newCategoryText = EhUtils.getCategory(gi.category) + if (!newCategoryText!!.contentEquals(category.text)) { + category.text = newCategoryText + category.setBackgroundColor(EhUtils.getCategoryColor(gi.category)) } - - GalleryInfo gi = mLazyList.get(position); - holder.thumb.load(EhCacheKeyFactory.getThumbKey(gi.gid), gi.thumb); - 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.contentEquals(category.getText())) { - category.setText(newCategoryText); - category.setBackgroundColor(EhUtils.getCategoryColor(gi.category)); - } - holder.posted.setText(gi.posted); - holder.pages.setText(null); - holder.pages.setVisibility(View.GONE); + holder.posted.text = gi.posted + holder.pages.text = null + holder.pages.visibility = View.GONE if (TextUtils.isEmpty(gi.simpleLanguage)) { - holder.simpleLanguage.setText(null); - holder.simpleLanguage.setVisibility(View.GONE); + holder.simpleLanguage.text = null + holder.simpleLanguage.visibility = View.GONE } else { - holder.simpleLanguage.setText(gi.simpleLanguage); - holder.simpleLanguage.setVisibility(View.VISIBLE); + holder.simpleLanguage.text = gi.simpleLanguage + holder.simpleLanguage.visibility = View.VISIBLE } - holder.downloaded.setVisibility(mDownloadManager.containDownloadInfo(gi.gid) ? View.VISIBLE : View.GONE); + holder.downloaded.visibility = + if (mDownloadManager!!.containDownloadInfo(gi.gid)) View.VISIBLE else View.GONE // Update transition name - long gid = gi.gid; - ViewCompat.setTransitionName(holder.thumb, TransitionNameFactory.getThumbTransitionName(gid)); - - holder.card.setOnClickListener(v -> onItemClick(holder.itemView, position)); - holder.card.setOnLongClickListener(v -> onItemLongClick(position)); - } - - @Override - public int getItemCount() { - return null != mLazyList ? mLazyList.size() : 0; + val gid = gi.gid + ViewCompat.setTransitionName( + holder.thumb, + TransitionNameFactory.getThumbTransitionName(gid) + ) + holder.card.setOnClickListener { onItemClick(position) } + holder.card.setOnLongClickListener { onItemLongClick(position) } } } - private class HistoryItemTouchHelperCallback extends ItemTouchHelper.Callback { - - @Override - public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) { - return makeMovementFlags(0, ItemTouchHelper.LEFT); + private inner class HistoryItemTouchHelperCallback : ItemTouchHelper.Callback() { + override fun getMovementFlags( + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder + ): Int { + return makeMovementFlags(0, ItemTouchHelper.LEFT) } - @Override - public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) { - return false; + override fun onMove( + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + target: RecyclerView.ViewHolder + ): Boolean { + return false } - @Override - public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { - int mPosition = viewHolder.getBindingAdapterPosition(); - if (null == mLazyList || mAdapter == null) { - return; + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) { + val mPosition = viewHolder.bindingAdapterPosition + if (mAdapter == null) { + return } - HistoryInfo info = mLazyList.get(mPosition); - EhDB.deleteHistoryInfo(info); - updateLazyList(); - mAdapter.notifyItemRemoved(mPosition); - updateView(true); + val info: HistoryInfo = mAdapter!!.peek(mPosition)!! + EhDB.deleteHistoryInfo(info) + mAdapter!!.refresh() } } -} +} \ No newline at end of file