From f47c09deda44fd41077424c6af668ac8759a27d5 Mon Sep 17 00:00:00 2001 From: seven332 Date: Sat, 27 Feb 2016 22:34:37 +0800 Subject: [PATCH] Add DownloadService start range, stop range and delete range --- .../ehviewer/download/DownloadManager.java | 114 ++++++++++- .../ehviewer/download/DownloadService.java | 21 ++ .../ehviewer/ui/scene/DownloadScene.java | 181 +++++++++++++++--- app/src/main/res/values-zh-rCN/strings.xml | 1 + app/src/main/res/values-zh-rHK/strings.xml | 8 +- app/src/main/res/values-zh-rTW/strings.xml | 8 +- app/src/main/res/values/strings.xml | 1 + 7 files changed, 304 insertions(+), 30 deletions(-) diff --git a/app/src/main/java/com/hippo/ehviewer/download/DownloadManager.java b/app/src/main/java/com/hippo/ehviewer/download/DownloadManager.java index c8a05e53a..31040f475 100644 --- a/app/src/main/java/com/hippo/ehviewer/download/DownloadManager.java +++ b/app/src/main/java/com/hippo/ehviewer/download/DownloadManager.java @@ -29,6 +29,7 @@ import com.hippo.ehviewer.dao.DownloadLabelRaw; import com.hippo.ehviewer.spider.SpiderQueen; import com.hippo.image.Image; import com.hippo.yorozuya.ConcurrentPool; +import com.hippo.yorozuya.IntList; import com.hippo.yorozuya.SimpleHandler; import java.util.HashMap; @@ -63,7 +64,9 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener { @NonNull private final SpeedReminder mSpeedReminder; + @Nullable private DownloadListener mDownloadListener; + @Nullable private DownloadInfoListener mDownloadInfoListener; @Nullable @@ -71,6 +74,7 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener { @Nullable private SpiderQueen mCurrentSpider; + @NonNull private final ConcurrentPool mNotifyTaskPool = new ConcurrentPool<>(5); public DownloadManager(Context context) { @@ -181,11 +185,11 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener { return mMap.get(label); } - public void setDownloadInfoListener(DownloadInfoListener downloadInfoListener) { + public void setDownloadInfoListener(@Nullable DownloadInfoListener downloadInfoListener) { mDownloadInfoListener = downloadInfoListener; } - public void setDownloadListener(DownloadListener listener) { + public void setDownloadListener(@Nullable DownloadListener listener) { mDownloadListener = listener; } @@ -281,6 +285,38 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener { } } + void startRangeDownload(IntList gidList) { + boolean update = false; + + for (int i = 0, n = gidList.size(); i < n; i++) { + int gid = gidList.get(i); + DownloadInfo info = mAllInfoMap.get(gid); + if (null == info) { + Log.d(TAG, "Can't get download info with gid: " + gid); + continue; + } + + if (info.state != DownloadInfo.STATE_WAIT) { + update = true; + // Set state DownloadInfo.STATE_WAIT + info.state = DownloadInfo.STATE_WAIT; + // Add to wait list + mWaitList.add(info); + // Update in DB + EhDB.updateDownloadInfo(info); + } + } + + if (update) { + // Notify Listener + if (mDownloadInfoListener != null) { + mDownloadInfoListener.onUpdateAll(); + } + // Ensure download + ensureDownload(); + } + } + void startAllDownload() { boolean update = false; // Start all STATE_NONE and STATE_FAILED item @@ -335,6 +371,18 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener { } } + void stopRangeDownload(IntList gidList) { + stopRangeDownloadInternal(gidList); + + // Update listener + if (mDownloadInfoListener != null) { + mDownloadInfoListener.onUpdateAll(); + } + + // Ensure download + ensureDownload(); + } + void stopAllDownload() { // Stop all in wait list for (DownloadInfo info : mWaitList) { @@ -381,6 +429,36 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener { } } + void deleteRangeDownload(IntList gidList) { + stopRangeDownloadInternal(gidList); + + for (int i = 0, n = gidList.size(); i < n; i++) { + int gid = gidList.get(i); + DownloadInfo info = mAllInfoMap.get(gid); + if (null == info) { + Log.d(TAG, "Can't get download info with gid: " + gid); + continue; + } + + // Remove from DB + EhDB.removeDownloadInfo(info.galleryInfo.gid); + + // Remove from all info map + mAllInfoMap.remove(info.galleryInfo.gid); + + // Remove from label list + LinkedList list = getInfoListForLabel(info.label); + if (list != null) { + list.remove(info); + } + } + + // Update listener + if (mDownloadInfoListener != null) { + mDownloadInfoListener.onReload(); + } + } + // Update in DB // Update listener // No ensureDownload @@ -435,6 +513,36 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener { return info; } + // Update in DB + // Update mDownloadListener + private void stopRangeDownloadInternal(IntList gidList) { + // Two way + if (gidList.size() < mWaitList.size()) { + for (int i = 0, n = gidList.size(); i < n; i++) { + DownloadInfo info = stopDownloadInternal(gidList.get(i)); + } + } else { + // Check current task + if (mCurrentTask != null && gidList.contains(mCurrentTask.galleryInfo.gid)) { + // Stop current + stopCurrentDownloadInternal(); + } + + // Check all in wait list + for (Iterator iterator = mWaitList.iterator(); iterator.hasNext();) { + DownloadInfo info = iterator.next(); + if (gidList.contains(info.galleryInfo.gid)) { + // Remove from wait list + iterator.remove(); + // Update state + info.state = DownloadInfo.STATE_NONE; + // Update in DB + EhDB.updateDownloadInfo(info); + } + } + } + } + boolean isIdle() { return mCurrentTask == null && mWaitList.isEmpty(); } @@ -725,6 +833,8 @@ public class DownloadManager implements SpiderQueen.OnSpiderListener { void onUpdateAll(); + void onReload(); + void onRemove(DownloadInfo info, List list, int position); } diff --git a/app/src/main/java/com/hippo/ehviewer/download/DownloadService.java b/app/src/main/java/com/hippo/ehviewer/download/DownloadService.java index 431e74550..b0b672636 100644 --- a/app/src/main/java/com/hippo/ehviewer/download/DownloadService.java +++ b/app/src/main/java/com/hippo/ehviewer/download/DownloadService.java @@ -33,21 +33,27 @@ import com.hippo.ehviewer.EhApplication; import com.hippo.ehviewer.R; import com.hippo.ehviewer.client.data.GalleryInfo; import com.hippo.yorozuya.FileUtils; +import com.hippo.yorozuya.IntList; +// TODO Avoid frequent notification public class DownloadService extends Service implements DownloadManager.DownloadListener { public static final String ACTION_START = "start"; + public static final String ACTION_START_RANGE = "start_range"; public static final String ACTION_START_ALL = "start_all"; public static final String ACTION_STOP = "stop"; + public static final String ACTION_STOP_RANGE = "stop_range"; public static final String ACTION_STOP_CURRENT = "stop_current"; public static final String ACTION_STOP_ALL = "stop_all"; public static final String ACTION_DELETE = "delete"; + public static final String ACTION_DELETE_RANGE = "delete_range"; public static final String ACTION_CLEAR = "clear"; public static final String KEY_GALLERY_INFO = "gallery_info"; public static final String KEY_LABEL = "label"; public static final String KEY_GID = "gid"; + public static final String KEY_GID_LIST = "gid_list"; private static final int ID_DOWNLOADING = 1; private static final int ID_DOWNLOADED = 2; @@ -137,6 +143,11 @@ public class DownloadService extends Service implements DownloadManager.Download if (gi != null && mDownloadManager != null) { mDownloadManager.startDownload(gi, label); } + } else if (ACTION_START_RANGE.equals(action)) { + IntList gidList = intent.getParcelableExtra(KEY_GID_LIST); + if (gidList != null && mDownloadManager != null) { + mDownloadManager.startRangeDownload(gidList); + } } else if (ACTION_START_ALL.equals(action)) { if (mDownloadManager != null) { mDownloadManager.startAllDownload(); @@ -150,6 +161,11 @@ public class DownloadService extends Service implements DownloadManager.Download if (mDownloadManager != null) { mDownloadManager.stopCurrentDownload(); } + } else if (ACTION_STOP_RANGE.equals(action)) { + IntList gidList = intent.getParcelableExtra(KEY_GID_LIST); + if (gidList != null && mDownloadManager != null) { + mDownloadManager.stopRangeDownload(gidList); + } } else if (ACTION_STOP_ALL.equals(action)) { if (mDownloadManager != null) { mDownloadManager.stopAllDownload(); @@ -159,6 +175,11 @@ public class DownloadService extends Service implements DownloadManager.Download if (gid != -1 && mDownloadManager != null) { mDownloadManager.deleteDownload(gid); } + } else if (ACTION_DELETE_RANGE.equals(action)) { + IntList gidList = intent.getParcelableExtra(KEY_GID_LIST); + if (gidList != null && mDownloadManager != null) { + mDownloadManager.deleteRangeDownload(gidList); + } } else if (ACTION_CLEAR.equals(action)) { EhApplication.clearDownloadService(getApplicationContext(), this); } diff --git a/app/src/main/java/com/hippo/ehviewer/ui/scene/DownloadScene.java b/app/src/main/java/com/hippo/ehviewer/ui/scene/DownloadScene.java index 7f4f93860..403325afc 100644 --- a/app/src/main/java/com/hippo/ehviewer/ui/scene/DownloadScene.java +++ b/app/src/main/java/com/hippo/ehviewer/ui/scene/DownloadScene.java @@ -33,6 +33,7 @@ import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; import android.transition.TransitionInflater; +import android.util.SparseBooleanArray; import android.view.Gravity; import android.view.LayoutInflater; import android.view.MenuItem; @@ -72,9 +73,11 @@ import com.hippo.widget.FabLayout; import com.hippo.widget.LoadImageView; import com.hippo.widget.SimpleImageView; import com.hippo.yorozuya.FileUtils; +import com.hippo.yorozuya.IntList; import com.hippo.yorozuya.ObjectUtils; import java.util.ArrayList; +import java.util.LinkedList; import java.util.List; public class DownloadScene extends ToolbarScene @@ -100,6 +103,9 @@ public class DownloadScene extends ToolbarScene @Nullable private List mList; + private final IntList mTempIntList = new IntList(); + private final List mTempGalleryInfoList = new LinkedList<>(); + // TODO Only single instance @Override public int getLaunchMode() { @@ -386,24 +392,71 @@ public class DownloadScene extends ToolbarScene @Override public void onClickSecondaryFab(FabLayout view, FloatingActionButton fab, int position) { - switch (position) { - case 0: // Check all - if (mRecyclerView != null) { - mRecyclerView.checkAll(); + EasyRecyclerView recyclerView = mRecyclerView; + if (recyclerView == null) { + return; + } + + if (0 == position) { + recyclerView.checkAll(); + } else { + List list = mList; + if (list == null) { + return; + } + + boolean collectGalleryInfo = position == 3; // Delete + + SparseBooleanArray stateArray = recyclerView.getCheckedItemPositions(); + for (int i = 0, n = stateArray.size(); i < n; i++) { + if (stateArray.valueAt(i)) { + GalleryInfo gi = list.get(stateArray.keyAt(i)).galleryInfo; + if (collectGalleryInfo) { + mTempGalleryInfoList.add(gi); + } + mTempIntList.add(gi.gid); } - break; - case 1: // Start - // TODO - break; - case 2: // Stop - // TODO - break; - case 3: // Delete - // TODO - break; - case 4: // Move - // TODO - break; + } + + switch (position) { + case 1: { // Start + Intent intent = new Intent(getActivity(), DownloadService.class); + intent.setAction(DownloadService.ACTION_START_RANGE); + intent.putExtra(DownloadService.KEY_GID_LIST, mTempIntList); + getActivity().startService(intent); + // Clear + mTempIntList.clear(); + // Cancel check mode + recyclerView.outOfCustomChoiceMode(); + break; + } + case 2: { // Stop + Intent intent = new Intent(getActivity(), DownloadService.class); + intent.setAction(DownloadService.ACTION_STOP_RANGE); + intent.putExtra(DownloadService.KEY_GID_LIST, mTempIntList); + getActivity().startService(intent); + // Clear + mTempIntList.clear(); + // Cancel check mode + recyclerView.outOfCustomChoiceMode(); + break; + } + case 3: // Delete + CheckBoxDialogBuilder builder = new CheckBoxDialogBuilder(getContext(), + getString(R.string.download_remove_dialog_message_2, mTempIntList.size()), + getString(R.string.download_remove_dialog_check_text), + Settings.getRemoveImageFiles()); + DeleteRangeDialogHelper helper = new DeleteRangeDialogHelper( + mTempGalleryInfoList, mTempIntList, builder); + builder.setTitle(R.string.download_remove_dialog_title) + .setPositiveButton(android.R.string.ok, helper) + .setOnDismissListener(helper) + .show(); + break; + case 4: // Move + // TODO + break; + } } } @@ -463,6 +516,21 @@ public class DownloadScene extends ToolbarScene } } + @Override + public void onReload() { + if (mAdapter != null) { + mAdapter.notifyDataSetChanged(); + } + + if (mViewTransition != null) { + if (mList != null && mList.size() == 0) { + mViewTransition.showView(1); + } else { + mViewTransition.showView(0); + } + } + } + @Override public void onRemove(DownloadInfo info, List list, int position) { if (mList != list) { @@ -541,6 +609,18 @@ public class DownloadScene extends ToolbarScene holder.speed.setText(FileUtils.humanReadableByteCount(speed, false) + "/S"); } + private static void deleteFileAsync(UniFile... files) { + new AsyncTask() { + @Override + protected Void doInBackground(UniFile... params) { + for (UniFile file: params) { + file.delete(); + } + return null; + } + }.execute(files); + } + private class DeleteDialogHelper implements DialogInterface.OnClickListener { private final GalleryInfo mGalleryInfo; @@ -563,6 +643,7 @@ public class DownloadScene extends ToolbarScene intent.putExtra(DownloadService.KEY_GID, mGalleryInfo.gid); getActivity().startService(intent); + // Delete image files boolean checked = mBuilder.isChecked(); Settings.putRemoveImageFiles(checked); if (checked) { @@ -570,19 +651,67 @@ public class DownloadScene extends ToolbarScene EhDB.removeDownloadDirname(mGalleryInfo.gid); // Delete file UniFile file = SpiderDen.getGalleryDownloadDir(mGalleryInfo); - new AsyncTask() { - @Override - protected Void doInBackground(UniFile... params) { - for (UniFile file: params) { - file.delete(); - } - return null; - } - }.execute(file); + deleteFileAsync(file); } } } + private class DeleteRangeDialogHelper implements DialogInterface.OnClickListener, + DialogInterface.OnDismissListener { + + private final List mGalleryInfoList; + private final IntList mGidList; + private final CheckBoxDialogBuilder mBuilder; + + public DeleteRangeDialogHelper(List galleryInfoList, + IntList gidList, CheckBoxDialogBuilder builder) { + mGalleryInfoList = galleryInfoList; + mGidList = gidList; + mBuilder = builder; + } + + @Override + public void onClick(DialogInterface dialog, int which) { + if (which != DialogInterface.BUTTON_POSITIVE) { + return; + } + + // Delete + Intent intent = new Intent(getActivity(), DownloadService.class); + intent.setAction(DownloadService.ACTION_DELETE_RANGE); + intent.putExtra(DownloadService.KEY_GID_LIST, mGidList); + getActivity().startService(intent); + + // Delete image files + boolean checked = mBuilder.isChecked(); + Settings.putRemoveImageFiles(checked); + if (checked) { + UniFile[] files = new UniFile[mGalleryInfoList.size()]; + int i = 0; + for (GalleryInfo gi: mGalleryInfoList) { + // Remove download path + EhDB.removeDownloadDirname(gi.gid); + // Put file + files[i] = SpiderDen.getGalleryDownloadDir(gi); + i++; + } + // Delete file + deleteFileAsync(files); + } + + // Cancel check mode + if (mRecyclerView != null) { + mRecyclerView.outOfCustomChoiceMode(); + } + } + + @Override + public void onDismiss(DialogInterface dialog) { + mGalleryInfoList.clear(); + mGidList.clear(); + } + } + private class DownloadHolder extends RecyclerView.ViewHolder implements View.OnClickListener { public final LoadImageView thumb; diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 98a724c9d..238d66515 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -192,6 +192,7 @@ 下载失败:%s 移除下载项 从下载列表移除 %s ? + 从下载列表移除 %d 项? 删除图片文件 全部停止 标签 diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 5c136e252..70d7ebedf 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -91,6 +91,8 @@ 顯示被刪除的畫廊 最低評分: + 收藏 + 2 星 3 星 @@ -173,6 +175,7 @@ 跳頁 + 下載 - %s 無下載項目 未啟動 等待中 @@ -187,10 +190,13 @@ %1$d 項下載成功,%2$d 項下載失敗 下載成功:%s 下載失敗:%s - 移除畫廊 + 移除下載項 從下載列表移除 %s ? + 從下載列表移除 %d 項? 刪除圖片文件 全部停止 + 標籤 + 默認 第 %d 頁 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index b31e546b8..2660d2aa4 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -91,6 +91,8 @@ 顯示被刪除的畫廊 最低評分: + 收藏 + 2 星 3 星 @@ -173,6 +175,7 @@ 跳頁 + 下載 - %s 無下載項目 未啟動 等待中 @@ -187,10 +190,13 @@ %1$d 項下載成功,%2$d 項下載失敗 下載成功:%s 下載失敗:%s - 移除畫廊 + 移除下載項 從下載列表移除 %s ? + 從下載列表移除 %d 項? 刪除圖片檔案 全部停止 + 標籤 + 預設 第 %d 頁 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index c23681aa6..0b8e7edd3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -232,6 +232,7 @@ Failed: %s Remove Download Item Remove %s from download list ? + Remove %d items from download list ? Delete image files Stop All Label