/*
* 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.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SimpleItemAnimator;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.Display;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.github.amlcurran.showcaseview.ShowcaseView;
import com.github.amlcurran.showcaseview.SimpleShowcaseEventListener;
import com.github.amlcurran.showcaseview.targets.PointTarget;
import com.github.amlcurran.showcaseview.targets.ViewTarget;
import com.hippo.app.CheckBoxDialogBuilder;
import com.hippo.conaco.DataContainer;
import com.hippo.conaco.ProgressNotifier;
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.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.download.DownloadManager;
import com.hippo.ehviewer.download.DownloadService;
import com.hippo.ehviewer.spider.SpiderDen;
import com.hippo.ehviewer.ui.GalleryActivity;
import com.hippo.ehviewer.ui.MainActivity;
import com.hippo.ehviewer.widget.SimpleRatingView;
import com.hippo.io.UniFileInputStreamPipe;
import com.hippo.ripple.Ripple;
import com.hippo.scene.Announcer;
import com.hippo.streampipe.InputStreamPipe;
import com.hippo.unifile.UniFile;
import com.hippo.util.ApiHelper;
import com.hippo.util.DrawableManager;
import com.hippo.view.ViewTransition;
import com.hippo.widget.FabLayout;
import com.hippo.widget.LoadImageView;
import com.hippo.widget.recyclerview.AutoStaggeredGridLayoutManager;
import com.hippo.yorozuya.FileUtils;
import com.hippo.yorozuya.IOUtils;
import com.hippo.yorozuya.ObjectUtils;
import com.hippo.yorozuya.ResourcesUtils;
import com.hippo.yorozuya.ViewUtils;
import com.hippo.yorozuya.collect.LongList;
import junit.framework.Assert;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class DownloadsScene extends ToolbarScene
implements DownloadManager.DownloadInfoListener,
EasyRecyclerView.OnItemClickListener,
EasyRecyclerView.OnItemLongClickListener,
FabLayout.OnClickFabListener, FastScroller.OnDragHandlerListener {
private static final String TAG = DownloadsScene.class.getSimpleName();
public static final String KEY_GID = "gid";
public static final String KEY_ACTION = "action";
private static final String KEY_LABEL = "label";
public static final String ACTION_CLEAR_DOWNLOAD_SERVICE = "clear_download_service";
/*---------------
Whole life cycle
---------------*/
@Nullable
private DownloadManager mDownloadManager;
@Nullable
private String mLabel;
@Nullable
private List<DownloadInfo> mList;
/*---------------
View life cycle
---------------*/
@Nullable
private EasyRecyclerView mRecyclerView;
@Nullable
private ViewTransition mViewTransition;
@Nullable
private FabLayout mFabLayout;
@Nullable
private DownloadAdapter mAdapter;
@Nullable
private AutoStaggeredGridLayoutManager mLayoutManager;
private ShowcaseView mShowcaseView;
private int mInitPosition = -1;
@Override
public int getNavCheckedItem() {
return R.id.nav_downloads;
}
private boolean handleArguments(Bundle args) {
if (null == args) {
return false;
}
if (ACTION_CLEAR_DOWNLOAD_SERVICE.equals(args.getString(KEY_ACTION))) {
DownloadService.clear();
}
long gid;
if (null != mDownloadManager && -1L != (gid = args.getLong(KEY_GID, -1L))) {
DownloadInfo info = mDownloadManager.getDownloadInfo(gid);
if (null != info) {
mLabel = info.getLabel();
updateForLabel();
updateView();
// Get position
if (null != mList) {
int position = mList.indexOf(info);
if (position >= 0 && null != mRecyclerView) {
mRecyclerView.scrollToPosition(position);
} else {
mInitPosition = position;
}
}
return true;
}
}
return false;
}
@Override
public void onNewArguments(@NonNull Bundle args) {
handleArguments(args);
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Context context = getContext2();
Assert.assertNotNull(context);
mDownloadManager = EhApplication.getDownloadManager(context);
mDownloadManager.addDownloadInfoListener(this);
if (savedInstanceState == null) {
onInit();
} else {
onRestore(savedInstanceState);
}
}
@Override
public void onDestroy() {
super.onDestroy();
mList = null;
DownloadManager manager = mDownloadManager;
if (null == manager) {
Context context = getContext2();
if (null != context) {
manager = EhApplication.getDownloadManager(context);
}
} else {
mDownloadManager = null;
}
if (null != manager) {
manager.removeDownloadInfoListener(this);
} else {
Log.e(TAG, "Can't removeDownloadInfoListener");
}
}
private void updateForLabel() {
if (null == mDownloadManager) {
return;
}
if (mLabel == null) {
mList = mDownloadManager.getDefaultDownloadInfoList();
} else {
mList = mDownloadManager.getLabelDownloadInfoList(mLabel);
if (mList == null) {
mLabel = null;
mList = mDownloadManager.getDefaultDownloadInfoList();
}
}
if (mAdapter != null) {
mAdapter.notifyDataSetChanged();
}
updateTitle();
Settings.putRecentDownloadLabel(mLabel);
}
private void updateTitle() {
setTitle(getString(R.string.scene_download_title,
mLabel != null ? mLabel : getString(R.string.default_download_label_name)));
}
private void onInit() {
if (!handleArguments(getArguments())) {
mLabel = Settings.getRecentDownloadLabel();
updateForLabel();
}
}
private void onRestore(@NonNull Bundle savedInstanceState) {
mLabel = savedInstanceState.getString(KEY_LABEL);
updateForLabel();
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(KEY_LABEL, mLabel);
}
@Nullable
@Override
public View onCreateView3(LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.scene_download, 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);
mFabLayout = (FabLayout) ViewUtils.$$(view, R.id.fab_layout);
TextView tip = (TextView) ViewUtils.$$(view, R.id.tip);
mViewTransition = new ViewTransition(content, tip);
Context context = getContext2();
Assert.assertNotNull(content);
Resources resources = context.getResources();
Drawable drawable = DrawableManager.getDrawable(context, R.drawable.big_download);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
tip.setCompoundDrawables(null, drawable, null, null);
mAdapter = new DownloadAdapter();
mAdapter.setHasStableIds(true);
mRecyclerView.setAdapter(mAdapter);
mLayoutManager = new AutoStaggeredGridLayoutManager(0, StaggeredGridLayoutManager.VERTICAL);
mLayoutManager.setColumnSize(resources.getDimensionPixelOffset(Settings.getDetailSizeResId()));
mLayoutManager.setStrategy(AutoStaggeredGridLayoutManager.STRATEGY_MIN_SIZE);
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setSelector(Ripple.generateRippleDrawable(context, false));
mRecyclerView.setDrawSelectorOnTop(true);
mRecyclerView.hasFixedSize();
mRecyclerView.setClipToPadding(false);
mRecyclerView.setOnItemClickListener(this);
mRecyclerView.setOnItemLongClickListener(this);
mRecyclerView.setChoiceMode(EasyRecyclerView.CHOICE_MODE_MULTIPLE_CUSTOM);
mRecyclerView.setCustomCheckedListener(new DownloadChoiceListener());
// Cancel change animation
RecyclerView.ItemAnimator itemAnimator = mRecyclerView.getItemAnimator();
if (itemAnimator instanceof SimpleItemAnimator) {
((SimpleItemAnimator) itemAnimator).setSupportsChangeAnimations(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);
decoration.applyPaddings(mRecyclerView);
if (mInitPosition >= 0) {
mRecyclerView.scrollToPosition(mInitPosition);
mInitPosition = -1;
}
fastScroller.attachToRecyclerView(mRecyclerView);
HandlerDrawable handlerDrawable = new HandlerDrawable();
handlerDrawable.setColor(ResourcesUtils.getAttrColor(context, R.attr.colorAccent));
fastScroller.setHandlerDrawable(handlerDrawable);
fastScroller.setOnDragHandlerListener(this);
mFabLayout.setExpanded(false, false);
mFabLayout.setHidePrimaryFab(true);
mFabLayout.setAutoCancel(false);
mFabLayout.setOnClickFabListener(this);
addAboveSnackView(mFabLayout);
updateView();
guide();
return view;
}
private void guide() {
if (Settings.getGuideDownloadThumb() && null != mRecyclerView) {
mRecyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (Settings.getGuideDownloadThumb()) {
guideDownloadThumb();
}
if (null != mRecyclerView) {
ViewUtils.removeOnGlobalLayoutListener(mRecyclerView.getViewTreeObserver(), this);
}
}
});
} else {
guideDownloadLabels();
}
}
private void guideDownloadThumb() {
MainActivity activity = getActivity2();
if (null == activity || !Settings.getGuideDownloadThumb() || null == mLayoutManager || null == mRecyclerView) {
guideDownloadLabels();
return;
}
int position = mLayoutManager.findFirstCompletelyVisibleItemPositions(null)[0];
if (position < 0) {
guideDownloadLabels();
return;
}
RecyclerView.ViewHolder holder = mRecyclerView.findViewHolderForAdapterPosition(position);
if (null == holder) {
guideDownloadLabels();
return;
}
mShowcaseView = new ShowcaseView.Builder(activity)
.withMaterialShowcase()
.setStyle(R.style.Guide)
.setTarget(new ViewTarget(((DownloadHolder) holder).thumb))
.blockAllTouches()
.setContentTitle(R.string.guide_download_thumb_title)
.setContentText(R.string.guide_download_thumb_text)
.replaceEndButton(R.layout.button_guide)
.setShowcaseEventListener(new SimpleShowcaseEventListener() {
@Override
public void onShowcaseViewDidHide(ShowcaseView showcaseView) {
mShowcaseView = null;
ViewUtils.removeFromParent(showcaseView);
Settings.putGuideDownloadThumb(false);
guideDownloadLabels();
}
}).build();
}
private void guideDownloadLabels() {
MainActivity activity = getActivity2();
if (null == activity || !Settings.getGuideDownloadLabels()) {
return;
}
Display display = activity.getWindowManager().getDefaultDisplay();
Point point = new Point();
display.getSize(point);
mShowcaseView = new ShowcaseView.Builder(activity)
.withMaterialShowcase()
.setStyle(R.style.Guide)
.setTarget(new PointTarget(point.x, point.y / 3))
.blockAllTouches()
.setContentTitle(R.string.guide_download_labels_title)
.setContentText(R.string.guide_download_labels_text)
.replaceEndButton(R.layout.button_guide)
.setShowcaseEventListener(new SimpleShowcaseEventListener() {
@Override
public void onShowcaseViewDidHide(ShowcaseView showcaseView) {
mShowcaseView = null;
ViewUtils.removeFromParent(showcaseView);
Settings.puttGuideDownloadLabels(false);
openDrawer(Gravity.RIGHT);
}
}).build();
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
updateTitle();
setNavigationIcon(R.drawable.v_arrow_left_dark_x24);
}
@Override
public void onDestroyView() {
super.onDestroyView();
if (null != mShowcaseView) {
ViewUtils.removeFromParent(mShowcaseView);
mShowcaseView = null;
}
if (null != mRecyclerView) {
mRecyclerView.stopScroll();
mRecyclerView = null;
}
if (null != mFabLayout) {
removeAboveSnackView(mFabLayout);
mFabLayout = null;
}
mRecyclerView = null;
mViewTransition = null;
mAdapter = null;
mLayoutManager = null;
}
@Override
public void onNavigationClick() {
onBackPressed();
}
@Override
public int getMenuResId() {
return R.menu.scene_download;
}
@Override
public boolean onMenuItemClick(MenuItem item) {
// Skip when in choice mode
Activity activity = getActivity2();
if (null == activity || null == mRecyclerView || mRecyclerView.isInCustomChoice()) {
return false;
}
int id = item.getItemId();
switch (id) {
case R.id.action_start_all: {
Intent intent = new Intent(activity, DownloadService.class);
intent.setAction(DownloadService.ACTION_START_ALL);
activity.startService(intent);
return true;
}
case R.id.action_stop_all: {
if (null != mDownloadManager) {
mDownloadManager.stopAllDownload();
}
return true;
}
}
return false;
}
public void updateView() {
if (mViewTransition != null) {
if (mList == null || mList.size() == 0) {
mViewTransition.showView(1);
} else {
mViewTransition.showView(0);
}
}
}
@Override
public View onCreateDrawerView(LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.drawer_list, container, false);
final Context context = getContext2();
Assert.assertNotNull(context);
Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar);
toolbar.setTitle(R.string.download_labels);
toolbar.inflateMenu(R.menu.drawer_download);
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.action_settings:
startScene(new Announcer(DownloadLabelsScene.class));
return true;
case R.id.action_default_download_label:
DownloadManager dm = mDownloadManager;
if (null == dm) {
return true;
}
List<DownloadLabel> list = dm.getLabelList();
final String[] items = new String[list.size() + 2];
items[0] = getString(R.string.let_me_select);
items[1] = getString(R.string.default_download_label_name);
for (int i = 0, n = list.size(); i < n; i++) {
items[i + 2] = list.get(i).getLabel();
}
new AlertDialog.Builder(context)
.setTitle(R.string.default_download_label)
.setItems(items, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (which == 0) {
Settings.putHasDefaultDownloadLabel(false);
} else {
Settings.putHasDefaultDownloadLabel(true);
String label;
if (which == 1) {
label = null;
} else {
label = items[which];
}
Settings.putDefaultDownloadLabel(label);
}
}
}).show();
return true;
}
return false;
}
});
List<DownloadLabel> list = EhApplication.getDownloadManager(context).getLabelList();
final List<String> labels = new ArrayList<>(list.size() + 1);
// Add default label name
labels.add(getString(R.string.default_download_label_name));
for (DownloadLabel raw: list) {
labels.add(raw.getLabel());
}
// TODO handle download label items update
ListView listView = (ListView) view.findViewById(R.id.list_view);
listView.setAdapter(new ArrayAdapter<>(context, R.layout.item_simple_list, labels));
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String label;
if (position == 0) {
label = null;
} else {
label = labels.get(position);
}
if (!ObjectUtils.equal(label, mLabel)) {
mLabel = label;
updateForLabel();
updateView();
closeDrawer(Gravity.RIGHT);
}
}
});
return view;
}
@Override
public void onBackPressed() {
if (null != mShowcaseView) {
return;
}
if (mRecyclerView != null && mRecyclerView.isInCustomChoice()) {
mRecyclerView.outOfCustomChoiceMode();
} else {
super.onBackPressed();
}
}
@Override
public void onStartDragHandler() {
// Lock right drawer
setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, Gravity.RIGHT);
}
@Override
public void onEndDragHandler() {
// Restore right drawer
if (null != mRecyclerView && !mRecyclerView.isInCustomChoice()) {
setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, Gravity.RIGHT);
}
}
@Override
public boolean onItemClick(EasyRecyclerView parent, View view, int position, long id) {
Activity activity = getActivity2();
EasyRecyclerView recyclerView = mRecyclerView;
if (null == activity || null == recyclerView) {
return false;
}
if (recyclerView.isInCustomChoice()) {
recyclerView.toggleItemChecked(position);
return true;
} else {
List<DownloadInfo> list = mList;
if (list == null) {
return false;
}
if (position < 0 && position >= list.size()) {
return false;
}
Intent intent = new Intent(activity, GalleryActivity.class);
intent.setAction(GalleryActivity.ACTION_EH);
intent.putExtra(GalleryActivity.KEY_GALLERY_INFO, list.get(position));
startActivity(intent);
return true;
}
}
@Override
public boolean onItemLongClick(EasyRecyclerView parent, View view, int position, long id) {
EasyRecyclerView recyclerView = mRecyclerView;
if (recyclerView == null) {
return false;
}
if (!recyclerView.isInCustomChoice()) {
recyclerView.intoCustomChoiceMode();
}
recyclerView.toggleItemChecked(position);
return true;
}
@Override
public void onClickPrimaryFab(FabLayout view, FloatingActionButton fab) {
if (mRecyclerView != null && mRecyclerView.isInCustomChoice()) {
mRecyclerView.outOfCustomChoiceMode();
}
}
@Override
public void onClickSecondaryFab(FabLayout view, FloatingActionButton fab, int position) {
Context context = getContext2();
Activity activity = getActivity2();
EasyRecyclerView recyclerView = mRecyclerView;
if (null == context || null == activity || null == recyclerView) {
return;
}
if (0 == position) {
recyclerView.checkAll();
} else {
List<DownloadInfo> list = mList;
if (list == null) {
return;
}
LongList gidList = null;
List<DownloadInfo> downloadInfoList = null;
boolean collectGid = position == 1 || position == 2 || position == 3; // Start, Stop, Delete
boolean collectDownloadInfo = position == 3 || position == 4; // Delete or Move
if (collectGid) {
gidList = new LongList();
}
if (collectDownloadInfo) {
downloadInfoList = new LinkedList<>();
}
SparseBooleanArray stateArray = recyclerView.getCheckedItemPositions();
for (int i = 0, n = stateArray.size(); i < n; i++) {
if (stateArray.valueAt(i)) {
DownloadInfo info = list.get(stateArray.keyAt(i));
if (collectDownloadInfo) {
downloadInfoList.add(info);
}
if (collectGid) {
gidList.add(info.gid);
}
}
}
switch (position) {
case 1: { // Start
Intent intent = new Intent(activity, DownloadService.class);
intent.setAction(DownloadService.ACTION_START_RANGE);
intent.putExtra(DownloadService.KEY_GID_LIST, gidList);
activity.startService(intent);
// Cancel check mode
recyclerView.outOfCustomChoiceMode();
break;
}
case 2: { // Stop
if (null != mDownloadManager) {
mDownloadManager.stopRangeDownload(gidList);
}
// Cancel check mode
recyclerView.outOfCustomChoiceMode();
break;
}
case 3: { // Delete
CheckBoxDialogBuilder builder = new CheckBoxDialogBuilder(context,
getString(R.string.download_remove_dialog_message_2, gidList.size()),
getString(R.string.download_remove_dialog_check_text),
Settings.getRemoveImageFiles());
DeleteRangeDialogHelper helper = new DeleteRangeDialogHelper(
downloadInfoList, gidList, builder);
builder.setTitle(R.string.download_remove_dialog_title)
.setPositiveButton(android.R.string.ok, helper)
.show();
break;
}
case 4: {// Move
List<DownloadLabel> labelRawList = EhApplication.getDownloadManager(context).getLabelList();
List<String> 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[labelList.size()]);
MoveDialogHelper helper = new MoveDialogHelper(labels, downloadInfoList);
new AlertDialog.Builder(context)
.setTitle(R.string.download_move_dialog_title)
.setItems(labels, helper)
.show();
break;
}
}
}
}
@Override
public void onAdd(@NonNull DownloadInfo info, @NonNull List<DownloadInfo> list, int position) {
if (mList != list) {
return;
}
if (mAdapter != null) {
mAdapter.notifyItemInserted(position);
}
updateView();
}
@Override
public void onUpdate(@NonNull DownloadInfo info, @NonNull List<DownloadInfo> list) {
if (mList != list) {
return;
}
int index = list.indexOf(info);
if (index >= 0 && mAdapter != null) {
mAdapter.notifyItemChanged(index);
}
}
@Override
public void onUpdateAll() {
if (mAdapter != null) {
mAdapter.notifyDataSetChanged();
}
}
@Override
public void onReload() {
if (mAdapter != null) {
mAdapter.notifyDataSetChanged();
}
updateView();
}
@Override
public void onChange() {
mLabel = null;
updateForLabel();
updateView();
}
@Override
public void onRenameLabel(String from, String to) {
if (!ObjectUtils.equal(mLabel, from)) {
return;
}
mLabel = to;
updateForLabel();
updateView();
}
@Override
public void onRemove(@NonNull DownloadInfo info, @NonNull List<DownloadInfo> list, int position) {
if (mList != list) {
return;
}
if (mAdapter != null) {
mAdapter.notifyItemRemoved(position);
}
updateView();
}
@Override
public void onUpdateLabels() {
// TODO
}
private void bindForState(DownloadHolder holder, DownloadInfo info) {
Resources resources = getResources2();
if (null == resources) {
return;
}
switch (info.state) {
case DownloadInfo.STATE_NONE:
bindState(holder, info, resources.getString(R.string.download_state_none));
break;
case DownloadInfo.STATE_WAIT:
bindState(holder, info, resources.getString(R.string.download_state_wait));
break;
case DownloadInfo.STATE_DOWNLOAD:
bindProgress(holder, info);
break;
case DownloadInfo.STATE_FAILED:
String text;
if (info.legacy <= 0) {
text = resources.getString(R.string.download_state_failed);
} else {
text = resources.getString(R.string.download_state_failed_2, info.legacy);
}
bindState(holder, info, text);
break;
case DownloadInfo.STATE_FINISH:
bindState(holder, info, resources.getString(R.string.download_state_finish));
break;
}
}
private void bindState(DownloadHolder holder, DownloadInfo info, String state) {
holder.uploader.setVisibility(View.VISIBLE);
holder.rating.setVisibility(View.VISIBLE);
holder.category.setVisibility(View.VISIBLE);
holder.state.setVisibility(View.VISIBLE);
holder.progressBar.setVisibility(View.GONE);
holder.percent.setVisibility(View.GONE);
holder.speed.setVisibility(View.GONE);
if (info.state == DownloadInfo.STATE_WAIT || info.state == DownloadInfo.STATE_DOWNLOAD) {
holder.start.setVisibility(View.GONE);
holder.stop.setVisibility(View.VISIBLE);
} else {
holder.start.setVisibility(View.VISIBLE);
holder.stop.setVisibility(View.GONE);
}
holder.state.setText(state);
}
@SuppressLint("SetTextI18n")
private void bindProgress(DownloadHolder holder, DownloadInfo info) {
holder.uploader.setVisibility(View.GONE);
holder.rating.setVisibility(View.GONE);
holder.category.setVisibility(View.GONE);
holder.state.setVisibility(View.GONE);
holder.progressBar.setVisibility(View.VISIBLE);
holder.percent.setVisibility(View.VISIBLE);
holder.speed.setVisibility(View.VISIBLE);
if (info.state == DownloadInfo.STATE_WAIT || info.state == DownloadInfo.STATE_DOWNLOAD) {
holder.start.setVisibility(View.GONE);
holder.stop.setVisibility(View.VISIBLE);
} else {
holder.start.setVisibility(View.VISIBLE);
holder.stop.setVisibility(View.GONE);
}
if (info.total <= 0 || info.finished < 0) {
holder.percent.setText(null);
holder.progressBar.setIndeterminate(true);
} else {
holder.percent.setText(info.finished + "/" + info.total);
holder.progressBar.setIndeterminate(false);
holder.progressBar.setMax(info.total);
holder.progressBar.setProgress(info.finished);
}
long speed = info.speed;
if (speed < 0) {
speed = 0;
}
holder.speed.setText(FileUtils.humanReadableByteCount(speed, false) + "/S");
}
private static void deleteFileAsync(UniFile... files) {
new AsyncTask<UniFile, Void, Void>() {
@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;
private final CheckBoxDialogBuilder mBuilder;
public DeleteDialogHelper(GalleryInfo galleryInfo, CheckBoxDialogBuilder builder) {
mGalleryInfo = galleryInfo;
mBuilder = builder;
}
@Override
public void onClick(DialogInterface dialog, int which) {
if (which != DialogInterface.BUTTON_POSITIVE) {
return;
}
// Delete
if (null != mDownloadManager) {
mDownloadManager.deleteDownload(mGalleryInfo.gid);
}
// Delete image files
boolean checked = mBuilder.isChecked();
Settings.putRemoveImageFiles(checked);
if (checked) {
// Remove download path
EhDB.removeDownloadDirname(mGalleryInfo.gid);
// Delete file
UniFile file = SpiderDen.getGalleryDownloadDir(mGalleryInfo);
deleteFileAsync(file);
}
}
}
private class DeleteRangeDialogHelper implements DialogInterface.OnClickListener {
private final List<DownloadInfo> mDownloadInfoList;
private final LongList mGidList;
private final CheckBoxDialogBuilder mBuilder;
public DeleteRangeDialogHelper(List<DownloadInfo> downloadInfoList,
LongList gidList, CheckBoxDialogBuilder builder) {
mDownloadInfoList = downloadInfoList;
mGidList = gidList;
mBuilder = builder;
}
@Override
public void onClick(DialogInterface dialog, int which) {
if (which != DialogInterface.BUTTON_POSITIVE) {
return;
}
// Cancel check mode
if (mRecyclerView != null) {
mRecyclerView.outOfCustomChoiceMode();
}
// Delete
if (null != mDownloadManager) {
mDownloadManager.deleteRangeDownload(mGidList);
}
// Delete image files
boolean checked = mBuilder.isChecked();
Settings.putRemoveImageFiles(checked);
if (checked) {
UniFile[] files = new UniFile[mDownloadInfoList.size()];
int i = 0;
for (DownloadInfo info: mDownloadInfoList) {
// Remove download path
EhDB.removeDownloadDirname(info.gid);
// Put file
files[i] = SpiderDen.getGalleryDownloadDir(info);
i++;
}
// Delete file
deleteFileAsync(files);
}
}
}
private class MoveDialogHelper implements DialogInterface.OnClickListener {
private final String[] mLabels;
private final List<DownloadInfo> mDownloadInfoList;
public MoveDialogHelper(String[] labels, List<DownloadInfo> downloadInfoList) {
mLabels = labels;
mDownloadInfoList = downloadInfoList;
}
@Override
public void onClick(DialogInterface dialog, int which) {
// Cancel check mode
Context context = getContext2();
if (null == context) {
return;
}
if (null != mRecyclerView) {
mRecyclerView.outOfCustomChoiceMode();
}
String label;
if (which == 0) {
label = null;
} else {
label = mLabels[which];
}
EhApplication.getDownloadManager(context).changeLabel(mDownloadInfoList, label);
}
}
private class DownloadHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
public final LoadImageView thumb;
public final TextView title;
public final TextView uploader;
public final SimpleRatingView rating;
public final TextView category;
public final View start;
public final View stop;
public final TextView state;
public final ProgressBar progressBar;
public final TextView percent;
public final TextView speed;
public DownloadHolder(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);
start = itemView.findViewById(R.id.start);
stop = itemView.findViewById(R.id.stop);
state = (TextView) itemView.findViewById(R.id.state);
progressBar = (ProgressBar) itemView.findViewById(R.id.progress_bar);
percent = (TextView) itemView.findViewById(R.id.percent);
speed = (TextView) itemView.findViewById(R.id.speed);
// TODO cancel on click listener when select items
thumb.setOnClickListener(this);
start.setOnClickListener(this);
stop.setOnClickListener(this);
Ripple.addRipple(start, false);
Ripple.addRipple(stop, false);
}
@Override
public void onClick(View v) {
Context context = getContext2();
Activity activity = getActivity2();
EasyRecyclerView recyclerView = mRecyclerView;
if (null == context || null == activity || null == recyclerView || recyclerView.isInCustomChoice()) {
return;
}
List<DownloadInfo> list = mList;
if (list == null) {
return;
}
int size = list.size();
int index = recyclerView.getChildAdapterPosition(itemView);
if (index < 0 && index >= size) {
return;
}
if (thumb == v) {
Bundle args = new Bundle();
args.putString(GalleryDetailScene.KEY_ACTION, GalleryDetailScene.ACTION_GALLERY_INFO);
args.putParcelable(GalleryDetailScene.KEY_GALLERY_INFO, list.get(index));
Announcer announcer = new Announcer(GalleryDetailScene.class).setArgs(args);
if (ApiHelper.SUPPORT_TRANSITION) {
announcer.setTranHelper(new EnterGalleryDetailTransaction(thumb));
}
startScene(announcer);
} else if (start == v) {
Intent intent = new Intent(activity, DownloadService.class);
intent.setAction(DownloadService.ACTION_START);
intent.putExtra(DownloadService.KEY_GALLERY_INFO, list.get(index));
activity.startService(intent);
} else if (stop == v) {
if (null != mDownloadManager) {
mDownloadManager.stopDownload(list.get(index).gid);
}
}
}
}
private class DownloadAdapter extends RecyclerView.Adapter<DownloadHolder> {
private final LayoutInflater mInflater;
public DownloadAdapter() {
mInflater = getLayoutInflater2();
Assert.assertNotNull(mInflater);
}
@Override
public long getItemId(int position) {
if (mList == null || position < 0 || position >= mList.size()) {
return 0;
}
return mList.get(position).gid;
}
@Override
public DownloadHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return new DownloadHolder(mInflater.inflate(R.layout.item_download, parent, false));
}
@Override
public void onBindViewHolder(DownloadHolder holder, int position) {
if (mList == null) {
return;
}
DownloadInfo info = mList.get(position);
holder.thumb.load(EhCacheKeyFactory.getThumbKey(info.gid), info.thumb,
new ThumbDataContainer(info), true);
holder.title.setText(EhUtils.getSuitableTitle(info));
holder.uploader.setText(info.uploader);
holder.rating.setRating(info.rating);
TextView category = holder.category;
String newCategoryText = EhUtils.getCategory(info.category);
if (!newCategoryText.equals(category.getText())) {
category.setText(newCategoryText);
category.setBackgroundColor(EhUtils.getCategoryColor(info.category));
}
bindForState(holder, info);
// Update transition name
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
long gid = info.gid;
holder.thumb.setTransitionName(TransitionNameFactory.getThumbTransitionName(gid));
}
}
@Override
public int getItemCount() {
return mList == null ? 0 : mList.size();
}
}
private class DownloadChoiceListener implements EasyRecyclerView.CustomChoiceListener {
@Override
public void onIntoCustomChoice(EasyRecyclerView view) {
if (mRecyclerView != null) {
mRecyclerView.setOnItemLongClickListener(null);
mRecyclerView.setLongClickable(false);
}
if (mFabLayout != null) {
mFabLayout.setExpanded(true);
}
// Lock drawer
setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, Gravity.LEFT);
setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, Gravity.RIGHT);
}
@Override
public void onOutOfCustomChoice(EasyRecyclerView view) {
if (mRecyclerView != null) {
mRecyclerView.setOnItemLongClickListener(DownloadsScene.this);
}
if (mFabLayout != null) {
mFabLayout.setExpanded(false);
}
// Unlock drawer
setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, Gravity.LEFT);
setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, Gravity.RIGHT);
}
@Override
public void onItemCheckedStateChanged(EasyRecyclerView view, int position, long id, boolean checked) {
if (view.getCheckedItemCount() == 0) {
view.outOfCustomChoiceMode();
}
}
}
private class ThumbDataContainer implements DataContainer {
private final DownloadInfo mInfo;
@Nullable
private UniFile mFile;
public ThumbDataContainer(@NonNull DownloadInfo info) {
mInfo = info;
}
private void ensureFile() {
if (mFile == null) {
UniFile dir = SpiderDen.getGalleryDownloadDir(mInfo);
if (dir != null && dir.isDirectory()) {
mFile = dir.createFile(".thumb");
}
}
}
@Override
public boolean isEnabled() {
ensureFile();
return mFile != null;
}
@Override
public void onUrlMoved(String requestUrl, String responseUrl) {}
@Override
public boolean save(InputStream is, long length, String mediaType, ProgressNotifier notify) {
ensureFile();
if (mFile == null) {
return false;
}
OutputStream os = null;
try {
os = mFile.openOutputStream();
IOUtils.copy(is, os);
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
} finally {
IOUtils.closeQuietly(os);
}
}
@Override
public InputStreamPipe get() {
ensureFile();
if (mFile != null) {
return new UniFileInputStreamPipe(mFile);
} else {
return null;
}
}
@Override
public void remove() {
if (mFile != null) {
mFile.delete();
}
}
}
}