Add download
This commit is contained in:
1 parent
3aaf14ef3f
commit
4a80ea7dcd
43 files changed
+2167
-270
No files matched your search
+5
-5
@@ -2,13 +2,13 @@ apply plugin: 'com.android.model.application'
|
||||
|
||||
model {
|
||||
android {
|
||||
compileSdkVersion = 22
|
||||
buildToolsVersion = "23.0.0 rc3"
|
||||
compileSdkVersion = 23
|
||||
buildToolsVersion = "23.0.0"
|
||||
|
||||
defaultConfig.with {
|
||||
applicationId = "com.hippo.ehviewer.test"
|
||||
minSdkVersion.apiLevel = 14
|
||||
targetSdkVersion.apiLevel = 22
|
||||
targetSdkVersion.apiLevel = 23
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
}
|
||||
@@ -45,8 +45,8 @@ model {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'com.android.support:support-v4:22.2.1'
|
||||
compile 'com.android.support:appcompat-v7:22.2.1'
|
||||
compile 'com.android.support:support-v4:23.0.0'
|
||||
compile 'com.android.support:appcompat-v7:23.0.0'
|
||||
compile 'de.greenrobot:greendao:1.3.7'
|
||||
compile 'com.squareup.leakcanary:leakcanary-android:1.3.1'
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
|
||||
@@ -51,6 +51,11 @@
|
||||
|
||||
</activity>
|
||||
|
||||
<service
|
||||
android:name="com.hippo.ehviewer.service.DownloadService"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/download_server"/>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -30,6 +30,8 @@ public final class Constants {
|
||||
public static final int MESSENGER_ID_ARCHIVE_DOWNLOAD_LOCATION;
|
||||
public static final int MESSENGER_ID_UPDATE_QUICK_SEARCH;
|
||||
public static final int MESSENGER_ID_UPDATE_QUICK_SEARCH_NAME;
|
||||
public static final int MESSENGER_ID_UPDATE_DOWNLOAD;
|
||||
public static final int MESSENGER_ID_UPDATE_DOWNLOAD_TAG;
|
||||
|
||||
static {
|
||||
Messenger messenger = Messenger.getInstance();
|
||||
@@ -43,5 +45,7 @@ public final class Constants {
|
||||
MESSENGER_ID_ARCHIVE_DOWNLOAD_LOCATION = messenger.newId();
|
||||
MESSENGER_ID_UPDATE_QUICK_SEARCH = messenger.newId();
|
||||
MESSENGER_ID_UPDATE_QUICK_SEARCH_NAME = messenger.newId();
|
||||
MESSENGER_ID_UPDATE_DOWNLOAD = messenger.newId();
|
||||
MESSENGER_ID_UPDATE_DOWNLOAD_TAG = messenger.newId();
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import com.hippo.ehviewer.gallery.GallerySpider;
|
||||
import com.hippo.ehviewer.gallery.ImageHandler;
|
||||
import com.hippo.ehviewer.gallery.ui.TouchHelper;
|
||||
import com.hippo.ehviewer.network.EhHttpClient;
|
||||
import com.hippo.ehviewer.service.DownloadManager;
|
||||
import com.hippo.ehviewer.util.DBUtils;
|
||||
import com.hippo.ehviewer.util.Settings;
|
||||
import com.hippo.scene.SceneApplication;
|
||||
@@ -51,6 +52,7 @@ public class EhApplication extends SceneApplication {
|
||||
Settings.initialize(this);
|
||||
DBUtils.initialize(this);
|
||||
TouchHelper.initialize(this);
|
||||
DownloadManager.initialize();
|
||||
|
||||
File sayFile = AppConfig.getFileInAppDir("EhViewer.log");
|
||||
if (sayFile != null) {
|
||||
|
||||
@@ -289,8 +289,10 @@ public final class EhClient {
|
||||
// Clear
|
||||
mEhHttpRequest = null;
|
||||
mListener = null;
|
||||
} else if (status == Status.FINISHED) {
|
||||
mEhHttpRequest.disconnect();
|
||||
} else if (status == Status.RUNNING) {
|
||||
if (mEhHttpRequest != null) {
|
||||
mEhHttpRequest.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ class EhEngine {
|
||||
String body = response.getString();
|
||||
return SignInParser.parse(body);
|
||||
} catch (Exception e) {
|
||||
if (httpRequest.getState() == HttpRequest.STATE_DISCONNECT) {
|
||||
if (httpRequest.isCancelled()) {
|
||||
throw new CanceledException();
|
||||
} else {
|
||||
throw e;
|
||||
@@ -71,7 +71,7 @@ class EhEngine {
|
||||
String body = response.getString();
|
||||
return GalleryListParser.parse(body, source);
|
||||
} catch (Exception e) {
|
||||
if (httpRequest.getState() == HttpRequest.STATE_DISCONNECT) {
|
||||
if (httpRequest.isCancelled()) {
|
||||
throw new CanceledException();
|
||||
} else {
|
||||
throw e;
|
||||
@@ -93,7 +93,7 @@ class EhEngine {
|
||||
String body = response.getString();
|
||||
return PopularParser.parse(body);
|
||||
} catch (Exception e) {
|
||||
if (httpRequest.getState() == HttpRequest.STATE_DISCONNECT) {
|
||||
if (httpRequest.isCancelled()) {
|
||||
throw new CanceledException();
|
||||
} else {
|
||||
throw e;
|
||||
@@ -116,7 +116,7 @@ class EhEngine {
|
||||
GalleryDetailParser.REQUEST_PREVIEW |
|
||||
GalleryDetailParser.REQUEST_COMMENT);
|
||||
} catch (Exception e) {
|
||||
if (httpRequest.getState() == HttpRequest.STATE_DISCONNECT) {
|
||||
if (httpRequest.isCancelled()) {
|
||||
throw new CanceledException();
|
||||
} else {
|
||||
throw e;
|
||||
@@ -134,7 +134,7 @@ class EhEngine {
|
||||
String body = response.getString();
|
||||
return GalleryDetailParser.parsePreview(body, source);
|
||||
} catch (Exception e) {
|
||||
if (httpRequest.getState() == HttpRequest.STATE_DISCONNECT) {
|
||||
if (httpRequest.isCancelled()) {
|
||||
throw new CanceledException();
|
||||
} else {
|
||||
throw e;
|
||||
@@ -174,7 +174,7 @@ class EhEngine {
|
||||
|
||||
return list;
|
||||
} catch (Exception e) {
|
||||
if (httpRequest.getState() == HttpRequest.STATE_DISCONNECT) {
|
||||
if (httpRequest.isCancelled()) {
|
||||
throw new CanceledException();
|
||||
} else {
|
||||
throw e;
|
||||
@@ -203,7 +203,7 @@ class EhEngine {
|
||||
|
||||
return RateGalleryParser.parse(body);
|
||||
} catch (Exception e) {
|
||||
if (httpRequest.getState() == HttpRequest.STATE_DISCONNECT) {
|
||||
if (httpRequest.isCancelled()) {
|
||||
throw new CanceledException();
|
||||
} else {
|
||||
throw e;
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2015 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.client.data;
|
||||
|
||||
import com.hippo.ehviewer.dao.DownloadInfoObj;
|
||||
import com.hippo.ehviewer.util.DBUtils;
|
||||
|
||||
public class DownloadInfo {
|
||||
|
||||
public static final int STATE_NONE = 0x0;
|
||||
public static final int STATE_WAIT = 0x1;
|
||||
public static final int STATE_DOWNLOAD = 0x2;
|
||||
public static final int STATE_FINISH = 0x3;
|
||||
|
||||
public String tag;
|
||||
public GalleryBase galleryBase;
|
||||
public int state = STATE_NONE;
|
||||
// byte/second, -1 for can't get speed now
|
||||
public long speed;
|
||||
// -1 for unknown
|
||||
public int download = -1;
|
||||
// -1 for unknown
|
||||
public int total = -1;
|
||||
// Integer.MAX_VALUE for unknown
|
||||
public int legacy = Integer.MAX_VALUE;
|
||||
|
||||
public static DownloadInfo fromDownloadInfoObj(DownloadInfoObj obj) {
|
||||
GalleryBase galleryBase = DBUtils.getGalleryBase((int) (long) obj.getGid());
|
||||
if (galleryBase != null) {
|
||||
DownloadInfo downloadInfo = new DownloadInfo();
|
||||
downloadInfo.galleryBase = galleryBase;
|
||||
downloadInfo.tag = obj.getTag();
|
||||
downloadInfo.state = obj.getState();
|
||||
downloadInfo.legacy = obj.getLegacy();
|
||||
return downloadInfo;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,8 @@ public class GallerySpider implements GalleryProvider, SpiderQueen.SpiderListene
|
||||
private AtomicLongArray mReceivedSizes;
|
||||
private AtomicReferenceArray<Float> mPercents;
|
||||
|
||||
private List<GalleryProviderListener> mGalleryProviderListeners = new ArrayList<>();
|
||||
private List<GalleryProviderListener> mGalleryProviderListeners = new ArrayList<>(2);
|
||||
private List<SpiderQueen.SpiderListener> mSpiderListeners = new ArrayList<>(2);
|
||||
|
||||
private int mReference = 0;
|
||||
|
||||
@@ -160,6 +161,14 @@ public class GallerySpider implements GalleryProvider, SpiderQueen.SpiderListene
|
||||
mGalleryProviderListeners.remove(listener);
|
||||
}
|
||||
|
||||
public void addSpiderSpiderListener(SpiderQueen.SpiderListener listener) {
|
||||
mSpiderListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeSpiderSpiderListener(SpiderQueen.SpiderListener listener) {
|
||||
mSpiderListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object request(int index) {
|
||||
if (mSpiderQueen != null) {
|
||||
@@ -178,7 +187,11 @@ public class GallerySpider implements GalleryProvider, SpiderQueen.SpiderListene
|
||||
|
||||
@Override
|
||||
public Object forceRequest(int index) {
|
||||
return null;// TODO
|
||||
if (mSpiderQueen != null) {
|
||||
return mSpiderQueen.forceRequest(index);
|
||||
} else {
|
||||
return GalleryProvider.RESULT_OUT_OF_RANGE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -226,6 +239,10 @@ public class GallerySpider implements GalleryProvider, SpiderQueen.SpiderListene
|
||||
for (GalleryProviderListener l : mGalleryProviderListeners) {
|
||||
l.onTotallyFailed(e);
|
||||
}
|
||||
|
||||
for (SpiderQueen.SpiderListener l : mSpiderListeners) {
|
||||
l.onTotallyFailed(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -238,13 +255,24 @@ public class GallerySpider implements GalleryProvider, SpiderQueen.SpiderListene
|
||||
for (GalleryProviderListener l : mGalleryProviderListeners) {
|
||||
l.onPartlyFailed(e);
|
||||
}
|
||||
|
||||
for (SpiderQueen.SpiderListener l : mSpiderListeners) {
|
||||
l.onPartlyFailed(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDone() {
|
||||
// TODO
|
||||
public void onDone(final int legacy) {
|
||||
SimpleHandler.getInstance().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (SpiderQueen.SpiderListener l : mSpiderListeners) {
|
||||
l.onDone(legacy);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -259,6 +287,10 @@ public class GallerySpider implements GalleryProvider, SpiderQueen.SpiderListene
|
||||
for (GalleryProviderListener l : mGalleryProviderListeners) {
|
||||
l.onGetSize(pages);
|
||||
}
|
||||
|
||||
for (SpiderQueen.SpiderListener l : mSpiderListeners) {
|
||||
l.onGetPages(pages);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -277,17 +309,21 @@ public class GallerySpider implements GalleryProvider, SpiderQueen.SpiderListene
|
||||
for (GalleryProviderListener l : mGalleryProviderListeners) {
|
||||
l.onPagePercent(index, 0.0f);
|
||||
}
|
||||
|
||||
for (SpiderQueen.SpiderListener l : mSpiderListeners) {
|
||||
l.onSpiderStart(index, totalSize);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpiderPage(final int index, long receivedSize) {
|
||||
public void onSpiderPage(final int index, final long receivedSize, final long singleReceivedSize) {
|
||||
if (mReceivedSizes != null && index >= 0 && index < mReceivedSizes.length()) {
|
||||
mReceivedSizes.lazySet(index, receivedSize);
|
||||
}
|
||||
|
||||
long totalSize= mTotalSizes.get(index);
|
||||
final long totalSize= mTotalSizes.get(index);
|
||||
final float percent = totalSize == 0 ? 0.0f :
|
||||
(float) receivedSize / (float) totalSize;
|
||||
|
||||
@@ -299,6 +335,10 @@ public class GallerySpider implements GalleryProvider, SpiderQueen.SpiderListene
|
||||
for (GalleryProviderListener l : mGalleryProviderListeners) {
|
||||
l.onPagePercent(index, percent);
|
||||
}
|
||||
|
||||
for (SpiderQueen.SpiderListener l : mSpiderListeners) {
|
||||
l.onSpiderPage(index, receivedSize, singleReceivedSize);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -311,6 +351,10 @@ public class GallerySpider implements GalleryProvider, SpiderQueen.SpiderListene
|
||||
for (GalleryProviderListener l : mGalleryProviderListeners) {
|
||||
l.onPageSucceed(index);
|
||||
}
|
||||
|
||||
for (SpiderQueen.SpiderListener l : mSpiderListeners) {
|
||||
l.onSpiderSucceed(index);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -323,10 +367,21 @@ public class GallerySpider implements GalleryProvider, SpiderQueen.SpiderListene
|
||||
for (GalleryProviderListener l : mGalleryProviderListeners) {
|
||||
l.onPageFailed(index, e);
|
||||
}
|
||||
|
||||
for (SpiderQueen.SpiderListener l : mSpiderListeners) {
|
||||
l.onSpiderFailed(index, e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpiderCancelled(final int index) {
|
||||
for (SpiderQueen.SpiderListener l : mSpiderListeners) {
|
||||
l.onSpiderCancelled(index);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGetImage(final int index, final Object obj) {
|
||||
SimpleHandler.getInstance().post(new Runnable() {
|
||||
|
||||
@@ -250,6 +250,31 @@ public class ImageHandler {
|
||||
}
|
||||
}
|
||||
|
||||
public void removeFromRead(int index) {
|
||||
sDiskCache.remove(EhCacheKeyFactory.getImageKey(mGalleryBase.gid, index));
|
||||
}
|
||||
|
||||
public void removeFromDownload(int index) {
|
||||
if (mDownloadDir == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (String extension : POSSIBLE_IMAGE_EXTENSIONS) {
|
||||
String filename = getImageFilename(index, extension);
|
||||
UniFile file = mDownloadDir.findFile(filename);
|
||||
if (file != null) {
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(int index) {
|
||||
removeFromRead(index);
|
||||
if (mMode == Mode.DOWNLOAD) {
|
||||
removeFromDownload(index);
|
||||
}
|
||||
}
|
||||
|
||||
public void save(HttpClient httpClient, String url, int index, SaveHelper helper) throws Exception {
|
||||
OutputStreamPipe osPipe = null;
|
||||
|
||||
@@ -328,8 +353,8 @@ public class ImageHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDonwlad(long receivedSize) {
|
||||
mHelper.onSave(receivedSize);
|
||||
public void onDonwlad(long receivedSize, long singleReceivedSize) {
|
||||
mHelper.onSave(receivedSize, singleReceivedSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -442,7 +467,7 @@ public class ImageHandler {
|
||||
|
||||
public abstract void onStartSaving(long totalSize);
|
||||
|
||||
public abstract void onSave(long receivedSize);
|
||||
public abstract void onSave(long receivedSize, long singleReceivedSize);
|
||||
|
||||
public boolean isCancelled() {
|
||||
return mCancel;
|
||||
|
||||
@@ -20,12 +20,13 @@ import android.util.Log;
|
||||
|
||||
import com.hippo.ehviewer.client.EhConfig;
|
||||
import com.hippo.ehviewer.client.data.GalleryBase;
|
||||
import com.hippo.yorozuya.AssertUtils;
|
||||
import com.hippo.yorozuya.AutoExpandArray;
|
||||
import com.hippo.yorozuya.IOUtils;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.EOFException;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@@ -72,119 +73,86 @@ public class SpiderInfo {
|
||||
}
|
||||
|
||||
GalleryBase gb = galleryBase;
|
||||
OutputStreamWriter osWrite = new OutputStreamWriter(os, "UTF-8");
|
||||
osWrite.append(Integer.toString(VERSION)).append('\n')
|
||||
.append(Integer.toString(gb.gid)).append('\n')
|
||||
.append(gb.token).append('\n')
|
||||
.append(stringToHexString(gb.title)).append('\n')
|
||||
.append(stringToHexString(gb.titleJpn)).append('\n')
|
||||
.append(gb.thumb).append('\n')
|
||||
.append(Integer.toString(gb.category)).append('\n')
|
||||
.append(gb.posted).append('\n')
|
||||
.append(gb.uploader).append('\n')
|
||||
.append(Float.toString(gb.rating)).append('\n')
|
||||
.append(Integer.toString(pages)).append('\n')
|
||||
.append(previewSize).append('\n')
|
||||
.append(Integer.toString(previewPages)).append('\n')
|
||||
.append(Integer.toString(previewCountPerPage)).append('\n');
|
||||
JSONObject jo;
|
||||
try {
|
||||
jo = new JSONObject();
|
||||
jo.put("version", VERSION);
|
||||
jo.put("gid", gb.gid);
|
||||
jo.put("token", gb.token);
|
||||
jo.put("title", gb.title);
|
||||
jo.put("titleJpn", gb.titleJpn);
|
||||
jo.put("thumb", gb.thumb);
|
||||
jo.put("category", gb.category);
|
||||
jo.put("posted", gb.posted);
|
||||
jo.put("uploader", gb.uploader);
|
||||
jo.put("rating", gb.rating);
|
||||
jo.put("pages", pages);
|
||||
jo.put("previewSize", previewSize);
|
||||
jo.put("previewPages", previewPages);
|
||||
jo.put("previewCountPerPage", previewCountPerPage);
|
||||
|
||||
if (tokens != null) {
|
||||
JSONArray tokenJa = new JSONArray();
|
||||
int length = Math.min(tokens.maxValidIndex() + 1, pages);
|
||||
for (int i = 0; i < length; i++) {
|
||||
String token = tokens.get(i);
|
||||
if (token != null) {
|
||||
osWrite.append(Integer.toString(i)).append(':')
|
||||
.append(token).append('\n');
|
||||
}
|
||||
tokenJa.put(tokens.get(i));
|
||||
}
|
||||
|
||||
jo.put("tokens", tokenJa);
|
||||
} catch (JSONException e) {
|
||||
Log.e(TAG, "Can't create SpiderInfo JSON to write", e);
|
||||
jo = null;
|
||||
}
|
||||
|
||||
osWrite.flush();
|
||||
osWrite.close();
|
||||
if (jo != null) {
|
||||
OutputStreamWriter osWrite = new OutputStreamWriter(os, "UTF-8");
|
||||
osWrite.append(jo.toString());
|
||||
osWrite.flush();
|
||||
osWrite.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static SpiderInfo read(InputStream is) throws Exception {
|
||||
BufferedInputStream bis = new BufferedInputStream(is);
|
||||
SpiderInfo spiderInfo = new SpiderInfo();
|
||||
String str = IOUtils.readString(is, "UTF-8");
|
||||
|
||||
int version = Integer.parseInt(IOUtils.readAsciiLine(bis));
|
||||
JSONObject jo = new JSONObject(str);
|
||||
|
||||
int version = jo.optInt("version", 0);
|
||||
if (VERSION != version){
|
||||
throw new IllegalStateException("Version should be " + VERSION +
|
||||
", but it is " + version);
|
||||
}
|
||||
|
||||
SpiderInfo spiderInfo = new SpiderInfo();
|
||||
|
||||
GalleryBase gb = new GalleryBase();
|
||||
gb.gid = Integer.parseInt(IOUtils.readAsciiLine(bis));
|
||||
gb.token = IOUtils.readAsciiLine(bis);
|
||||
gb.title = hexStringToString(IOUtils.readAsciiLine(bis));
|
||||
gb.titleJpn = hexStringToString(IOUtils.readAsciiLine(bis));
|
||||
gb.thumb = IOUtils.readAsciiLine(bis);
|
||||
gb.category = Integer.parseInt(IOUtils.readAsciiLine(bis));
|
||||
gb.posted = IOUtils.readAsciiLine(bis);
|
||||
gb.uploader = IOUtils.readAsciiLine(bis);
|
||||
gb.rating = Float.parseFloat(IOUtils.readAsciiLine(bis));
|
||||
gb.gid = jo.getInt("gid");
|
||||
gb.token = jo.getString("token");
|
||||
gb.title = jo.getString("title");
|
||||
gb.titleJpn = jo.optString("titleJpn", null);
|
||||
gb.thumb = jo.getString("thumb");
|
||||
gb.category = jo.getInt("category");
|
||||
gb.posted = jo.getString("posted");
|
||||
gb.uploader = jo.getString("uploader");
|
||||
gb.rating = (float) jo.getDouble("rating");
|
||||
spiderInfo.galleryBase = gb;
|
||||
|
||||
spiderInfo.pages = Integer.parseInt(IOUtils.readAsciiLine(bis));
|
||||
spiderInfo.previewSize = IOUtils.readAsciiLine(bis);
|
||||
spiderInfo.pages = jo.getInt("pages");
|
||||
spiderInfo.previewSize = jo.getString("previewSize");
|
||||
if (!spiderInfo.previewSize.equals(EhConfig.PREVIEW_SIZE_NORMAL) &&
|
||||
!spiderInfo.previewSize.equals(EhConfig.PREVIEW_SIZE_LARGE)) {
|
||||
throw new IllegalStateException("Unknown preview size " + spiderInfo.previewSize);
|
||||
}
|
||||
spiderInfo.previewPages = Integer.parseInt(IOUtils.readAsciiLine(bis));
|
||||
spiderInfo.previewCountPerPage = Integer.parseInt(IOUtils.readAsciiLine(bis));
|
||||
spiderInfo.previewPages = jo.getInt("previewPages");
|
||||
spiderInfo.previewCountPerPage = jo.getInt("previewCountPerPage");
|
||||
|
||||
AutoExpandArray<String> tokens = new AutoExpandArray<>(spiderInfo.pages);
|
||||
try {
|
||||
//noinspection InfiniteLoopStatement
|
||||
for (;;) {
|
||||
String line = IOUtils.readAsciiLine(is);
|
||||
int pos = line.indexOf(":");
|
||||
if (pos < 0) {
|
||||
Log.e(TAG, "Can't parse line " + line);
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
int index = Integer.parseInt(line.substring(0, pos));
|
||||
String token = line.substring(pos + 1);
|
||||
tokens.set(index, token);
|
||||
} catch (NumberFormatException e) {
|
||||
// Empty
|
||||
Log.e(TAG, "Can't parse line " + line);
|
||||
}
|
||||
}
|
||||
} catch (EOFException e) {
|
||||
// Empty
|
||||
}
|
||||
JSONArray ja = jo.getJSONArray("tokens");
|
||||
AutoExpandArray<String> tokens = new AutoExpandArray<>(ja.length());
|
||||
spiderInfo.tokens = tokens;
|
||||
for (int i = 0, n = ja.length(); i < n; i++) {
|
||||
tokens.set(i, ja.getString(i));
|
||||
}
|
||||
|
||||
return spiderInfo;
|
||||
}
|
||||
|
||||
public static String stringToHexString(String str) {
|
||||
StringBuilder sb = new StringBuilder(320);
|
||||
int length = str.length();
|
||||
for (int i = 0; i < length; i++) {
|
||||
char ch = str.charAt(i);
|
||||
String s = Integer.toString((int) ch, 16);
|
||||
int length2 = 4 - s.length();
|
||||
for (int j = 0; j < length2; j++) {
|
||||
sb.append('0');
|
||||
}
|
||||
sb.append(s);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static String hexStringToString(String str) {
|
||||
AssertUtils.assertEquals("Hex String's length must be a multiple of 4.", str.length() % 4, 0);
|
||||
|
||||
StringBuilder sb = new StringBuilder(80);
|
||||
int length = str.length();
|
||||
for (int i = 0; i < length; i += 4) {
|
||||
sb.append((char) Integer.parseInt(str.substring(i, i + 4), 16));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,6 @@ import com.hippo.yorozuya.Say;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.LinkedList;
|
||||
@@ -47,8 +46,6 @@ import java.util.List;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicIntegerArray;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
public class SpiderQueen implements Runnable {
|
||||
|
||||
@@ -79,9 +76,11 @@ public class SpiderQueen implements Runnable {
|
||||
private SpiderListener mSpiderListener;
|
||||
|
||||
public SpiderInfo mSpiderInfo;
|
||||
|
||||
public boolean mHasCheckIndexAgain = true;
|
||||
public volatile int mNextIndex;
|
||||
public AtomicIntegerArray mPageStates;
|
||||
public int[] mPageStates;
|
||||
public LinkedList<Integer> mRequestIndex = new LinkedList<>();
|
||||
|
||||
private volatile HttpRequest mCurrentHttpRequest;
|
||||
|
||||
@@ -100,8 +99,8 @@ public class SpiderQueen implements Runnable {
|
||||
// The lock to make worker sleep
|
||||
private final Object mWorkerLock = new Object();
|
||||
// The lock for next index
|
||||
private final Object mNextIndexLock = new Object();
|
||||
private final ReentrantLock mWorkerArrayLock = new ReentrantLock();
|
||||
private final Object mIndexLock = new Object();
|
||||
private final Object mWorkerArrayLock = new Object();
|
||||
// Lock for mRequestTokens and mSpiderInfo.tokens
|
||||
private final Object mTokenLock = new Object();
|
||||
// The lock to make sure onGetSize call first
|
||||
@@ -142,7 +141,7 @@ public class SpiderQueen implements Runnable {
|
||||
return GalleryProvider.RESULT_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
int state = mPageStates.get(index);
|
||||
int state = getPageState(index);
|
||||
switch (state) {
|
||||
case PAGE_STATE_NONE:
|
||||
// TODO set next index
|
||||
@@ -169,11 +168,8 @@ public class SpiderQueen implements Runnable {
|
||||
if (index < 0 || index >= mSpiderInfo.pages) {
|
||||
return GalleryProvider.RESULT_OUT_OF_RANGE;
|
||||
}
|
||||
// TODO
|
||||
throw new IllegalStateException();
|
||||
|
||||
|
||||
|
||||
addRequestIndex(index);
|
||||
return GalleryProvider.RESULT_WAIT;
|
||||
} else {
|
||||
return GalleryProvider.RESULT_OUT_OF_RANGE;
|
||||
}
|
||||
@@ -188,7 +184,7 @@ public class SpiderQueen implements Runnable {
|
||||
public void stop() {
|
||||
mStop = true;
|
||||
if (mCurrentHttpRequest != null) {
|
||||
mCurrentHttpRequest.disconnect();
|
||||
mCurrentHttpRequest.cancel();
|
||||
mCurrentHttpRequest = null;
|
||||
}
|
||||
synchronized (mQueenLock) {
|
||||
@@ -211,7 +207,7 @@ public class SpiderQueen implements Runnable {
|
||||
}
|
||||
|
||||
public int pages() {
|
||||
if (mSpiderInfo != null) {
|
||||
if (mSpiderInfo != null && mGetSizeFinished) {
|
||||
return mSpiderInfo.pages;
|
||||
} else {
|
||||
return -1;
|
||||
@@ -567,17 +563,19 @@ public class SpiderQueen implements Runnable {
|
||||
return;
|
||||
}
|
||||
|
||||
setGetSizeFinished(false);
|
||||
|
||||
// 5. Perpare
|
||||
// Update EhConfig preview size
|
||||
ehConfig.previewSize = spiderInfo.previewSize;
|
||||
ehConfig.setDirty();
|
||||
mSpiderInfo = spiderInfo;
|
||||
mNextIndex = 0;
|
||||
// Init AtomicIntegerArray stuff
|
||||
// Init int array stuff
|
||||
int length = spiderInfo.pages;
|
||||
mPageStates = new AtomicIntegerArray(length);
|
||||
mPageStates = new int[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
mPageStates.lazySet(i, PAGE_STATE_NONE);
|
||||
mPageStates[i] = PAGE_STATE_NONE;
|
||||
}
|
||||
mSpiderWorkers = new SpiderWorker[3];
|
||||
mImageHandler = new ImageHandler(gb, spiderInfo.pages, mMode, mDownloadDirparent, mDownloadDirname);
|
||||
@@ -587,7 +585,6 @@ public class SpiderQueen implements Runnable {
|
||||
}
|
||||
|
||||
// 6. Make workers and render to work
|
||||
setGetSizeFinished(false);
|
||||
ensureWorker();
|
||||
mRender = new Render();
|
||||
Thread thread = new PriorityThread(mRender, "Render", Process.THREAD_PRIORITY_BACKGROUND);
|
||||
@@ -601,42 +598,30 @@ public class SpiderQueen implements Runnable {
|
||||
// 8. Get tokens
|
||||
handleToken(spiderInfo, ehConfig);
|
||||
|
||||
// 5. The queen dies, workers die, render dies
|
||||
mWorkerArrayLock.lock();
|
||||
|
||||
for (SpiderWorker worker : mSpiderWorkers) {
|
||||
if (worker != null) {
|
||||
worker.stop();
|
||||
// 9. The queen dies, workers die, render dies
|
||||
synchronized (mWorkerArrayLock) {
|
||||
for (SpiderWorker worker : mSpiderWorkers) {
|
||||
if (worker != null) {
|
||||
worker.stop();
|
||||
}
|
||||
}
|
||||
synchronized (mWorkerLock) {
|
||||
mWorkerLock.notifyAll();
|
||||
}
|
||||
}
|
||||
synchronized (mWorkerLock) {
|
||||
mWorkerLock.notifyAll();
|
||||
}
|
||||
|
||||
mWorkerArrayLock.unlock();
|
||||
|
||||
mRender.stop();
|
||||
}
|
||||
|
||||
private void ensureWorker() {
|
||||
mWorkerArrayLock.lock();
|
||||
|
||||
int length = mSpiderWorkers.length;
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (mSpiderWorkers[i] == null) {
|
||||
SpiderWorker worker = new SpiderWorker(i);
|
||||
mSpiderWorkers[i] = worker;
|
||||
mThreadFactory.newThread(worker).start();
|
||||
}
|
||||
}
|
||||
|
||||
mWorkerArrayLock.unlock();
|
||||
}
|
||||
|
||||
private void setNextIndex(int index) {
|
||||
synchronized (mNextIndexLock) {
|
||||
if (mSpiderInfo != null && index < mSpiderInfo.pages) {
|
||||
mNextIndex = index;
|
||||
synchronized (mWorkerArrayLock) {
|
||||
int length = mSpiderWorkers.length;
|
||||
for (int i = 0; i < length; i++) {
|
||||
if (mSpiderWorkers[i] == null) {
|
||||
SpiderWorker worker = new SpiderWorker(i);
|
||||
mSpiderWorkers[i] = worker;
|
||||
mThreadFactory.newThread(worker).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -656,29 +641,79 @@ public class SpiderQueen implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO request index may
|
||||
private void setNextIndex(int index) {
|
||||
synchronized (mIndexLock) {
|
||||
if (mSpiderInfo != null && index < mSpiderInfo.pages) {
|
||||
mNextIndex = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getPageState(int index) {
|
||||
synchronized (mIndexLock) {
|
||||
return mPageStates[index];
|
||||
}
|
||||
}
|
||||
|
||||
private void setPageState(int index, int state) {
|
||||
synchronized (mIndexLock) {
|
||||
mPageStates[index] = state;
|
||||
}
|
||||
}
|
||||
|
||||
// it to request queue
|
||||
private void addRequestIndex(int index) {
|
||||
synchronized (mTokenLock) {
|
||||
if (mPageStates[index] != PAGE_STATE_SPIDER) {
|
||||
mPageStates[index] = PAGE_STATE_NONE;
|
||||
mRequestIndex.add(index);
|
||||
mImageHandler.remove(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get first PAGE_STATE_NONE index and set state PAGE_STATE_SPIDER
|
||||
private int getRequestIndex() {
|
||||
synchronized (mNextIndexLock) {
|
||||
synchronized (mIndexLock) {
|
||||
int length = mSpiderInfo.pages;
|
||||
|
||||
for (;;) {
|
||||
if (mNextIndex >= length) {
|
||||
if (!mHasCheckIndexAgain) {
|
||||
mHasCheckIndexAgain = true;
|
||||
mNextIndex = 0;
|
||||
} else {
|
||||
return -1;
|
||||
int index;
|
||||
if (mRequestIndex.isEmpty()) {
|
||||
if (mNextIndex >= length) {
|
||||
if (!mHasCheckIndexAgain) {
|
||||
mHasCheckIndexAgain = true;
|
||||
mNextIndex = 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
index = mNextIndex++;
|
||||
} else {
|
||||
index = mRequestIndex.remove(0);
|
||||
}
|
||||
|
||||
int index = mNextIndex;
|
||||
if (mPageStates.get(mNextIndex++) == PAGE_STATE_NONE) {
|
||||
if (mPageStates[index] == PAGE_STATE_NONE) {
|
||||
mPageStates[index] = PAGE_STATE_SPIDER;
|
||||
return index;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int getLegacy() {
|
||||
synchronized (mIndexLock) {
|
||||
int legacy = 0;
|
||||
for (int i = 0, n = mPageStates.length; i < n; i++) {
|
||||
int state = mPageStates[i];
|
||||
if (state != PAGE_STATE_SUCCEED) {
|
||||
legacy++;
|
||||
}
|
||||
}
|
||||
return legacy;
|
||||
}
|
||||
}
|
||||
|
||||
class SpiderWorker implements Runnable {
|
||||
|
||||
private String TAG = SpiderWorker.class.getSimpleName();
|
||||
@@ -698,7 +733,7 @@ public class SpiderQueen implements Runnable {
|
||||
public void stop() {
|
||||
mStop = true;
|
||||
if (mCurrentHttpRequest != null) {
|
||||
mCurrentHttpRequest.disconnect();
|
||||
mCurrentHttpRequest.cancel();
|
||||
mCurrentHttpRequest = null;
|
||||
}
|
||||
if (mCurrentSaveHelper != null) {
|
||||
@@ -738,6 +773,13 @@ public class SpiderQueen implements Runnable {
|
||||
Exception exception = null;
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
// Check stop
|
||||
if (mStop) {
|
||||
setPageState(index, PAGE_STATE_NONE);
|
||||
mSpiderListener.onSpiderCancelled(index);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get image url
|
||||
GalleryPageParser.Result result;
|
||||
try {
|
||||
@@ -749,6 +791,13 @@ public class SpiderQueen implements Runnable {
|
||||
imageUrl = result.imageUrl;
|
||||
skipHathKey = result.skipHathKey;
|
||||
|
||||
// Check stop
|
||||
if (mStop) {
|
||||
setPageState(index, PAGE_STATE_NONE);
|
||||
mSpiderListener.onSpiderCancelled(index);
|
||||
return;
|
||||
}
|
||||
|
||||
// Download image
|
||||
try {
|
||||
mCurrentSaveHelper = new ImageHandler.SaveHelper() {
|
||||
@@ -758,18 +807,18 @@ public class SpiderQueen implements Runnable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSave(long receivedSize) {
|
||||
mSpiderListener.onSpiderPage(index, receivedSize);
|
||||
public void onSave(long receivedSize, long singleReceivedSize) {
|
||||
mSpiderListener.onSpiderPage(index, receivedSize, singleReceivedSize);
|
||||
}
|
||||
};
|
||||
mImageHandler.save(mHttpClient, imageUrl, index, mCurrentSaveHelper);
|
||||
mPageStates.set(index, PAGE_STATE_SUCCEED);
|
||||
setPageState(index, PAGE_STATE_SUCCEED);
|
||||
mSpiderListener.onSpiderSucceed(index);
|
||||
return;
|
||||
} catch (Exception e) {
|
||||
if (mCurrentSaveHelper != null && mCurrentSaveHelper.isCancelled()) {
|
||||
mPageStates.lazySet(index, PAGE_STATE_FAILED);
|
||||
mSpiderListener.onSpiderFailed(index, new IOException("Cancelled"));
|
||||
setPageState(index, PAGE_STATE_NONE);
|
||||
mSpiderListener.onSpiderCancelled(index);
|
||||
return;
|
||||
} else {
|
||||
exception = e;
|
||||
@@ -779,12 +828,10 @@ public class SpiderQueen implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
mPageStates.lazySet(index, PAGE_STATE_FAILED);
|
||||
setPageState(index, PAGE_STATE_FAILED);
|
||||
mSpiderListener.onSpiderFailed(index, exception);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
TAG = Thread.currentThread().getName();
|
||||
@@ -803,14 +850,12 @@ public class SpiderQueen implements Runnable {
|
||||
if (index == -1) {
|
||||
// There is no more
|
||||
break;
|
||||
} else {
|
||||
mPageStates.lazySet(index, PAGE_STATE_SPIDER);
|
||||
}
|
||||
|
||||
// Check contain
|
||||
if (handler.contain(index)) {
|
||||
// Find it, no need to download
|
||||
mPageStates.lazySet(index, PAGE_STATE_SUCCEED);
|
||||
setPageState(index, PAGE_STATE_SUCCEED);
|
||||
// Listener
|
||||
mSpiderListener.onSpiderSucceed(index);
|
||||
continue;
|
||||
@@ -835,19 +880,26 @@ public class SpiderQueen implements Runnable {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// For stop
|
||||
if (mStop) {
|
||||
mPageStates.lazySet(index, PAGE_STATE_NONE);
|
||||
break;
|
||||
}
|
||||
|
||||
downloadPage(gb.gid, index, token);
|
||||
}
|
||||
|
||||
// TODO this lock is not right, we need to lock when before check it is over
|
||||
mWorkerArrayLock.lock();
|
||||
mSpiderWorkers[mIndex] = null;
|
||||
mWorkerArrayLock.unlock();
|
||||
synchronized (mWorkerArrayLock) {
|
||||
mSpiderWorkers[mIndex] = null;
|
||||
|
||||
boolean allDie = true;
|
||||
for (SpiderWorker worker : mSpiderWorkers) {
|
||||
if (worker != null) {
|
||||
allDie = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (allDie) {
|
||||
// Get legacy
|
||||
mSpiderListener.onDone(getLegacy());
|
||||
}
|
||||
}
|
||||
|
||||
Say.d(TAG, Thread.currentThread().getName() + " dies");
|
||||
}
|
||||
@@ -943,22 +995,20 @@ public class SpiderQueen implements Runnable {
|
||||
|
||||
void onPartlyFailed(Exception e);
|
||||
|
||||
/**
|
||||
* The whole gallery has been spidered
|
||||
* TODO
|
||||
*/
|
||||
void onDone();
|
||||
void onDone(int legacy);
|
||||
|
||||
void onGetPages(int pages);
|
||||
|
||||
void onSpiderStart(int index, long totalSize);
|
||||
|
||||
void onSpiderPage(int index, long receivedSize);
|
||||
void onSpiderPage(int index, long receivedSize, long singleReceivedSize);
|
||||
|
||||
void onSpiderSucceed(int index);
|
||||
|
||||
void onSpiderFailed(int index, Exception e);
|
||||
|
||||
void onSpiderCancelled(int index);
|
||||
|
||||
void onGetImage(int index, Object obj);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,595 @@
|
||||
/*
|
||||
* Copyright 2015 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.service;
|
||||
|
||||
import android.os.SystemClock;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.hippo.ehviewer.Constants;
|
||||
import com.hippo.ehviewer.client.data.DownloadInfo;
|
||||
import com.hippo.ehviewer.client.data.GalleryBase;
|
||||
import com.hippo.ehviewer.gallery.GallerySpider;
|
||||
import com.hippo.ehviewer.gallery.ImageHandler;
|
||||
import com.hippo.ehviewer.gallery.SpiderQueen;
|
||||
import com.hippo.ehviewer.util.DBUtils;
|
||||
import com.hippo.ehviewer.util.EhUtils;
|
||||
import com.hippo.yorozuya.Messenger;
|
||||
import com.hippo.yorozuya.SimpleHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class DownloadManager {
|
||||
|
||||
private static final String TAG = DownloadManager.class.getSimpleName();
|
||||
|
||||
public static final int OPS_SHIFT = 30;
|
||||
public static final int OPS_MASK = 0x3 << OPS_SHIFT;
|
||||
public static final int OPS_ADD = 0 << OPS_SHIFT;
|
||||
public static final int OPS_REMOVE = 1 << OPS_SHIFT;
|
||||
public static final int OPS_UPDATE = 2 << OPS_SHIFT;
|
||||
//
|
||||
public static final int OPS_ALL_CHANGE = 3 << OPS_SHIFT;
|
||||
|
||||
public static int getOps(int mix) {
|
||||
return (mix & OPS_MASK);
|
||||
}
|
||||
|
||||
public static int getGid(int mix) {
|
||||
return (mix & ~OPS_MASK);
|
||||
}
|
||||
|
||||
public static int makeMix(int gid, int ops) {
|
||||
return (gid & ~OPS_MASK) | (ops & OPS_MASK);
|
||||
}
|
||||
|
||||
private List<DownloadInfo> mDownloadInfos;
|
||||
private Map<String, List<DownloadInfo>> mDownloadInfoMap;
|
||||
private List<DownloadInfo> mDefaultDownloadInfos;
|
||||
|
||||
private List<DownloadInfo> mWaitList;
|
||||
|
||||
private @Nullable DownloadInfo mCurrentTask;
|
||||
private GallerySpider mCurrentSpider;
|
||||
|
||||
private SpeedReminder mSpeedReminder;
|
||||
private DownloadSpiderListener mDownloadSpiderListener;
|
||||
private @Nullable DownloadUpdateListener mDownloadUpdateListener;
|
||||
private DownloadUpdateInfo mUpdateInfo;
|
||||
|
||||
private static DownloadManager sInstance;
|
||||
|
||||
public static void initialize() {
|
||||
sInstance = new DownloadManager();
|
||||
}
|
||||
|
||||
public static DownloadManager getInstance() {
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
public DownloadManager() {
|
||||
List<String> tags = DBUtils.getAllDownloadTag();
|
||||
List<DownloadInfo> downloadInfos = DBUtils.getAllDownloadInfo();
|
||||
mDownloadInfos = downloadInfos;
|
||||
mDownloadInfoMap = new HashMap<>();
|
||||
|
||||
// Create list for each tag
|
||||
for (String tag : tags) {
|
||||
mDownloadInfoMap.put(tag, new ArrayList<DownloadInfo>());
|
||||
}
|
||||
// Create default for non tag
|
||||
mDefaultDownloadInfos = new ArrayList<>();
|
||||
|
||||
// Fill each list with DownloadInfo
|
||||
for (DownloadInfo info : downloadInfos) {
|
||||
// Fix download state
|
||||
if (info.state == DownloadInfo.STATE_DOWNLOAD || info.state == DownloadInfo.STATE_WAIT) {
|
||||
info.state = DownloadInfo.STATE_NONE;
|
||||
}
|
||||
|
||||
List<DownloadInfo> list;
|
||||
if (TextUtils.isEmpty(info.tag)) {
|
||||
list = mDefaultDownloadInfos;
|
||||
} else {
|
||||
list = mDownloadInfoMap.get(info.tag);
|
||||
}
|
||||
|
||||
if (list == null) {
|
||||
list = mDefaultDownloadInfos;
|
||||
}
|
||||
|
||||
list.add(info);
|
||||
}
|
||||
|
||||
mWaitList = new LinkedList<>();
|
||||
mSpeedReminder = new SpeedReminder();
|
||||
mDownloadSpiderListener = new DownloadSpiderListener();
|
||||
mUpdateInfo = new DownloadUpdateInfo();
|
||||
}
|
||||
|
||||
public void setDownloadUpdateListener(@Nullable DownloadUpdateListener listener) {
|
||||
mDownloadUpdateListener = listener;
|
||||
}
|
||||
|
||||
public List<DownloadInfo> getDownloadList(String tag) {
|
||||
return getDownloadListInternal(tag, false);
|
||||
}
|
||||
|
||||
private List<DownloadInfo> getDownloadListInternal(String tag, boolean create) {
|
||||
if (TextUtils.isEmpty(tag)) {
|
||||
return mDefaultDownloadInfos;
|
||||
} else {
|
||||
List<DownloadInfo> list = mDownloadInfoMap.get(tag);
|
||||
if (list == null && create) {
|
||||
list = new ArrayList<>();
|
||||
mDownloadInfoMap.put(tag, list);
|
||||
// notify
|
||||
Messenger.getInstance().notify(Constants.MESSENGER_ID_UPDATE_DOWNLOAD_TAG, null);
|
||||
// Save tag to DB
|
||||
DBUtils.addDownloadTag(tag);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure is downloading
|
||||
private void ensureDownload() {
|
||||
if (mCurrentTask != null) {
|
||||
// Only one download
|
||||
return;
|
||||
}
|
||||
|
||||
Log.v(TAG, "ensureDownload");
|
||||
|
||||
// get download from wait list
|
||||
if (!mWaitList.isEmpty()) {
|
||||
DownloadInfo info = mWaitList.remove(0);
|
||||
GallerySpider spider = null;
|
||||
try {
|
||||
spider = GallerySpider.obtain(info.galleryBase, ImageHandler.Mode.DOWNLOAD);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (spider != null) {
|
||||
int gid = info.galleryBase.gid;
|
||||
mCurrentTask = info;
|
||||
mCurrentSpider = spider;
|
||||
info.state = DownloadInfo.STATE_DOWNLOAD;
|
||||
info.speed = -1;
|
||||
// Fill Download update info
|
||||
DownloadUpdateInfo updateInfo = mUpdateInfo;
|
||||
updateInfo.gid = gid;
|
||||
updateInfo.title = EhUtils.getSuitableTitle(info.galleryBase);
|
||||
updateInfo.pages = spider.size();
|
||||
updateInfo.downloadedPages = 0;
|
||||
updateInfo.speed = -1;
|
||||
updateInfo.legacy = Integer.MAX_VALUE;
|
||||
// Notify
|
||||
Messenger.getInstance().notify(Constants.MESSENGER_ID_UPDATE_DOWNLOAD,
|
||||
makeMix(gid, OPS_UPDATE));
|
||||
// Listener
|
||||
if (mDownloadUpdateListener != null) {
|
||||
mDownloadUpdateListener.onStart(updateInfo);
|
||||
}
|
||||
// Update DownloadInfo to DB
|
||||
DBUtils.updateDownloadInfo(info);
|
||||
|
||||
info.total = spider.size();
|
||||
mDownloadSpiderListener.start();
|
||||
spider.addSpiderSpiderListener(mDownloadSpiderListener);
|
||||
mSpeedReminder.start();
|
||||
|
||||
} else {
|
||||
// Get error when getting spider
|
||||
info.state = DownloadInfo.STATE_FINISH;
|
||||
info.legacy = Integer.MAX_VALUE;
|
||||
// Fill Download update info
|
||||
DownloadUpdateInfo updateInfo = mUpdateInfo;
|
||||
updateInfo.gid = info.galleryBase.gid;
|
||||
updateInfo.title = EhUtils.getSuitableTitle(info.galleryBase);
|
||||
updateInfo.pages = -1;
|
||||
updateInfo.downloadedPages = 0;
|
||||
updateInfo.speed = -1;
|
||||
updateInfo.legacy = Integer.MAX_VALUE;
|
||||
// Notify
|
||||
Messenger.getInstance().notify(Constants.MESSENGER_ID_UPDATE_DOWNLOAD,
|
||||
makeMix(info.galleryBase.gid, OPS_UPDATE));
|
||||
// Listener
|
||||
if (mDownloadUpdateListener != null) {
|
||||
mDownloadUpdateListener.onFinish(updateInfo);
|
||||
}
|
||||
// Update DownloadInfo to DB
|
||||
DBUtils.updateDownloadInfo(info);
|
||||
|
||||
// Continue
|
||||
ensureDownload();
|
||||
}
|
||||
}
|
||||
|
||||
// No gallery to download
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tag null for default
|
||||
*/
|
||||
public void startDownload(GalleryBase galleryBase, @Nullable String tag) {
|
||||
try {
|
||||
if (mCurrentTask != null && mCurrentTask.galleryBase.gid == galleryBase.gid) {
|
||||
Log.v(TAG, "It is current task");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check in download list
|
||||
for (DownloadInfo info: mDownloadInfos) {
|
||||
if (info.galleryBase.gid == galleryBase.gid) {
|
||||
Log.v(TAG, "It is in download list");
|
||||
if (info.state == DownloadInfo.STATE_FINISH || info.state == DownloadInfo.STATE_NONE) {
|
||||
info.state = DownloadInfo.STATE_WAIT;
|
||||
// Add to wait list
|
||||
mWaitList.add(info);
|
||||
// Notify
|
||||
Messenger.getInstance().notify(Constants.MESSENGER_ID_UPDATE_DOWNLOAD,
|
||||
makeMix(galleryBase.gid, OPS_UPDATE));
|
||||
// Update DownloadInfo to DB
|
||||
DBUtils.updateDownloadInfo(info);
|
||||
} else {
|
||||
// No need to update
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Log.v(TAG, "It is not in download list");
|
||||
|
||||
// It is new download info
|
||||
DownloadInfo downloadInfo = new DownloadInfo();
|
||||
downloadInfo.galleryBase = galleryBase;
|
||||
downloadInfo.tag = tag;
|
||||
downloadInfo.state = DownloadInfo.STATE_WAIT;
|
||||
|
||||
List<DownloadInfo> list = getDownloadListInternal(tag, true);
|
||||
list.add(downloadInfo);
|
||||
mDownloadInfos.add(downloadInfo);
|
||||
|
||||
// Add to wait list
|
||||
mWaitList.add(downloadInfo);
|
||||
// Notify
|
||||
Messenger.getInstance().notify(Constants.MESSENGER_ID_UPDATE_DOWNLOAD,
|
||||
makeMix(galleryBase.gid, OPS_ADD));
|
||||
// Save DownloadInfo to DB
|
||||
DBUtils.addDownloadInfo(downloadInfo);
|
||||
} finally {
|
||||
ensureDownload();
|
||||
}
|
||||
}
|
||||
|
||||
public void startAllDownload() {
|
||||
for (DownloadInfo info : mDownloadInfos) {
|
||||
if (info.state == DownloadInfo.STATE_NONE ||
|
||||
(info.state == DownloadInfo.STATE_FINISH && info.legacy != 0)) {
|
||||
info.state = DownloadInfo.STATE_WAIT;
|
||||
// Add to wait list
|
||||
mWaitList.add(info);
|
||||
// Notify
|
||||
Messenger.getInstance().notify(Constants.MESSENGER_ID_UPDATE_DOWNLOAD,
|
||||
makeMix(info.galleryBase.gid, OPS_UPDATE));
|
||||
// Update DownloadInfo to DB
|
||||
DBUtils.updateDownloadInfo(info);
|
||||
}
|
||||
}
|
||||
ensureDownload();
|
||||
}
|
||||
|
||||
public void stopDownload(int gid) {
|
||||
// Check current task
|
||||
if (mCurrentTask != null && mCurrentTask.galleryBase.gid == gid) {
|
||||
// Stop current
|
||||
stopCurrentDownloadInternal();
|
||||
|
||||
// Continue
|
||||
ensureDownload();
|
||||
return;
|
||||
}
|
||||
|
||||
// Check in wait list
|
||||
if (!mWaitList.isEmpty()) {
|
||||
for (Iterator<DownloadInfo> iter = mWaitList.iterator(); iter.hasNext();) {
|
||||
DownloadInfo info = iter.next();
|
||||
if (info.galleryBase.gid == gid) {
|
||||
// Remove from wait list
|
||||
iter.remove();
|
||||
|
||||
info.state = DownloadInfo.STATE_NONE;
|
||||
|
||||
// Notify
|
||||
Messenger.getInstance().notify(Constants.MESSENGER_ID_UPDATE_DOWNLOAD,
|
||||
makeMix(gid, OPS_UPDATE));
|
||||
// Update in DB
|
||||
DBUtils.updateDownloadInfo(info);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void stopCurrentDownload() {
|
||||
stopCurrentDownloadInternal();
|
||||
ensureDownload();
|
||||
}
|
||||
|
||||
public void stopAllDownload() {
|
||||
// Stop all in wait list
|
||||
for (DownloadInfo info : mWaitList) {
|
||||
info.state = DownloadInfo.STATE_NONE;
|
||||
// Notify
|
||||
Messenger.getInstance().notify(Constants.MESSENGER_ID_UPDATE_DOWNLOAD,
|
||||
makeMix(info.galleryBase.gid, OPS_UPDATE));
|
||||
// Update in DB
|
||||
DBUtils.updateDownloadInfo(info);
|
||||
}
|
||||
mWaitList.clear();
|
||||
|
||||
// Stop current
|
||||
stopCurrentDownloadInternal();
|
||||
}
|
||||
|
||||
private void stopCurrentDownloadInternal() {
|
||||
if (mCurrentTask == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mCurrentTask.state = DownloadInfo.STATE_NONE;
|
||||
|
||||
int gid = mCurrentTask.galleryBase.gid;
|
||||
// Notify
|
||||
Messenger.getInstance().notify(Constants.MESSENGER_ID_UPDATE_DOWNLOAD,
|
||||
makeMix(gid, OPS_UPDATE));
|
||||
// Listener
|
||||
if (mDownloadUpdateListener != null) {
|
||||
mDownloadUpdateListener.onCancel(mUpdateInfo);
|
||||
}
|
||||
// Update in DB
|
||||
DBUtils.updateDownloadInfo(mCurrentTask);
|
||||
|
||||
// Release
|
||||
releaseCurrent();
|
||||
}
|
||||
|
||||
public boolean hasWaitingDownloadInfo() {
|
||||
return !mWaitList.isEmpty();
|
||||
}
|
||||
|
||||
public boolean isDownloading() {
|
||||
return mCurrentTask != null || hasWaitingDownloadInfo();
|
||||
}
|
||||
|
||||
private void releaseCurrent() {
|
||||
if (mCurrentTask != null) {
|
||||
mCurrentTask = null;
|
||||
mCurrentSpider.removeSpiderSpiderListener(mDownloadSpiderListener);
|
||||
GallerySpider.release(mCurrentSpider);
|
||||
mCurrentSpider = null;
|
||||
mDownloadSpiderListener.reset();
|
||||
mSpeedReminder.stop();
|
||||
}
|
||||
}
|
||||
|
||||
private class DownloadSpiderListener implements SpiderQueen.SpiderListener {
|
||||
|
||||
private long mReceived;
|
||||
private long mTime;
|
||||
|
||||
public void start() {
|
||||
// reset
|
||||
mReceived = 0;
|
||||
mTime = SystemClock.uptimeMillis();
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
// reset
|
||||
mReceived = 0;
|
||||
}
|
||||
|
||||
// -1 for can't get speed
|
||||
public long getSpeed() {
|
||||
if (mCurrentTask == null || mCurrentTask.total == -1) {
|
||||
return -1;
|
||||
} else {
|
||||
long time = SystemClock.uptimeMillis();
|
||||
long speed = mReceived * 1000 / (time - mTime);
|
||||
mTime = time;
|
||||
mReceived = 0;
|
||||
return speed;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTotallyFailed(Exception e) {
|
||||
onDone(Integer.MAX_VALUE); // TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPartlyFailed(Exception e) {
|
||||
onDone(Integer.MAX_VALUE); // TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDone(int legacy) {
|
||||
if (mCurrentTask == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mCurrentTask.state = DownloadInfo.STATE_FINISH;
|
||||
mCurrentTask.legacy = legacy;
|
||||
|
||||
int gid = mCurrentTask.galleryBase.gid;
|
||||
// Fill download update info
|
||||
mUpdateInfo.legacy = legacy;
|
||||
// Notify
|
||||
Messenger.getInstance().notify(Constants.MESSENGER_ID_UPDATE_DOWNLOAD,
|
||||
makeMix(gid, OPS_UPDATE));
|
||||
// Listener
|
||||
if (mDownloadUpdateListener != null) {
|
||||
mDownloadUpdateListener.onFinish(mUpdateInfo);
|
||||
}
|
||||
// Update to DB
|
||||
DBUtils.updateDownloadInfo(mCurrentTask);
|
||||
|
||||
// Release
|
||||
releaseCurrent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGetPages(int pages) {
|
||||
if (mCurrentTask == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mCurrentTask.total = pages;
|
||||
|
||||
int gid = mCurrentTask.galleryBase.gid;
|
||||
// Fill download update info
|
||||
mUpdateInfo.pages = pages;
|
||||
// Notify
|
||||
Messenger.getInstance().notify(Constants.MESSENGER_ID_UPDATE_DOWNLOAD,
|
||||
makeMix(gid, OPS_UPDATE));
|
||||
// Listener
|
||||
if (mDownloadUpdateListener != null) {
|
||||
mDownloadUpdateListener.onGetPages(mUpdateInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpiderStart(int index, long totalSize) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpiderPage(int index, long receivedSize, long singleReceivedSize) {
|
||||
mReceived += singleReceivedSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpiderSucceed(int index) {
|
||||
// TODO force request may onSpiderSucceed more than once
|
||||
if (mCurrentTask == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mCurrentTask.download++;
|
||||
|
||||
int gid = mCurrentTask.galleryBase.gid;
|
||||
// Fill download update info
|
||||
mUpdateInfo.downloadedPages++;
|
||||
// Notify
|
||||
Messenger.getInstance().notify(Constants.MESSENGER_ID_UPDATE_DOWNLOAD,
|
||||
makeMix(gid, OPS_UPDATE));
|
||||
// Listener
|
||||
if (mDownloadUpdateListener != null) {
|
||||
mDownloadUpdateListener.onDownloadPage(mUpdateInfo);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpiderFailed(int index, Exception e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSpiderCancelled(int index) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGetImage(int index, Object obj) {
|
||||
}
|
||||
}
|
||||
|
||||
class SpeedReminder implements Runnable {
|
||||
|
||||
private boolean mStop = true;
|
||||
|
||||
public void start() {
|
||||
if (mStop) {
|
||||
mStop = false;
|
||||
SimpleHandler.getInstance().post(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (!mStop) {
|
||||
mStop = true;
|
||||
SimpleHandler.getInstance().removeCallbacks(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (mCurrentTask != null && mCurrentTask.total >= 0) {
|
||||
long speed = mDownloadSpiderListener.getSpeed();
|
||||
// Fill download update info
|
||||
mUpdateInfo.speed = speed;
|
||||
mCurrentTask.speed = speed;
|
||||
|
||||
if (speed != -1) {
|
||||
// Notify
|
||||
Messenger.getInstance().notify(Constants.MESSENGER_ID_UPDATE_DOWNLOAD,
|
||||
makeMix(mCurrentTask.galleryBase.gid, OPS_UPDATE));
|
||||
// Listener
|
||||
if (mDownloadUpdateListener != null) {
|
||||
mDownloadUpdateListener.onDownload(mUpdateInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!mStop) {
|
||||
SimpleHandler.getInstance().postDelayed(this, 2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface DownloadUpdateListener {
|
||||
|
||||
void onStart(DownloadUpdateInfo info);
|
||||
|
||||
void onGetPages(DownloadUpdateInfo info);
|
||||
|
||||
// Update download pages
|
||||
void onDownloadPage(DownloadUpdateInfo info);
|
||||
|
||||
// Update speed
|
||||
void onDownload(DownloadUpdateInfo info);
|
||||
|
||||
void onFinish(DownloadUpdateInfo info);
|
||||
|
||||
void onCancel(DownloadUpdateInfo info);
|
||||
}
|
||||
|
||||
public class DownloadUpdateInfo {
|
||||
public int gid;
|
||||
public String title;
|
||||
public int pages;
|
||||
public int downloadedPages;
|
||||
public long speed;
|
||||
public int legacy;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Copyright 2015 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.service;
|
||||
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.client.data.GalleryBase;
|
||||
import com.hippo.yorozuya.FileUtils;
|
||||
|
||||
public class DownloadService extends Service implements DownloadManager.DownloadUpdateListener {
|
||||
|
||||
private static final String TAG = DownloadService.class.getSimpleName();
|
||||
|
||||
public static final String KEY_GALLERY_BASE = "gallery_base";
|
||||
public static final String KEY_TAG = "tag";
|
||||
public static final String KEY_GID = "gid";
|
||||
|
||||
public static final String ACTION_START = "com.hippo.ehviewer.service.DownloadService.START";
|
||||
public static final String ACTION_START_ALL = "com.hippo.ehviewer.service.DownloadService.START_ALL";
|
||||
public static final String ACTION_STOP = "com.hippo.ehviewer.service.DownloadService.STOP";
|
||||
public static final String ACTION_STOP_CURRENT = "com.hippo.ehviewer.service.DownloadService.STOP_CURRENT";
|
||||
public static final String ACTION_STOP_ALL = "com.hippo.ehviewer.service.DownloadService.STOP_ALL";
|
||||
public static final String ACTION_DELETE = "com.hippo.ehviewer.service.DownloadService.DELETE";
|
||||
public static final String ACTION_CLEAR = "com.hippo.ehviewer.service.DownloadService.CLEAR";
|
||||
|
||||
private static final int NOTIFY_ID_DOWNLOADING = -1;
|
||||
private static final int NOTIFY_ID_DOWNLOAD = -2;
|
||||
|
||||
private NotificationManager mNotifyManager;
|
||||
private NotificationCompat.Builder mDownloadingBuilder;
|
||||
private NotificationCompat.Builder mDownloadedBuilder;
|
||||
|
||||
private static int sSucceeCount = 0;
|
||||
private static int sFailedCount = 0;
|
||||
|
||||
private DownloadManager mDownloadManager;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
mDownloadManager = DownloadManager.getInstance();
|
||||
mDownloadManager.setDownloadUpdateListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
mDownloadManager.setDownloadUpdateListener(null);
|
||||
mDownloadManager = null;
|
||||
mNotifyManager = null;
|
||||
mDownloadingBuilder = null;
|
||||
mDownloadedBuilder = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable IBinder onBind(Intent intent) {
|
||||
throw new IllegalStateException("No bindService");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
handleIntent(intent);
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
private void handleIntent(Intent intent) {
|
||||
String action = null;
|
||||
if (intent != null) {
|
||||
action = intent.getAction();
|
||||
}
|
||||
|
||||
boolean checkStop = false;
|
||||
|
||||
if (ACTION_START.equals(action)) {
|
||||
GalleryBase gb = intent.getParcelableExtra(KEY_GALLERY_BASE);
|
||||
String tag = intent.getStringExtra(KEY_TAG);
|
||||
if (gb != null) {
|
||||
mDownloadManager.startDownload(gb, tag);
|
||||
}
|
||||
} else if (ACTION_START_ALL.equals(action)) {
|
||||
mDownloadManager.startAllDownload();
|
||||
} else if (ACTION_STOP.equals(action)) {
|
||||
int gid = intent.getIntExtra(KEY_GID, 0);
|
||||
if (gid != 0) {
|
||||
mDownloadManager.stopDownload(gid);
|
||||
}
|
||||
checkStop = true;
|
||||
} else if (ACTION_STOP_CURRENT.equals(action)) {
|
||||
mDownloadManager.stopCurrentDownload();
|
||||
checkStop = true;
|
||||
} else if (ACTION_STOP_ALL.equals(action)) {
|
||||
mDownloadManager.stopAllDownload();
|
||||
checkStop = true;
|
||||
} else if (ACTION_DELETE.equals(action)) {
|
||||
// TODO
|
||||
} else if (ACTION_CLEAR.equals(action)) {
|
||||
sSucceeCount = 0;
|
||||
sFailedCount = 0;
|
||||
} else {
|
||||
checkStop = true;
|
||||
}
|
||||
|
||||
if (checkStop) {
|
||||
if (!mDownloadManager.isDownloading()) {
|
||||
stopForeground(true);
|
||||
stopSelf();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureDownloadingNotification() {
|
||||
if (mDownloadingBuilder != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mDownloadingBuilder = new NotificationCompat.Builder(getApplicationContext());
|
||||
mDownloadingBuilder.setSmallIcon(android.R.drawable.stat_sys_download);
|
||||
mDownloadingBuilder.setOngoing(true).setAutoCancel(false);
|
||||
|
||||
// Add action
|
||||
Intent stopIntent = new Intent(this, DownloadService.class);
|
||||
stopIntent.setAction(ACTION_STOP_CURRENT);
|
||||
PendingIntent piStop = PendingIntent.getService(this, 0, stopIntent, 0);
|
||||
mDownloadingBuilder.addAction(R.drawable.ic_pause_x24, getString(R.string.stop), piStop);
|
||||
|
||||
Intent stopAllIntent = new Intent(this, DownloadService.class);
|
||||
stopAllIntent.setAction(ACTION_STOP_ALL);
|
||||
PendingIntent piStopAll = PendingIntent.getService(this, 0, stopAllIntent, 0);
|
||||
mDownloadingBuilder.addAction(R.drawable.ic_close_x24, getString(R.string.stop_all), piStopAll);
|
||||
}
|
||||
|
||||
private void ensureDownloadedNotification() {
|
||||
if (mDownloadedBuilder != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Intent clearIntent = new Intent(this, DownloadService.class);
|
||||
clearIntent.setAction(ACTION_CLEAR);
|
||||
PendingIntent piClear = PendingIntent.getService(this, 0, clearIntent, 0);
|
||||
mDownloadedBuilder = new NotificationCompat.Builder(getApplicationContext());
|
||||
mDownloadedBuilder.setSmallIcon(android.R.drawable.stat_sys_download_done)
|
||||
.setDeleteIntent(piClear).setOngoing(false).setAutoCancel(true);
|
||||
}
|
||||
|
||||
private void setPendingIntent() {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart(DownloadManager.DownloadUpdateInfo info) {
|
||||
ensureDownloadingNotification();
|
||||
setPendingIntent();
|
||||
|
||||
mDownloadingBuilder.setContentTitle(info.title)
|
||||
.setContentText(null)
|
||||
.setProgress(0, 0, true);
|
||||
startForeground(NOTIFY_ID_DOWNLOADING, mDownloadingBuilder.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGetPages(DownloadManager.DownloadUpdateInfo info) {
|
||||
ensureDownloadingNotification();
|
||||
setPendingIntent();
|
||||
|
||||
mDownloadingBuilder.setContentTitle(info.title)
|
||||
.setContentText(null)
|
||||
.setProgress(info.pages, info.downloadedPages, false);
|
||||
startForeground(NOTIFY_ID_DOWNLOADING, mDownloadingBuilder.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDownloadPage(DownloadManager.DownloadUpdateInfo info) {
|
||||
ensureDownloadingNotification();
|
||||
setPendingIntent();
|
||||
|
||||
String text = FileUtils.humanReadableByteCount(info.speed, false) + "/S";
|
||||
|
||||
mDownloadingBuilder.setContentTitle(info.title)
|
||||
.setContentText(text)
|
||||
.setProgress(info.pages, info.downloadedPages, false);
|
||||
startForeground(NOTIFY_ID_DOWNLOADING, mDownloadingBuilder.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDownload(DownloadManager.DownloadUpdateInfo info) {
|
||||
ensureDownloadingNotification();
|
||||
setPendingIntent();
|
||||
|
||||
String text = FileUtils.humanReadableByteCount(info.speed, false) + "/S";
|
||||
|
||||
mDownloadingBuilder.setContentTitle(info.title)
|
||||
.setContentText(text)
|
||||
.setProgress(info.pages, info.downloadedPages, false);
|
||||
startForeground(NOTIFY_ID_DOWNLOADING, mDownloadingBuilder.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish(DownloadManager.DownloadUpdateInfo info) {
|
||||
mNotifyManager.cancel(NOTIFY_ID_DOWNLOADING);
|
||||
|
||||
ensureDownloadedNotification();
|
||||
|
||||
if (info.legacy == 0) {
|
||||
sSucceeCount++;
|
||||
} else {
|
||||
sFailedCount++;
|
||||
}
|
||||
|
||||
if (sSucceeCount + sFailedCount == 1) {
|
||||
mDownloadedBuilder.setContentTitle(info.title);
|
||||
if (sSucceeCount == 1) {
|
||||
mDownloadedBuilder.setContentText(getResources().getString(R.string.successfully_downloaded));
|
||||
} else {
|
||||
mDownloadedBuilder.setContentText(getResources().getString(R.string.incompletely_downloaded));
|
||||
}
|
||||
} else {
|
||||
mDownloadedBuilder.setContentTitle(getResources().getString(R.string.downloading_complete));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (sSucceeCount != 0) {
|
||||
sb.append(getResources().getQuantityString(R.plurals.item_successfully_downloaded, sSucceeCount, sSucceeCount));
|
||||
}
|
||||
if (sFailedCount != 0) {
|
||||
if (sSucceeCount != 0) {
|
||||
sb.append("\n");
|
||||
}
|
||||
sb.append(getResources().getQuantityString(R.plurals.item_incompletely_downloaded, sFailedCount, sFailedCount));
|
||||
}
|
||||
mDownloadedBuilder.setContentText(sb.toString());
|
||||
}
|
||||
mNotifyManager.notify(NOTIFY_ID_DOWNLOAD, mDownloadedBuilder.build());
|
||||
|
||||
checkStopSelf();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel(DownloadManager.DownloadUpdateInfo info) {
|
||||
mNotifyManager.cancel(NOTIFY_ID_DOWNLOADING);
|
||||
checkStopSelf();
|
||||
}
|
||||
|
||||
private void checkStopSelf() {
|
||||
if (!mDownloadManager.hasWaitingDownloadInfo()) {
|
||||
stopForeground(true);
|
||||
stopSelf();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import android.widget.AdapterView;
|
||||
|
||||
import com.hippo.ehviewer.Constants;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.ui.scene.DownloadScene;
|
||||
import com.hippo.ehviewer.ui.scene.DrawerProvider;
|
||||
import com.hippo.ehviewer.ui.scene.GalleryListScene;
|
||||
import com.hippo.ehviewer.ui.scene.MainSettingsScene;
|
||||
@@ -42,6 +43,7 @@ import com.hippo.scene.Scene;
|
||||
import com.hippo.scene.SceneManager;
|
||||
import com.hippo.scene.StageActivity;
|
||||
import com.hippo.scene.StageLayout;
|
||||
import com.hippo.unifile.UniFile;
|
||||
import com.hippo.vectorold.content.VectorContext;
|
||||
import com.hippo.widget.DrawerLayout;
|
||||
import com.hippo.widget.DrawerListView;
|
||||
@@ -88,9 +90,9 @@ public final class ContentActivity extends StageActivity
|
||||
case DRAWER_LIST_FAVORITE:
|
||||
break;
|
||||
case DRAWER_LIST_DOWNLOAD:
|
||||
startScene(DownloadScene.class, null, new OffsetCurtain(OffsetCurtain.DIRECTION_BOTTOM));
|
||||
break;
|
||||
case DRAWER_LIST_SETTINGS:
|
||||
mDrawerLayout.closeDrawers();
|
||||
startScene(MainSettingsScene.class, null, new OffsetCurtain(OffsetCurtain.DIRECTION_BOTTOM));
|
||||
break;
|
||||
}
|
||||
@@ -171,6 +173,14 @@ public final class ContentActivity extends StageActivity
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_content);
|
||||
|
||||
// TODO check here ?
|
||||
UniFile uniFile = Settings.getImageDownloadLocation();
|
||||
if (uniFile != null) {
|
||||
uniFile.createFile(".nomedia");
|
||||
} else {
|
||||
// TODO
|
||||
}
|
||||
|
||||
addSceneStateListener(mSceneStateListener);
|
||||
|
||||
mResources = getResources();
|
||||
|
||||
@@ -26,7 +26,6 @@ import android.widget.TextView;
|
||||
|
||||
import com.h6ah4i.android.widget.advrecyclerview.animator.GeneralItemAnimator;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.animator.SwipeDismissItemAnimator;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.decoration.SimpleListDividerDecorator;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.ItemDraggableRange;
|
||||
import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager;
|
||||
@@ -39,6 +38,8 @@ import com.hippo.ehviewer.R;
|
||||
import com.hippo.rippleold.RippleSalon;
|
||||
import com.hippo.scene.AppbarScene;
|
||||
import com.hippo.widget.recyclerview.EasyRecyclerView;
|
||||
import com.hippo.widget.recyclerview.LinearDividerItemDecoration;
|
||||
import com.hippo.yorozuya.LayoutUtils;
|
||||
import com.hippo.yorozuya.ViewUtils;
|
||||
|
||||
import java.util.List;
|
||||
@@ -99,7 +100,12 @@ public abstract class AbsDragSortScene extends AppbarScene {
|
||||
mRecyclerView.setOnItemClickListener((EasyRecyclerView.OnItemClickListener) mAdapter);
|
||||
|
||||
// additional decorations
|
||||
mRecyclerView.addItemDecoration(new SimpleListDividerDecorator(resources.getDrawable(R.drawable.list_divider), true));
|
||||
LinearDividerItemDecoration decoration = new LinearDividerItemDecoration(
|
||||
LinearDividerItemDecoration.VERTICAL,
|
||||
resources.getColor(R.color.divider_light),
|
||||
LayoutUtils.dp2pix(getStageActivity(), 1));
|
||||
decoration.setOverlap(true);
|
||||
mRecyclerView.addItemDecoration(decoration);
|
||||
|
||||
// additional selector
|
||||
mRecyclerView.setSelector(RippleSalon.generateRippleDrawable(false));
|
||||
|
||||
@@ -16,11 +16,434 @@
|
||||
|
||||
package com.hippo.ehviewer.ui.scene;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.hippo.conaco.Conaco;
|
||||
import com.hippo.ehviewer.Constants;
|
||||
import com.hippo.ehviewer.EhApplication;
|
||||
import com.hippo.ehviewer.EhCacheKeyFactory;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.client.data.DownloadInfo;
|
||||
import com.hippo.ehviewer.client.data.GalleryBase;
|
||||
import com.hippo.ehviewer.service.DownloadManager;
|
||||
import com.hippo.ehviewer.service.DownloadService;
|
||||
import com.hippo.ehviewer.ui.ContentActivity;
|
||||
import com.hippo.ehviewer.util.EhUtils;
|
||||
import com.hippo.ehviewer.widget.LoadImageView;
|
||||
import com.hippo.ehviewer.widget.SimpleRatingView;
|
||||
import com.hippo.rippleold.RippleSalon;
|
||||
import com.hippo.scene.Scene;
|
||||
import com.hippo.widget.recyclerview.EasyRecyclerView;
|
||||
import com.hippo.yorozuya.FileUtils;
|
||||
import com.hippo.yorozuya.Messenger;
|
||||
|
||||
public class DownloadScene extends Scene {
|
||||
import java.util.List;
|
||||
|
||||
public class DownloadScene extends Scene implements DrawerProvider,
|
||||
EasyRecyclerView.OnItemClickListener, Messenger.Receiver {
|
||||
|
||||
private EasyRecyclerView mRecyclerView;
|
||||
|
||||
private DownloadAdapter mAdapter;
|
||||
|
||||
private List<DownloadInfo> mDownloadInfos;
|
||||
|
||||
private GidPositionMap mGidPositionMap;
|
||||
|
||||
private int mLastUpdateSize = -1;
|
||||
|
||||
@Override
|
||||
protected void onInit() {
|
||||
super.onInit();
|
||||
|
||||
mDownloadInfos = DownloadManager.getInstance().getDownloadList(null);
|
||||
mGidPositionMap = new GidPositionMap();
|
||||
Messenger.getInstance().register(Constants.MESSENGER_ID_UPDATE_DOWNLOAD, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDie() {
|
||||
super.onDie();
|
||||
|
||||
Messenger.getInstance().unregister(Constants.MESSENGER_ID_UPDATE_DOWNLOAD, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(boolean rebirth) {
|
||||
super.onCreate(rebirth);
|
||||
setContentView(R.layout.scene_download);
|
||||
|
||||
((ContentActivity) getStageActivity()).setDrawerListActivatedPosition(ContentActivity.DRAWER_LIST_DOWNLOAD);
|
||||
|
||||
mRecyclerView = (EasyRecyclerView) findViewById(R.id.recycler_view);
|
||||
|
||||
mAdapter = new DownloadAdapter();
|
||||
mAdapter.setHasStableIds(true);
|
||||
mRecyclerView.setAdapter(mAdapter);
|
||||
mRecyclerView.setLayoutManager(new LinearLayoutManager(getStageActivity()));
|
||||
mRecyclerView.setOnItemClickListener(this);
|
||||
mRecyclerView.setHasFixedSize(true);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
|
||||
((ContentActivity) getStageActivity()).setDrawerListActivatedPosition(ContentActivity.DRAWER_LIST_DOWNLOAD);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean showLeftDrawer() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindRightDrawer(ContentActivity activity) {
|
||||
// TODO
|
||||
activity.clearRightDrawerView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onItemClick(EasyRecyclerView parent, View view, int position, long id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
private View.OnClickListener mStartListener = new View.OnClickListener() {
|
||||
|
||||
private int getAdapterPosition(View startView) {
|
||||
EasyRecyclerView recyclerView = mRecyclerView;
|
||||
for (int i = 0, n = recyclerView.getChildCount(); i < n; i++) {
|
||||
View child = recyclerView.getChildAt(i);
|
||||
DownloadHolder holder = (DownloadHolder) recyclerView.getChildViewHolder(child);
|
||||
if (startView == holder.start) {
|
||||
return holder.getAdapterPosition();
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int position = getAdapterPosition(v);
|
||||
if (position >= 0) {
|
||||
// Add to cache
|
||||
DownloadInfo info = mDownloadInfos.get(position);
|
||||
mGidPositionMap.add(info.galleryBase.gid, position);
|
||||
|
||||
Intent intent = new Intent(getStageActivity(), DownloadService.class);
|
||||
intent.setAction(DownloadService.ACTION_START);
|
||||
intent.putExtra(DownloadService.KEY_GALLERY_BASE, info.galleryBase);
|
||||
getStageActivity().startService(intent);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private View.OnClickListener mStopListener = new View.OnClickListener() {
|
||||
|
||||
private int getAdapterPosition(View stopView) {
|
||||
EasyRecyclerView recyclerView = mRecyclerView;
|
||||
for (int i = 0, n = recyclerView.getChildCount(); i < n; i++) {
|
||||
View child = recyclerView.getChildAt(i);
|
||||
DownloadHolder holder = (DownloadHolder) recyclerView.getChildViewHolder(child);
|
||||
if (stopView == holder.stop) {
|
||||
return holder.getAdapterPosition();
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int position = getAdapterPosition(v);
|
||||
if (position >= 0) {
|
||||
// Add to cache
|
||||
DownloadInfo info = mDownloadInfos.get(position);
|
||||
mGidPositionMap.add(info.galleryBase.gid, position);
|
||||
|
||||
Intent intent = new Intent(getStageActivity(), DownloadService.class);
|
||||
intent.setAction(DownloadService.ACTION_STOP);
|
||||
intent.putExtra(DownloadService.KEY_GID, info.galleryBase.gid);
|
||||
getStageActivity().startService(intent);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private View.OnClickListener mDeleteListener = new View.OnClickListener() {
|
||||
|
||||
private int getAdapterPosition(View deleteView) {
|
||||
EasyRecyclerView recyclerView = mRecyclerView;
|
||||
for (int i = 0, n = recyclerView.getChildCount(); i < n; i++) {
|
||||
View child = recyclerView.getChildAt(i);
|
||||
DownloadHolder holder = (DownloadHolder) recyclerView.getChildViewHolder(child);
|
||||
if (deleteView == holder.delete) {
|
||||
return holder.getAdapterPosition();
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int position = getAdapterPosition(v);
|
||||
if (position >= 0) {
|
||||
// Add to cache
|
||||
DownloadInfo info = mDownloadInfos.get(position);
|
||||
mGidPositionMap.add(info.galleryBase.gid, position);
|
||||
|
||||
Intent intent = new Intent(getStageActivity(), DownloadService.class);
|
||||
intent.setAction(DownloadService.ACTION_DELETE);
|
||||
intent.putExtra(DownloadService.KEY_GID, info.galleryBase.gid);
|
||||
getStageActivity().startService(intent);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private int getPositionForGid(int gid) {
|
||||
if (mDownloadInfos == null) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int position = mGidPositionMap.getPosition(gid);
|
||||
|
||||
if (position == -1) {
|
||||
for (int i = 0, n = mDownloadInfos.size(); i < n; i++) {
|
||||
DownloadInfo info = mDownloadInfos.get(i);
|
||||
if (info.galleryBase.gid == gid) {
|
||||
position = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(int id, Object obj) {
|
||||
if (id == Constants.MESSENGER_ID_UPDATE_DOWNLOAD) {
|
||||
if (!(obj instanceof Integer)) {
|
||||
return;
|
||||
}
|
||||
if (mAdapter == null || mDownloadInfos == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int mix = (int) obj;
|
||||
int ops = DownloadManager.getOps(mix);
|
||||
int gid = DownloadManager.getGid(mix);
|
||||
|
||||
if (ops == DownloadManager.OPS_ALL_CHANGE) {
|
||||
mAdapter.notifyDataSetChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
int position = getPositionForGid(gid);
|
||||
if (position == -1 && mLastUpdateSize != mAdapter.getItemCount()) {
|
||||
// Can't get position, notifyDataSetChanged for safe
|
||||
mAdapter.notifyDataSetChanged();
|
||||
return;
|
||||
}
|
||||
|
||||
if (ops == DownloadManager.OPS_ADD) {
|
||||
mAdapter.notifyItemInserted(position);
|
||||
} else if (ops == DownloadManager.OPS_REMOVE) {
|
||||
mAdapter.notifyItemRemoved(position);
|
||||
} else if (ops == DownloadManager.OPS_UPDATE) {
|
||||
RecyclerView.ViewHolder holder = mRecyclerView.findViewHolderForAdapterPosition(position);
|
||||
if (holder != null) {
|
||||
bindHolder((DownloadHolder) holder, mDownloadInfos.get(position));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class DownloadHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
public LoadImageView thumb;
|
||||
public TextView title;
|
||||
public TextView uploader;
|
||||
public SimpleRatingView rating;
|
||||
public TextView category;
|
||||
public View start;
|
||||
public View stop;
|
||||
public View delete;
|
||||
public TextView state;
|
||||
public ProgressBar progressBar;
|
||||
public TextView percent;
|
||||
public 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);
|
||||
delete = itemView.findViewById(R.id.delete);
|
||||
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);
|
||||
|
||||
RippleSalon.addRipple(start, false);
|
||||
RippleSalon.addRipple(stop, false);
|
||||
RippleSalon.addRipple(delete, false);
|
||||
|
||||
start.setOnClickListener(mStartListener);
|
||||
stop.setOnClickListener(mStopListener);
|
||||
delete.setOnClickListener(mDeleteListener);
|
||||
}
|
||||
}
|
||||
|
||||
private void bindState(DownloadHolder holder, DownloadInfo info, String state) {
|
||||
GalleryBase galleryBase = info.galleryBase;
|
||||
EhApplication.getConaco(getStageActivity()).load(holder.thumb,
|
||||
EhCacheKeyFactory.getThumbKey(galleryBase.gid), galleryBase.thumb);
|
||||
holder.title.setText(EhUtils.getSuitableTitle(galleryBase));
|
||||
holder.uploader.setVisibility(View.VISIBLE);
|
||||
holder.rating.setVisibility(View.VISIBLE);
|
||||
holder.category.setVisibility(View.VISIBLE);
|
||||
holder.state.setVisibility(View.VISIBLE);
|
||||
holder.uploader.setText(galleryBase.uploader);
|
||||
holder.rating.setRating(galleryBase.rating);
|
||||
TextView category = holder.category;
|
||||
String newCategoryText = EhUtils.getCategory(galleryBase.category);
|
||||
if (!newCategoryText.equals(category.getText())) {
|
||||
category.setText(newCategoryText);
|
||||
category.setBackgroundColor(EhUtils.getCategoryColor(galleryBase.category));
|
||||
}
|
||||
holder.state.setText(state);
|
||||
holder.progressBar.setVisibility(View.INVISIBLE);
|
||||
holder.percent.setVisibility(View.INVISIBLE);
|
||||
holder.speed.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
|
||||
private void bindProgress(DownloadHolder holder, DownloadInfo info) {
|
||||
GalleryBase galleryBase = info.galleryBase;
|
||||
EhApplication.getConaco(getStageActivity()).load(holder.thumb,
|
||||
EhCacheKeyFactory.getThumbKey(info.galleryBase.gid), galleryBase.thumb);
|
||||
holder.title.setText(EhUtils.getSuitableTitle(galleryBase));
|
||||
holder.uploader.setVisibility(View.INVISIBLE);
|
||||
holder.rating.setVisibility(View.INVISIBLE);
|
||||
holder.category.setVisibility(View.INVISIBLE);
|
||||
holder.state.setVisibility(View.INVISIBLE);
|
||||
holder.progressBar.setVisibility(View.VISIBLE);
|
||||
|
||||
if (info.total <= 0 || info.speed < 0) {
|
||||
holder.progressBar.setIndeterminate(true);
|
||||
holder.percent.setVisibility(View.INVISIBLE);
|
||||
holder.speed.setVisibility(View.INVISIBLE);
|
||||
} else {
|
||||
holder.progressBar.setIndeterminate(false);
|
||||
holder.progressBar.setMax(info.total);
|
||||
holder.progressBar.setProgress(info.download);
|
||||
holder.percent.setVisibility(View.VISIBLE);
|
||||
holder.speed.setVisibility(View.VISIBLE);
|
||||
holder.percent.setText(info.download + "/" + info.total);
|
||||
holder.speed.setText(FileUtils.humanReadableByteCount(info.speed, false) + "/S");
|
||||
}
|
||||
}
|
||||
|
||||
private void bindHolder(DownloadHolder holder, DownloadInfo info) {
|
||||
switch (info.state) {
|
||||
case DownloadInfo.STATE_NONE:
|
||||
default:
|
||||
bindState(holder, info, getContext().getResources().getString(R.string.download_state_none));
|
||||
break;
|
||||
case DownloadInfo.STATE_WAIT:
|
||||
bindState(holder, info, getContext().getResources().getString(R.string.download_state_wait));
|
||||
break;
|
||||
case DownloadInfo.STATE_DOWNLOAD:
|
||||
bindProgress(holder, info);
|
||||
break;
|
||||
case DownloadInfo.STATE_FINISH:
|
||||
if (info.legacy == 0) {
|
||||
bindState(holder, info, getContext().getResources().getString(R.string.download_state_done));
|
||||
} else if (info.legacy > 0 && info.legacy != Integer.MAX_VALUE) {
|
||||
bindState(holder, info, getContext().getResources().getString(R.string.download_state_incomplete, info.legacy));
|
||||
} else {
|
||||
bindState(holder, info, getContext().getResources().getString(R.string.download_state_incomplete));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private class DownloadAdapter extends RecyclerView.Adapter<DownloadHolder> {
|
||||
|
||||
Conaco mConaco;
|
||||
|
||||
public DownloadAdapter() {
|
||||
mConaco = EhApplication.getConaco(getStageActivity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DownloadHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
return new DownloadHolder(getStageActivity().getLayoutInflater().inflate(R.layout.item_download, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(DownloadHolder holder, int position) {
|
||||
DownloadInfo info = mDownloadInfos.get(position);
|
||||
bindHolder(holder, info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return mDownloadInfos.get(position).galleryBase.gid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
mLastUpdateSize = mDownloadInfos != null ? mDownloadInfos.size() : 0;
|
||||
return mLastUpdateSize;
|
||||
}
|
||||
}
|
||||
|
||||
private static class GidPositionMap {
|
||||
|
||||
private static final int SIZE = 12;
|
||||
|
||||
private int[] mGids = new int[SIZE];
|
||||
private int[] mPosition = new int[SIZE];
|
||||
|
||||
private int mStartIndex = 0;
|
||||
private int mSize = 0;
|
||||
|
||||
public void add(int gid, int position) {
|
||||
int index = (mStartIndex + mSize) % SIZE;
|
||||
mGids[index] = gid;
|
||||
mPosition[index] = position;
|
||||
|
||||
// Update start index size and
|
||||
mSize++;
|
||||
if (mSize > SIZE) {
|
||||
mStartIndex = (mStartIndex + mSize) % SIZE;
|
||||
mSize = Math.min(mSize, SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
mSize = 0;
|
||||
}
|
||||
|
||||
public int getPosition(int gid) {
|
||||
for (int i = 0; i < mSize; i++) {
|
||||
int index = (mStartIndex + i) % SIZE;
|
||||
if (gid == mGids[index]) {
|
||||
return mPosition[index];
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,7 @@ import com.hippo.ehviewer.client.data.GalleryBase;
|
||||
import com.hippo.ehviewer.client.data.GalleryDetail;
|
||||
import com.hippo.ehviewer.client.data.PreviewSet;
|
||||
import com.hippo.ehviewer.client.data.TagGroup;
|
||||
import com.hippo.ehviewer.service.DownloadService;
|
||||
import com.hippo.ehviewer.ui.ContentActivity;
|
||||
import com.hippo.ehviewer.ui.GalleryActivity;
|
||||
import com.hippo.ehviewer.util.EhUtils;
|
||||
@@ -558,7 +559,10 @@ public class GalleryDetailScene extends Scene implements View.OnClickListener,
|
||||
requestGalleryDetail(mGid, mToken);
|
||||
}
|
||||
} else if (mDownload == v) {
|
||||
// TODO
|
||||
Intent intent = new Intent(getStageActivity(), DownloadService.class);
|
||||
intent.setAction(DownloadService.ACTION_START);
|
||||
intent.putExtra(DownloadService.KEY_GALLERY_BASE, mGalleryDetail);
|
||||
getStageActivity().startService(intent);
|
||||
} else if (mRead == v) {
|
||||
GalleryBase galleryBase = mGalleryDetail;
|
||||
if (galleryBase == null) {
|
||||
|
||||
@@ -75,7 +75,9 @@ import com.hippo.util.AnimationUtils;
|
||||
import com.hippo.widget.FabLayout;
|
||||
import com.hippo.widget.FloatingActionButton;
|
||||
import com.hippo.widget.recyclerview.EasyRecyclerView;
|
||||
import com.hippo.widget.recyclerview.LinearDividerItemDecoration;
|
||||
import com.hippo.yorozuya.AssertUtils;
|
||||
import com.hippo.yorozuya.LayoutUtils;
|
||||
import com.hippo.yorozuya.MathUtils;
|
||||
import com.hippo.yorozuya.Messenger;
|
||||
import com.hippo.yorozuya.SimpleHandler;
|
||||
@@ -303,27 +305,6 @@ public final class GalleryListScene extends Scene implements ListSearchBar.Helpe
|
||||
mSearchBarOriginalTop = lp.topMargin;
|
||||
mSearchBarOriginalBottom = lp.topMargin + mSearchBar.getMeasuredHeight();
|
||||
|
||||
|
||||
/*
|
||||
mSearchBar.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
ViewUtils.removeOnGlobalLayoutListener(mSearchBar.getViewTreeObserver(), this);
|
||||
mSearchBarOriginalTop = mSearchBar.getTop();
|
||||
mSearchBarOriginalBottom = mSearchBar.getBottom();
|
||||
int fitPaddingTop = mSearchBar.getHeight() + mResources.getDimensionPixelOffset(R.dimen.search_bar_padding_vertical);
|
||||
mContentLayout.setFitPaddingTop(fitPaddingTop);
|
||||
mSearchLayout.setFitPaddingTop(fitPaddingTop);
|
||||
|
||||
Log.d("TAG", "fitPaddingTop = " + fitPaddingTop);
|
||||
Log.d("TAG", "mSearchBarOriginalTop = " + mSearchBarOriginalTop);
|
||||
Log.d("TAG", "mSearchBarOriginalBottom = " + mSearchBarOriginalBottom);
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
|
||||
|
||||
// Content Layout
|
||||
// onRebirth may create new GalleryListHelper
|
||||
if (mGalleryListHelper == null) {
|
||||
@@ -365,6 +346,12 @@ public final class GalleryListScene extends Scene implements ListSearchBar.Helpe
|
||||
mQuickSearchView.setOnItemClickListener(new QuickSearchClickListener());
|
||||
mQuickSearchView.hasFixedSize();
|
||||
mQuickSearchView.setClipToPadding(false);
|
||||
LinearDividerItemDecoration decoration = new LinearDividerItemDecoration(
|
||||
LinearDividerItemDecoration.VERTICAL,
|
||||
mResources.getColor(R.color.divider_light),
|
||||
LayoutUtils.dp2pix(getStageActivity(), 1));
|
||||
decoration.setOverlap(true);
|
||||
mQuickSearchView.addItemDecoration(decoration);
|
||||
|
||||
// When scene start
|
||||
if (!rebirth) {
|
||||
@@ -1279,6 +1266,9 @@ public final class GalleryListScene extends Scene implements ListSearchBar.Helpe
|
||||
showSearchBar(true);
|
||||
mGalleryListHelper.refresh();
|
||||
((ContentActivity) getStageActivity()).closeDrawers();
|
||||
|
||||
mDrawerListActivatedPosition = ContentActivity.DRAWER_LIST_NONE;
|
||||
mActivity.setDrawerListActivatedPosition(ContentActivity.DRAWER_LIST_NONE);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ public class ModifyQuickSearchScene extends AppbarScene implements SearchLayout.
|
||||
// New name
|
||||
mQuickSearch.name = mNewName;
|
||||
}
|
||||
DBUtils.modifyQuickSearch(mQuickSearch);
|
||||
DBUtils.updateQuickSearch(mQuickSearch);
|
||||
|
||||
Messenger.getInstance().notify(Constants.MESSENGER_ID_UPDATE_QUICK_SEARCH, null);
|
||||
if (newName) {
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.content.Context;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.hippo.ehviewer.client.data.DownloadInfo;
|
||||
import com.hippo.ehviewer.client.data.GalleryBase;
|
||||
import com.hippo.ehviewer.client.data.ListUrlBuilder;
|
||||
import com.hippo.ehviewer.client.data.QuickSearch;
|
||||
@@ -27,6 +28,10 @@ import com.hippo.ehviewer.dao.DaoMaster;
|
||||
import com.hippo.ehviewer.dao.DaoSession;
|
||||
import com.hippo.ehviewer.dao.DirnameObj;
|
||||
import com.hippo.ehviewer.dao.DirnameObjDao;
|
||||
import com.hippo.ehviewer.dao.DownloadInfoObj;
|
||||
import com.hippo.ehviewer.dao.DownloadInfoObjDao;
|
||||
import com.hippo.ehviewer.dao.DownloadTagObj;
|
||||
import com.hippo.ehviewer.dao.DownloadTagObjDao;
|
||||
import com.hippo.ehviewer.dao.GalleryBaseObj;
|
||||
import com.hippo.ehviewer.dao.GalleryBaseObjDao;
|
||||
import com.hippo.ehviewer.dao.QuickSearchObj;
|
||||
@@ -84,6 +89,26 @@ public class DBUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static GalleryBase getGalleryBase(int gid) {
|
||||
GalleryBaseObjDao dao = sDaoSession.getGalleryBaseObjDao();
|
||||
GalleryBaseObj obj = dao.load((long) gid);
|
||||
if (obj != null) {
|
||||
GalleryBase galleryBase = new GalleryBase();
|
||||
galleryBase.gid = (int) (long) obj.getGid();
|
||||
galleryBase.token = obj.getToken();
|
||||
galleryBase.title = obj.getTitle();
|
||||
galleryBase.titleJpn = obj.getTitleJpn();
|
||||
galleryBase.thumb = obj.getThumb();
|
||||
galleryBase.category = obj.getCategory();
|
||||
galleryBase.posted = obj.getPosted();
|
||||
galleryBase.uploader = obj.getUploader();
|
||||
galleryBase.rating = obj.getRating();
|
||||
return galleryBase;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getDirname(int gid) {
|
||||
DirnameObjDao dirnameObjDao = sDaoSession.getDirnameObjDao();
|
||||
DirnameObj dirnameObj = dirnameObjDao.load((long) gid);
|
||||
@@ -147,7 +172,7 @@ public class DBUtils {
|
||||
dao.update(to);
|
||||
}
|
||||
|
||||
public static void modifyQuickSearch(QuickSearch quickSearch) {
|
||||
public static void updateQuickSearch(QuickSearch quickSearch) {
|
||||
QuickSearchObjDao dao = sDaoSession.getQuickSearchObjDao();
|
||||
QuickSearchObj obj = dao.load(quickSearch.id);
|
||||
obj.setName(quickSearch.name);
|
||||
@@ -172,4 +197,51 @@ public class DBUtils {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static List<DownloadInfo> getAllDownloadInfo() {
|
||||
DownloadInfoObjDao dao = sDaoSession.getDownloadInfoObjDao();
|
||||
List<DownloadInfoObj> list = dao.queryBuilder().orderAsc(DownloadInfoObjDao.Properties.Time).list();
|
||||
List<DownloadInfo> result = new ArrayList<>(list.size());
|
||||
for (DownloadInfoObj obj : list) {
|
||||
result.add(DownloadInfo.fromDownloadInfoObj(obj));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void addDownloadInfo(DownloadInfo downloadInfo) {
|
||||
DownloadInfoObj obj = new DownloadInfoObj();
|
||||
obj.setGid((long) downloadInfo.galleryBase.gid);
|
||||
obj.setTag(downloadInfo.tag);
|
||||
obj.setState(downloadInfo.state);
|
||||
obj.setLegacy(downloadInfo.legacy);
|
||||
obj.setTime(System.currentTimeMillis());
|
||||
sDaoSession.getDownloadInfoObjDao().insert(obj);
|
||||
addGalleryBase(downloadInfo.galleryBase);
|
||||
}
|
||||
|
||||
public static void updateDownloadInfo(DownloadInfo downloadInfo) {
|
||||
DownloadInfoObjDao dao = sDaoSession.getDownloadInfoObjDao();
|
||||
DownloadInfoObj obj = dao.load((long) downloadInfo.galleryBase.gid);
|
||||
obj.setState(downloadInfo.state);
|
||||
obj.setLegacy(downloadInfo.legacy);
|
||||
dao.update(obj);
|
||||
}
|
||||
|
||||
public static List<String> getAllDownloadTag() {
|
||||
DownloadTagObjDao dao = sDaoSession.getDownloadTagObjDao();
|
||||
List<DownloadTagObj> list = dao.queryBuilder().list();
|
||||
List<String> result = new ArrayList<>(list.size());
|
||||
for (DownloadTagObj obj : list) {
|
||||
result.add(obj.getTag());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void addDownloadTag(String tag) {
|
||||
DownloadTagObj obj = new DownloadTagObj();
|
||||
obj.setTag(tag);
|
||||
sDaoSession.getDownloadTagObjDao().insert(obj);
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,7 @@ public class DownloadClient {
|
||||
out.write(data, 0, bytesRead);
|
||||
receivedSize += bytesRead;
|
||||
if (listener != null) {
|
||||
listener.onDonwlad(receivedSize);
|
||||
listener.onDonwlad(receivedSize, bytesRead);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ public class DownloadClient {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDonwlad(long receivedSize) {
|
||||
public void onDonwlad(long receivedSize, long singleReceivedSize) {
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -227,7 +227,7 @@ public class DownloadClient {
|
||||
|
||||
void onConnect(long totalSize);
|
||||
|
||||
void onDonwlad(long receivedSize);
|
||||
void onDonwlad(long receivedSize, long singleReceivedSize);
|
||||
|
||||
void onFailed(Exception e);
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ public class DownloadRequest {
|
||||
|
||||
public void cancel() {
|
||||
if (mHttpRequest != null) {
|
||||
mHttpRequest.disconnect();
|
||||
mHttpRequest.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@@ -29,6 +30,7 @@ import android.view.ViewParent;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.hippo.ehviewer.client.data.DownloadInfo;
|
||||
import com.hippo.yorozuya.AssertUtils;
|
||||
|
||||
/**
|
||||
@@ -100,6 +102,13 @@ public abstract class Scene {
|
||||
return stageActivity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Aliases of {@link #getStageActivity()}
|
||||
*/
|
||||
public Context getContext() {
|
||||
return getStageActivity();
|
||||
}
|
||||
|
||||
public int getLaunchMode() {
|
||||
return LAUNCH_MODE_STANDARD;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
|
||||
// Add overlap
|
||||
/**
|
||||
* Only work for {@link android.support.v7.widget.LinearLayoutManager}.<br>
|
||||
* Show divider between item, just like
|
||||
@@ -44,6 +45,8 @@ public class LinearDividerItemDecoration extends RecyclerView.ItemDecoration {
|
||||
private int mPaddingStart = 0;
|
||||
private int mPaddingEnd = 0;
|
||||
|
||||
private boolean mOverlap = false;
|
||||
|
||||
private ShowDividerHelper mShowDividerHelper;
|
||||
|
||||
public LinearDividerItemDecoration(int orientation, int color, int thickness) {
|
||||
@@ -95,9 +98,23 @@ public class LinearDividerItemDecoration extends RecyclerView.ItemDecoration {
|
||||
mPaddingEnd = paddingEnd;
|
||||
}
|
||||
|
||||
public void setOverlap(boolean overlap) {
|
||||
mOverlap = overlap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getItemOffsets(Rect outRect, View view,
|
||||
RecyclerView parent, RecyclerView.State state) {
|
||||
if (parent.getAdapter() == null) {
|
||||
outRect.set(0, 0, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mOverlap) {
|
||||
outRect.set(0, 0, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
final int position = parent.getChildLayoutPosition(view);
|
||||
final int itemCount = parent.getAdapter().getItemCount();
|
||||
|
||||
@@ -147,6 +164,7 @@ public class LinearDividerItemDecoration extends RecyclerView.ItemDecoration {
|
||||
}
|
||||
|
||||
int itemCount = adapter.getItemCount();
|
||||
boolean overlap = mOverlap;
|
||||
|
||||
if (mOrientation == VERTICAL) {
|
||||
final boolean isRtl = ViewCompat.getLayoutDirection(parent) == ViewCompat.LAYOUT_DIRECTION_RTL;
|
||||
@@ -176,7 +194,10 @@ public class LinearDividerItemDecoration extends RecyclerView.ItemDecoration {
|
||||
show = position != itemCount - 1 || mShowLastDivider;
|
||||
}
|
||||
if (show) {
|
||||
final int top = child.getBottom() + lp.bottomMargin;
|
||||
int top = child.getBottom() + lp.bottomMargin;
|
||||
if (overlap) {
|
||||
top -= mThickness;
|
||||
}
|
||||
final int bottom = top + mThickness;
|
||||
mRect.set(left, top, right, bottom);
|
||||
c.drawRect(mRect, mPaint);
|
||||
@@ -189,7 +210,10 @@ public class LinearDividerItemDecoration extends RecyclerView.ItemDecoration {
|
||||
show = mShowFirstDivider;
|
||||
}
|
||||
if (show) {
|
||||
final int bottom = child.getTop() + lp.topMargin;
|
||||
int bottom = child.getTop() + lp.topMargin;
|
||||
if (overlap) {
|
||||
bottom += mThickness;
|
||||
}
|
||||
final int top = bottom - mThickness;
|
||||
mRect.set(left, top, right, bottom);
|
||||
c.drawRect(mRect, mPaint);
|
||||
@@ -213,7 +237,10 @@ public class LinearDividerItemDecoration extends RecyclerView.ItemDecoration {
|
||||
show = position != itemCount - 1 || mShowLastDivider;
|
||||
}
|
||||
if (show) {
|
||||
final int left = child.getRight() + lp.rightMargin;
|
||||
int left = child.getRight() + lp.rightMargin;
|
||||
if (overlap) {
|
||||
left -= mThickness;
|
||||
}
|
||||
final int right = left + mThickness;
|
||||
mRect.set(left, top, right, bottom);
|
||||
c.drawRect(mRect, mPaint);
|
||||
@@ -226,7 +253,10 @@ public class LinearDividerItemDecoration extends RecyclerView.ItemDecoration {
|
||||
show = mShowFirstDivider;
|
||||
}
|
||||
if (show) {
|
||||
final int right = child.getLeft() + lp.leftMargin;
|
||||
int right = child.getLeft() + lp.leftMargin;
|
||||
if (overlap) {
|
||||
right += mThickness;
|
||||
}
|
||||
final int left = right - mThickness;
|
||||
mRect.set(left, top, right, bottom);
|
||||
c.drawRect(mRect, mPaint);
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2015 Hippo Seven
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:auto="http://schemas.android.com/apk/res-auto"
|
||||
tools:targetApi="21"
|
||||
|
||||
auto:width="24dp"
|
||||
auto:height="24dp"
|
||||
auto:viewportWidth="24"
|
||||
auto:viewportHeight="24"
|
||||
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
auto:pathData="@string/pd_close"
|
||||
auto:fillColor="@color/primary_drawable_light"
|
||||
|
||||
android:pathData="@string/pd_close"
|
||||
android:fillColor="@color/primary_drawable_light"/>
|
||||
|
||||
</vector>
|
||||
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2015 Hippo Seven
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:auto="http://schemas.android.com/apk/res-auto"
|
||||
tools:targetApi="21"
|
||||
|
||||
auto:width="24dp"
|
||||
auto:height="24dp"
|
||||
auto:viewportWidth="24"
|
||||
auto:viewportHeight="24"
|
||||
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
auto:pathData="@string/pd_pause"
|
||||
auto:fillColor="@color/primary_drawable_light"
|
||||
|
||||
android:pathData="@string/pd_pause"
|
||||
android:fillColor="@color/primary_drawable_light"/>
|
||||
|
||||
</vector>
|
||||
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2015 Hippo Seven
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
xmlns:auto="http://schemas.android.com/apk/res-auto"
|
||||
tools:targetApi="21"
|
||||
|
||||
auto:width="24dp"
|
||||
auto:height="24dp"
|
||||
auto:viewportWidth="24"
|
||||
auto:viewportHeight="24"
|
||||
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
auto:pathData="@string/pd_play"
|
||||
auto:fillColor="@color/primary_drawable_light"
|
||||
|
||||
android:pathData="@string/pd_play"
|
||||
android:fillColor="@color/primary_drawable_light"/>
|
||||
|
||||
</vector>
|
||||
@@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2015 Haruki Hasegawa
|
||||
|
||||
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.
|
||||
-->
|
||||
<shape
|
||||
android:shape="rectangle"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<size android:height="1dp"/>
|
||||
<solid android:color="#20000000"/>
|
||||
</shape>
|
||||
@@ -0,0 +1,151 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2015 Hippo Seven
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<com.hippo.cardsalon.CardView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:auto="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
auto:cardElevation="4dp"
|
||||
auto:forceNoElevation="true">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.hippo.ehviewer.widget.LoadImageView
|
||||
android:id="@+id/thumb"
|
||||
android:layout_width="@dimen/list_thumb_width"
|
||||
android:layout_height="@dimen/list_thumb_height"
|
||||
auto:retryType="click"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
style="@style/CardTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginRight="8dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_toRightOf="@id/thumb"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/uploader"
|
||||
style="@style/CardMessage"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignLeft="@id/title"
|
||||
android:layout_below="@id/title"
|
||||
android:layout_marginTop="2dp"/>
|
||||
|
||||
<com.hippo.ehviewer.widget.SimpleRatingView
|
||||
android:id="@+id/rating"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignLeft="@id/title"
|
||||
android:layout_below="@id/uploader"
|
||||
android:layout_marginTop="2dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/category"
|
||||
style="@style/CardMessage"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignLeft="@id/title"
|
||||
android:layout_alignBottom="@id/thumb"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:paddingBottom="2dp"
|
||||
android:paddingLeft="8dp"
|
||||
android:paddingRight="8dp"
|
||||
android:paddingTop="2dp"
|
||||
android:textColor="@android:color/white"
|
||||
android:textAllCaps="true"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/actions"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignBottom="@+id/thumb"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginRight="8dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.hippo.widget.SimpleImageView
|
||||
android:id="@+id/start"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:padding="8dp"
|
||||
android:src="@drawable/ic_play_x24"/>
|
||||
|
||||
<com.hippo.widget.SimpleImageView
|
||||
android:id="@+id/stop"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginRight="8dp"
|
||||
android:padding="8dp"
|
||||
android:src="@drawable/ic_pause_x24"/>
|
||||
|
||||
<com.hippo.widget.SimpleImageView
|
||||
android:id="@+id/delete"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:padding="8dp"
|
||||
android:src="@drawable/ic_close_x24"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/state"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_above="@id/actions"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginRight="16dp"
|
||||
android:textColor="?attr/colorAccent"/>
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress_bar"
|
||||
style="?android:attr/progressBarStyleHorizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignLeft="@id/title"
|
||||
android:layout_marginRight="8dp"
|
||||
android:layout_above="@id/actions"
|
||||
android:indeterminate="false"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/percent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_above="@id/progress_bar"
|
||||
android:layout_alignLeft="@id/title"
|
||||
android:textSize="@dimen/text_super_small"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/speed"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_above="@id/progress_bar"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_marginRight="8dp"
|
||||
android:textSize="@dimen/text_super_small"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</com.hippo.cardsalon.CardView>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2015 Hippo Seven
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:auto="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.hippo.widget.recyclerview.MonoRecyclerView
|
||||
android:id="@+id/recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:clipChildren="false"
|
||||
auto:space="@dimen/search_layout_space"
|
||||
auto:spaceLeft="@dimen/search_layout_space_horizontal"
|
||||
auto:spaceRight="@dimen/search_layout_space_horizontal"/>
|
||||
|
||||
</FrameLayout>
|
||||
@@ -48,6 +48,9 @@
|
||||
<string name="pd_url" translatable="false">M11.6,7v7.1c0,1-0.3,1.8-0.9,2.4c-0.6,0.6-1.5,1-2.5,1.1l-0.4,0c-1.1,0-2.1-0.3-2.7-0.9c-0.7-0.6-1-1.5-1-2.6V7h1.4v7.1c0,0.8,0.2,1.3,0.6,1.8c0.4,0.4,1,0.6,1.8,0.6c0.8,0,1.4-0.2,1.8-0.6c0.4-0.4,0.6-1,0.6-1.8V7H11.6M17.3,10.9c-0.2,0-0.4-0.1-0.7-0.1c-0.9,0-1.5,0.4-1.8,1.1v5.5h-1.3V9.7h1.3l0,0.9c0.4-0.7,1.1-1,1.9-1c0.3,0,0.5,0,0.6,0.1V10.9M20,17.5h-1.3V6.4H20V17.5z</string>
|
||||
<string name="pd_book_open" translatable="false">M11,19V9A2,2 0 0,0 9,7H5V17H9A2,2 0 0,1 11,19M13,9V19A2,2 0 0,1 15,17H19V7H15A2,2 0 0,0 13,9M21,19H15A2,2 0 0,0 13,21H11A2,2 0 0,0 9,19H3V5H9A2,2 0 0,1 11,7H13A2,2 0 0,1 15,5H21V19Z</string>
|
||||
<string name="pd_delete" translatable="false">M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z</string>
|
||||
<string name="pd_play" translatable="false">M8,5.14V19.14L19,12.14L8,5.14Z</string>
|
||||
<string name="pd_pause" translatable="false">M14,19.14H18V5.14H14M6,19.14H10V5.14H6V19.14Z</string>
|
||||
<string name="pd_close" translatable="false">M19,7.1L16.9 5 12 9.9 7.1 5 5 7.1 9.9 12 5 16.9 7.1 19 12 14.1 16.9 19 19 16.9 14.1 12 z</string>
|
||||
|
||||
<string name="pd_slider_bubble" translatable="false">M13,0c7.2,0,13,5.9,13,13.2c0,3.7-2,7.6-7.3,12.9L13,32l-5.8-5.8C2,20.8,0,16.9,0,13.3C0,5.9,5.8,0,13,0z</string>
|
||||
|
||||
|
||||
@@ -216,6 +216,27 @@
|
||||
<string name="line_dean">\"What ?\"</string>
|
||||
<string name="line_sam">\"I lose my panda …\"</string>
|
||||
|
||||
<!-- Download Server -->
|
||||
<string name="download_server">Download server</string>
|
||||
<string name="stop">Stop</string>
|
||||
<string name="stop_all">Stop all</string>
|
||||
<string name="successfully_downloaded">Successfully downloaded</string>
|
||||
<string name="incompletely_downloaded">Incompletely downloaded</string>
|
||||
<string name="downloading_complete">Downloading complete</string>
|
||||
<plurals name="item_successfully_downloaded">
|
||||
<item quantity="one">One item successfully downloaded</item>
|
||||
<item quantity="other">%d items successfully downloaded</item>
|
||||
</plurals>
|
||||
<plurals name="item_incompletely_downloaded">
|
||||
<item quantity="one">One item incompletely downloaded</item>
|
||||
<item quantity="other">%d items incompletely downloaded</item>
|
||||
</plurals>
|
||||
<string name="download_state_none">IDLE</string>
|
||||
<string name="download_state_wait">Waiting</string>
|
||||
<string name="download_state_finish">Done</string>
|
||||
<string name="download_state_done">Done</string>
|
||||
<string name="download_state_incomplete">Incomplete</string>
|
||||
|
||||
<string name="keyword">Keyword</string>
|
||||
<string name="search">Search</string>
|
||||
<string name="retry">Retry</string>
|
||||
|
||||
@@ -97,6 +97,7 @@
|
||||
<!-- Card -->
|
||||
<style name="TextAppearance.CardTitle">
|
||||
<item name="@android:textSize">@dimen/text_little_small</item>
|
||||
<item name="@android:textColor">@color/primary_text_light</item>
|
||||
</style>
|
||||
|
||||
<style name="CardTitle">
|
||||
@@ -106,6 +107,10 @@
|
||||
<item name="@android:lineSpacingExtra">0sp</item>
|
||||
</style>
|
||||
|
||||
<style name="CardTitle.Download">
|
||||
<item name="@android:maxLines">1</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.CardMessage">
|
||||
<item name="@android:textColor">@color/secondary_text_light</item>
|
||||
</style>
|
||||
|
||||
+1
-1
Submodule beerbelly updated: f2b6766de5...2b2da15514.
+1
-1
Submodule cardsalon updated: 97d1d30822...18444fc75e.
+1
-1
Submodule conaco updated: 6bd8937391...5c1fea7a11.
@@ -37,6 +37,7 @@ public class EhDaoGenerator {
|
||||
addGalleryBase(schema);
|
||||
addQuickSearch(schema);
|
||||
addDownloadInfo(schema);
|
||||
addDownloadTag(schema);
|
||||
addDirname(schema);
|
||||
addReadInfo(schema);
|
||||
new DaoGenerator().generateAll(schema, OUT_DIR);
|
||||
@@ -71,12 +72,20 @@ public class EhDaoGenerator {
|
||||
}
|
||||
|
||||
public static void addDownloadInfo(Schema schema) {
|
||||
Entity downloadInfo = schema.addEntity("DownloadInfoObj");
|
||||
downloadInfo.setTableName("DOWNLOAD_INFO");
|
||||
downloadInfo.addLongProperty("gid").primaryKey();
|
||||
downloadInfo.addIntProperty("state");
|
||||
downloadInfo.addIntProperty("legacy");
|
||||
downloadInfo.addLongProperty("time");
|
||||
Entity entity = schema.addEntity("DownloadInfoObj");
|
||||
entity.setTableName("DOWNLOAD_INFO");
|
||||
entity.addLongProperty("gid").primaryKey();
|
||||
entity.addStringProperty("tag");
|
||||
entity.addIntProperty("state");
|
||||
entity.addIntProperty("legacy");
|
||||
entity.addLongProperty("time");
|
||||
}
|
||||
|
||||
public static void addDownloadTag(Schema schema) {
|
||||
Entity entity = schema.addEntity("DownloadTagObj");
|
||||
entity.setTableName("DOWNLOAD_TAG");
|
||||
entity.addIdProperty();
|
||||
entity.addStringProperty("tag");
|
||||
}
|
||||
|
||||
public static void addDirname(Schema schema) {
|
||||
|
||||
+1
-1
Submodule hotspot updated: 04129925be...2783f8b9c0.
+1
-1
Submodule httpclient updated: c4288ea904...005aad8517.
+1
-1
Submodule rippleold updated: f6aeb8cb1c...53a806d99d.
+1
-1
Submodule unifile updated: f068bc951b...60e3145f85.
+1
-1
Submodule vectorold updated: 34d314b584...b07793e9c5.
+1
-1
Submodule yorozuya updated: cd4d1b981c...805f0c5f7a.
Reference in new issue
Block a user