Improve download
No files matched your search
@@ -10,8 +10,8 @@ android {
|
||||
applicationId "com.hippo.ehviewer"
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 23
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
versionCode 48
|
||||
versionName "0.9.0"
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
@@ -53,8 +53,8 @@ android {
|
||||
}
|
||||
|
||||
clean {
|
||||
//delete file('src/main/obj').absolutePath
|
||||
//delete file('src/main/libs').absolutePath
|
||||
delete file('src/main/obj').absolutePath
|
||||
delete file('src/main/libs').absolutePath
|
||||
}
|
||||
|
||||
dependencies {
|
||||
|
||||
@@ -67,6 +67,11 @@
|
||||
android:configChanges="screenSize|uiMode"
|
||||
android:theme="@style/AppTheme"/>
|
||||
|
||||
<service
|
||||
android:name="com.hippo.ehviewer.download.DownloadService"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/download"/>
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
@@ -22,6 +22,7 @@ import android.os.Debug;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseBooleanArray;
|
||||
|
||||
import com.hippo.beerbelly.LruCacheEx;
|
||||
import com.hippo.conaco.Conaco;
|
||||
@@ -30,6 +31,8 @@ import com.hippo.ehviewer.client.EhClient;
|
||||
import com.hippo.ehviewer.client.EhCookieStore;
|
||||
import com.hippo.ehviewer.client.data.GalleryDetail;
|
||||
import com.hippo.ehviewer.client.data.LargePreviewSet;
|
||||
import com.hippo.ehviewer.download.DownloadManager;
|
||||
import com.hippo.ehviewer.download.DownloadService;
|
||||
import com.hippo.ehviewer.spider.SpiderDen;
|
||||
import com.hippo.network.StatusCodeException;
|
||||
import com.hippo.okhttp.CookieDB;
|
||||
@@ -37,12 +40,12 @@ import com.hippo.scene.SceneApplication;
|
||||
import com.hippo.text.Html;
|
||||
import com.hippo.util.ReadableTime;
|
||||
import com.hippo.yorozuya.FileUtils;
|
||||
import com.hippo.yorozuya.IntIdGenerator;
|
||||
import com.hippo.yorozuya.SimpleHandler;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Comparator;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
@@ -53,8 +56,8 @@ public class EhApplication extends SceneApplication {
|
||||
private static final boolean DEBUG_CONACO = false;
|
||||
private static final boolean DEBUG_NATIVE_MEMORY = false;
|
||||
|
||||
private IntIdGenerator mIdGenerator = new IntIdGenerator();
|
||||
private SparseArray<Object> mGlobalStuffMap = new SparseArray<>();
|
||||
private final AtomicInteger mIdGenerator = new AtomicInteger();
|
||||
private final SparseArray<Object> mGlobalStuffMap = new SparseArray<>();
|
||||
private EhCookieStore mEhCookieStore;
|
||||
private EhClient mEhClient;
|
||||
private OkHttpClient mOkHttpClient;
|
||||
@@ -63,6 +66,13 @@ public class EhApplication extends SceneApplication {
|
||||
private LruCacheEx<Integer, GalleryDetail> mGalleryDetailCache;
|
||||
private LruCacheEx<String, LargePreviewSet> mLargePreviewSetCache;
|
||||
private LruCacheEx<Integer, Integer> mPreviewPagesCache;
|
||||
private DownloadManager mDownloadManager;
|
||||
|
||||
private SparseBooleanArray mItemStateArray;
|
||||
private SparseArray<String> mItemTitleArray;
|
||||
private int mFailedCount;
|
||||
private int mFinishedCount;
|
||||
private int mDownloadedCount;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
@@ -76,6 +86,11 @@ public class EhApplication extends SceneApplication {
|
||||
Html.initialize(this);
|
||||
AppConfig.initialize(this);
|
||||
SpiderDen.initialize(this);
|
||||
EhDB.initialize(this);
|
||||
|
||||
if (EhDB.needMerge()) {
|
||||
EhDB.mergeOldDB(this);
|
||||
}
|
||||
|
||||
if (DEBUG_NATIVE_MEMORY) {
|
||||
debugNativeMemory();
|
||||
@@ -94,7 +109,7 @@ public class EhApplication extends SceneApplication {
|
||||
}
|
||||
|
||||
public int putGlobalStuff(@NonNull Object o) {
|
||||
int id = mIdGenerator.nextId();
|
||||
int id = mIdGenerator.getAndDecrement();
|
||||
mGlobalStuffMap.put(id, o);
|
||||
return id;
|
||||
}
|
||||
@@ -237,4 +252,43 @@ public class EhApplication extends SceneApplication {
|
||||
}
|
||||
return application.mPreviewPagesCache;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public static DownloadManager getDownloadManager(@NonNull Context context) {
|
||||
EhApplication application = ((EhApplication) context.getApplicationContext());
|
||||
if (application.mDownloadManager == null) {
|
||||
application.mDownloadManager = new DownloadManager(application);
|
||||
}
|
||||
return application.mDownloadManager;
|
||||
}
|
||||
|
||||
|
||||
public static void initDownloadService(Context context, DownloadService service) {
|
||||
EhApplication application = ((EhApplication) context.getApplicationContext());
|
||||
if (application.mItemStateArray == null) {
|
||||
application.mItemStateArray = new SparseBooleanArray();
|
||||
}
|
||||
if (application.mItemTitleArray == null) {
|
||||
application.mItemTitleArray = new SparseArray<>();
|
||||
}
|
||||
|
||||
service.init(application.mItemStateArray, application.mItemTitleArray,
|
||||
application.mFailedCount, application.mFinishedCount, application.mDownloadedCount);
|
||||
}
|
||||
|
||||
public static void clearDownloadService(Context context, DownloadService service) {
|
||||
EhApplication application = ((EhApplication) context.getApplicationContext());
|
||||
application.mFailedCount = 0;
|
||||
application.mFinishedCount = 0;
|
||||
application.mDownloadedCount = 0;
|
||||
service.clear();
|
||||
}
|
||||
|
||||
public static void backupDownloadService(Context context,
|
||||
int failedCount, int finishedCount, int downloadedCount) {
|
||||
EhApplication application = ((EhApplication) context.getApplicationContext());
|
||||
application.mFailedCount = failedCount;
|
||||
application.mFinishedCount = finishedCount;
|
||||
application.mDownloadedCount = downloadedCount;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,371 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.util.Log;
|
||||
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo;
|
||||
import com.hippo.ehviewer.client.data.ListUrlBuilder;
|
||||
import com.hippo.ehviewer.dao.DaoMaster;
|
||||
import com.hippo.ehviewer.dao.DaoSession;
|
||||
import com.hippo.ehviewer.dao.DownloadInfoDao;
|
||||
import com.hippo.ehviewer.dao.DownloadInfoRaw;
|
||||
import com.hippo.ehviewer.dao.DownloadLabelDao;
|
||||
import com.hippo.ehviewer.dao.DownloadLabelRaw;
|
||||
import com.hippo.ehviewer.dao.GalleryInfoDao;
|
||||
import com.hippo.ehviewer.dao.GalleryInfoRaw;
|
||||
import com.hippo.ehviewer.dao.HistoryInfoDao;
|
||||
import com.hippo.ehviewer.dao.HistoryInfoRaw;
|
||||
import com.hippo.ehviewer.dao.LocalFavoriteDao;
|
||||
import com.hippo.ehviewer.dao.LocalFavoriteRaw;
|
||||
import com.hippo.ehviewer.dao.QuickSearchDao;
|
||||
import com.hippo.ehviewer.dao.QuickSearchRaw;
|
||||
import com.hippo.ehviewer.download.DownloadInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import de.greenrobot.dao.query.LazyList;
|
||||
|
||||
public class EhDB {
|
||||
|
||||
private static DaoSession sDaoSession;
|
||||
|
||||
private static boolean sHasOldDB;
|
||||
private static boolean sNewDB;
|
||||
|
||||
private static class DBOpenHelper extends DaoMaster.OpenHelper {
|
||||
|
||||
public DBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
|
||||
super(context, name, factory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
super.onCreate(db);
|
||||
sNewDB = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
}
|
||||
}
|
||||
|
||||
private static class OldDBHelper extends SQLiteOpenHelper {
|
||||
|
||||
private static final String DB_NAME = "data";
|
||||
private static final int VERSION = 4;
|
||||
|
||||
private static final String TABLE_GALLERY = "gallery";
|
||||
private static final String TABLE_LOCAL_FAVOURITE = "local_favourite";
|
||||
private static final String TABLE_TAG = "tag";
|
||||
private static final String TABLE_DOWNLOAD = "download";
|
||||
private static final String TABLE_HISTORY = "history";
|
||||
|
||||
public OldDBHelper(Context context) {
|
||||
super(context, DB_NAME, null, VERSION);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(SQLiteDatabase db) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
}
|
||||
}
|
||||
|
||||
public static void initialize(Context context) {
|
||||
sHasOldDB = context.getDatabasePath("data").exists();
|
||||
|
||||
DBOpenHelper helper = new DBOpenHelper(
|
||||
context.getApplicationContext(), "eh.db", null);
|
||||
|
||||
SQLiteDatabase db = helper.getWritableDatabase();
|
||||
DaoMaster daoMaster = new DaoMaster(db);
|
||||
|
||||
sDaoSession = daoMaster.newSession();
|
||||
}
|
||||
|
||||
public static boolean needMerge() {
|
||||
return sNewDB && sHasOldDB;
|
||||
}
|
||||
|
||||
public static void mergeOldDB(Context context) {
|
||||
sNewDB = false;
|
||||
|
||||
OldDBHelper oldDBHelper = new OldDBHelper(context);
|
||||
SQLiteDatabase oldDB;
|
||||
try {
|
||||
oldDB = oldDBHelper.getReadableDatabase();
|
||||
} catch (Exception e) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Merge gallery info
|
||||
try {
|
||||
Cursor cursor = oldDB.rawQuery("select * from " + OldDBHelper.TABLE_GALLERY, null);
|
||||
if (cursor != null) {
|
||||
GalleryInfoDao dao = sDaoSession.getGalleryInfoDao();
|
||||
if (cursor.moveToFirst()) {
|
||||
while (!cursor.isAfterLast()) {
|
||||
GalleryInfoRaw raw = new GalleryInfoRaw();
|
||||
raw.setGid((long) cursor.getInt(0));
|
||||
raw.setToken(cursor.getString(1));
|
||||
raw.setTitle(cursor.getString(2));
|
||||
raw.setPosted(cursor.getString(3));
|
||||
raw.setCategory(cursor.getInt(4));
|
||||
raw.setThumb(cursor.getString(5));
|
||||
raw.setUploader(cursor.getString(6));
|
||||
raw.setRating(cursor.getFloat(7));
|
||||
raw.setReference(cursor.getInt(8));
|
||||
dao.insert(raw);
|
||||
cursor.moveToNext();
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
// Merge local favorite
|
||||
try {
|
||||
Cursor cursor = oldDB.rawQuery("select * from " + OldDBHelper.TABLE_LOCAL_FAVOURITE, null);
|
||||
if (cursor != null) {
|
||||
LocalFavoriteDao dao = sDaoSession.getLocalFavoriteDao();
|
||||
if (cursor.moveToFirst()) {
|
||||
long i = 0L;
|
||||
while (!cursor.isAfterLast()) {
|
||||
LocalFavoriteRaw raw = new LocalFavoriteRaw();
|
||||
raw.setGid((long) cursor.getInt(0));
|
||||
raw.setDate(i);
|
||||
dao.insert(raw);
|
||||
cursor.moveToNext();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
|
||||
// Merge quick search
|
||||
try {
|
||||
Cursor cursor = oldDB.rawQuery("select * from " + OldDBHelper.TABLE_TAG, null);
|
||||
if (cursor != null) {
|
||||
QuickSearchDao dao = sDaoSession.getQuickSearchDao();
|
||||
if (cursor.moveToFirst()) {
|
||||
while (!cursor.isAfterLast()) {
|
||||
QuickSearchRaw raw = new QuickSearchRaw();
|
||||
|
||||
int mode = cursor.getInt(2);
|
||||
String search = cursor.getString(4);
|
||||
String tag = cursor.getString(7);
|
||||
if (mode == ListUrlBuilder.MODE_UPLOADER && search != null &&
|
||||
search.startsWith("uploader:")) {
|
||||
search = search.substring("uploader:".length());
|
||||
}
|
||||
|
||||
raw.setDate((long) cursor.getInt(0));
|
||||
raw.setName(cursor.getString(1));
|
||||
raw.setMode(mode);
|
||||
raw.setCategory(cursor.getInt(3));
|
||||
raw.setKeyword(mode == ListUrlBuilder.MODE_TAG ? tag : search);
|
||||
raw.setAdvanceSearch(cursor.getInt(5));
|
||||
raw.setMinRating(cursor.getInt(6));
|
||||
|
||||
dao.insert(raw);
|
||||
cursor.moveToNext();
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
// Merge download info
|
||||
try {
|
||||
Cursor cursor = oldDB.rawQuery("select * from " + OldDBHelper.TABLE_DOWNLOAD, null);
|
||||
if (cursor != null) {
|
||||
DownloadInfoDao dao = sDaoSession.getDownloadInfoDao();
|
||||
if (cursor.moveToFirst()) {
|
||||
long i = 0L;
|
||||
while (!cursor.isAfterLast()) {
|
||||
DownloadInfoRaw raw = new DownloadInfoRaw();
|
||||
|
||||
int state = cursor.getInt(2);
|
||||
int legacy = cursor.getInt(3);
|
||||
if (state == DownloadInfo.STATE_FINISH && legacy > 0) {
|
||||
state = DownloadInfo.STATE_FAILED;
|
||||
}
|
||||
|
||||
raw.setGid((long) cursor.getInt(0));
|
||||
raw.setState(state);
|
||||
raw.setLegacy(legacy);
|
||||
if (cursor.getColumnCount() == 5) {
|
||||
raw.setDate(cursor.getLong(4));
|
||||
} else {
|
||||
raw.setDate(i);
|
||||
}
|
||||
dao.insert(raw);
|
||||
cursor.moveToNext();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
try {
|
||||
// Merge history info
|
||||
Cursor cursor = oldDB.rawQuery("select * from " + OldDBHelper.TABLE_HISTORY, null);
|
||||
if (cursor != null) {
|
||||
HistoryInfoDao dao = sDaoSession.getHistoryInfoDao();
|
||||
if (cursor.moveToFirst()) {
|
||||
while (!cursor.isAfterLast()) {
|
||||
HistoryInfoRaw raw = new HistoryInfoRaw();
|
||||
raw.setGid((long) cursor.getInt(0));
|
||||
raw.setMode(cursor.getInt(1));
|
||||
raw.setDate(cursor.getLong(2));
|
||||
dao.insert(raw);
|
||||
cursor.moveToNext();
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
try {
|
||||
oldDBHelper.close();
|
||||
} catch (Exception e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
private static void addGalleryInfo(GalleryInfo galleryInfo) {
|
||||
GalleryInfoDao dao = sDaoSession.getGalleryInfoDao();
|
||||
GalleryInfoRaw raw = dao.load((long) galleryInfo.gid);
|
||||
if (raw == null) {
|
||||
// add new item, set reference 1
|
||||
raw = new GalleryInfoRaw();
|
||||
raw.setGid((long) galleryInfo.gid);
|
||||
raw.setToken(galleryInfo.token);
|
||||
raw.setTitle(galleryInfo.title);
|
||||
raw.setThumb(galleryInfo.thumb);
|
||||
raw.setCategory(galleryInfo.category);
|
||||
raw.setPosted(galleryInfo.posted);
|
||||
raw.setUploader(galleryInfo.uploader);
|
||||
raw.setRating(galleryInfo.rating);
|
||||
raw.setReference(1);
|
||||
dao.insert(raw);
|
||||
} else {
|
||||
// already in db, add reference
|
||||
raw.setReference(raw.getReference() + 1);
|
||||
dao.update(raw);
|
||||
}
|
||||
}
|
||||
|
||||
private static void removeGalleryInfo(int gid) {
|
||||
GalleryInfoDao dao = sDaoSession.getGalleryInfoDao();
|
||||
GalleryInfoRaw raw = dao.load((long) gid);
|
||||
int reference = raw.getReference();
|
||||
if (reference <= 1) {
|
||||
// No reference, delete it
|
||||
dao.deleteByKey((long) gid);
|
||||
} else {
|
||||
// Still has reference, sub reference
|
||||
raw.setReference(reference - 1);
|
||||
dao.update(raw);
|
||||
}
|
||||
}
|
||||
|
||||
public static GalleryInfo getGalleryInfo(int gid) {
|
||||
GalleryInfoDao dao = sDaoSession.getGalleryInfoDao();
|
||||
GalleryInfoRaw raw = dao.load((long) gid);
|
||||
if (raw != null) {
|
||||
GalleryInfo gi = new GalleryInfo();
|
||||
gi.gid = (int) (long) raw.getGid();
|
||||
gi.token = raw.getToken();
|
||||
gi.title = raw.getTitle();
|
||||
gi.thumb = raw.getThumb();
|
||||
gi.category = raw.getCategory();
|
||||
gi.posted = raw.getPosted();
|
||||
gi.uploader = raw.getUploader();
|
||||
gi.rating = raw.getRating();
|
||||
gi.generateSLang();
|
||||
return gi;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> getAllDownloadLabelList() {
|
||||
DownloadLabelDao dao = sDaoSession.getDownloadLabelDao();
|
||||
List<DownloadLabelRaw> list = dao.queryBuilder().orderAsc(DownloadLabelDao.Properties.Time).list();
|
||||
List<String> result = new ArrayList<>(list.size());
|
||||
for (int i = 0, n = list.size(); i < n; i++) {
|
||||
result.add(list.get(i).getLabel());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static LazyList<DownloadInfoRaw> getDownloadInfoLazyList() {
|
||||
return sDaoSession.getDownloadInfoDao().queryBuilder()
|
||||
.orderAsc(DownloadInfoDao.Properties.Date).listLazy();
|
||||
}
|
||||
|
||||
public static void addDownloadInfo(DownloadInfo info) {
|
||||
// Add gallery info first
|
||||
addGalleryInfo(info.galleryInfo);
|
||||
// Add download info
|
||||
DownloadInfoDao dao = sDaoSession.getDownloadInfoDao();
|
||||
DownloadInfoRaw raw = new DownloadInfoRaw();
|
||||
raw.setGid((long) info.galleryInfo.gid);
|
||||
raw.setState(info.state);
|
||||
raw.setLegacy(info.legacy);
|
||||
raw.setDate(info.date);
|
||||
raw.setLabel(info.label);
|
||||
dao.insert(raw);
|
||||
}
|
||||
|
||||
public static void updateDownloadInfo(DownloadInfo info) {
|
||||
DownloadInfoDao dao = sDaoSession.getDownloadInfoDao();
|
||||
DownloadInfoRaw raw = dao.load((long) info.galleryInfo.gid);
|
||||
if (raw == null) {
|
||||
Log.e("TAG", "Can't find download info: " + info.galleryInfo.gid);
|
||||
addDownloadInfo(info);
|
||||
} else {
|
||||
raw.setState(info.state);
|
||||
raw.setLegacy(info.legacy);
|
||||
raw.setDate(info.date);
|
||||
raw.setLabel(info.label);
|
||||
dao.update(raw);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,6 +117,18 @@ public class Settings {
|
||||
putBoolean(KEY_SHOW_WARNING, value);
|
||||
}
|
||||
|
||||
public static final String KEY_RECENT_DOWNLOAD_LABEL = "recent_download_label";
|
||||
private static final String DEFAULT_RECENT_DOWNLOAD_LABEL = null;
|
||||
|
||||
public static String getRecentDownloadLabel() {
|
||||
return getString(KEY_RECENT_DOWNLOAD_LABEL, DEFAULT_RECENT_DOWNLOAD_LABEL);
|
||||
}
|
||||
|
||||
public static void putRecentDownloadLabel(String value) {
|
||||
putString(KEY_RECENT_DOWNLOAD_LABEL, value);
|
||||
}
|
||||
|
||||
|
||||
public static EhConfig getEhConfig() {
|
||||
return sEhConfig;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.download;
|
||||
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo;
|
||||
|
||||
public class DownloadInfo {
|
||||
|
||||
public static final int STATE_NONE = 0;
|
||||
public static final int STATE_WAIT = 1;
|
||||
public static final int STATE_DOWNLOAD = 2;
|
||||
public static final int STATE_FINISH = 3;
|
||||
public static final int STATE_FAILED = 4;
|
||||
|
||||
public String label;
|
||||
public GalleryInfo galleryInfo;
|
||||
public int state = STATE_NONE;
|
||||
// byte/second, -1 for can't get speed now
|
||||
public long speed;
|
||||
// -1 for unknown
|
||||
public int download = 0;
|
||||
// -1 for unknown
|
||||
public int total = -1;
|
||||
// -1 for unknown
|
||||
public int legacy = -1;
|
||||
// For order
|
||||
public long date;
|
||||
}
|
||||
@@ -0,0 +1,686 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.download;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import com.hippo.ehviewer.EhDB;
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo;
|
||||
import com.hippo.ehviewer.dao.DownloadInfoRaw;
|
||||
import com.hippo.ehviewer.spider.SpiderQueen;
|
||||
import com.hippo.image.Image;
|
||||
import com.hippo.yorozuya.ConcurrentPool;
|
||||
import com.hippo.yorozuya.SimpleHandler;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import de.greenrobot.dao.query.LazyList;
|
||||
|
||||
public class DownloadManager implements SpiderQueen.OnSpiderListener {
|
||||
|
||||
private static final String TAG = DownloadManager.class.getSimpleName();
|
||||
|
||||
private final Context mContext;
|
||||
|
||||
private final Map<String, LinkedList<DownloadInfo>> mMap;
|
||||
// All labels without default label
|
||||
private final List<String> mLabelList;
|
||||
// Store download info with default label
|
||||
private final LinkedList<DownloadInfo> mDefaultInfoList;
|
||||
// Store all download info
|
||||
private final LinkedList<DownloadInfo> mAllInfoList;
|
||||
// For quick search
|
||||
private final SparseArray<DownloadInfo> mAllInfoMap;
|
||||
// Store download info wait to start
|
||||
private final LinkedList<DownloadInfo> mWaitList;
|
||||
|
||||
private final SpeedReminder mSpeedReminder;
|
||||
|
||||
private DownloadListener mDownloadListener;
|
||||
private DownloadInfoListener mDownloadInfoListener;
|
||||
|
||||
@Nullable
|
||||
private DownloadInfo mCurrentTask;
|
||||
@Nullable
|
||||
private SpiderQueen mCurrentSpider;
|
||||
|
||||
private final ConcurrentPool<NotifyTask> mNotifyTaskPool = new ConcurrentPool<>(5);
|
||||
|
||||
public DownloadManager(Context context) {
|
||||
mContext = context;
|
||||
|
||||
List<String> labels = EhDB.getAllDownloadLabelList();
|
||||
mLabelList = labels;
|
||||
|
||||
// Create list for each label
|
||||
mMap = new HashMap<>();
|
||||
for (String label : labels) {
|
||||
mMap.put(label, new LinkedList<DownloadInfo>());
|
||||
}
|
||||
// Create default for non tag
|
||||
mDefaultInfoList = new LinkedList<>();
|
||||
// Create all download info list
|
||||
mAllInfoList = new LinkedList<>();
|
||||
// Create all download info map
|
||||
mAllInfoMap = new SparseArray<>();
|
||||
|
||||
// Fill download info list
|
||||
LazyList<DownloadInfoRaw> lazyList = EhDB.getDownloadInfoLazyList();
|
||||
for (DownloadInfoRaw raw : lazyList) {
|
||||
DownloadInfo info = createDownloadInfo(raw);
|
||||
if (info == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add to all info list
|
||||
mAllInfoList.add(info);
|
||||
// Add to all info map
|
||||
mAllInfoMap.put(info.galleryInfo.gid, info);
|
||||
|
||||
// Add to list
|
||||
List<DownloadInfo> list = null;
|
||||
if (info.label != null) {
|
||||
list = mMap.get(info.label);
|
||||
}
|
||||
if (list == null) {
|
||||
list = mDefaultInfoList;
|
||||
}
|
||||
list.add(info);
|
||||
}
|
||||
lazyList.close();
|
||||
|
||||
// Create wait list
|
||||
mWaitList = new LinkedList<>();
|
||||
|
||||
mSpeedReminder = new SpeedReminder();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private DownloadInfo createDownloadInfo(DownloadInfoRaw raw) {
|
||||
GalleryInfo gi = EhDB.getGalleryInfo((int) (long) raw.getGid());
|
||||
if (gi == null) {
|
||||
Log.d(TAG, "Can't get GalleryInfo: " + raw.getGid());
|
||||
return null;
|
||||
}
|
||||
|
||||
DownloadInfo info = new DownloadInfo();
|
||||
int state = raw.getState();
|
||||
if (state == DownloadInfo.STATE_WAIT || state == DownloadInfo.STATE_DOWNLOAD) {
|
||||
state = DownloadInfo.STATE_NONE;
|
||||
}
|
||||
info.galleryInfo = gi;
|
||||
info.state = state;
|
||||
info.legacy = raw.getLegacy();
|
||||
info.date = raw.getDate();
|
||||
info.label = raw.getLabel();
|
||||
return info;
|
||||
}
|
||||
|
||||
public boolean containLabel(String label) {
|
||||
return mLabelList.contains(label);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public List<String> getLabelList() {
|
||||
return mLabelList;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public List<DownloadInfo> getAllDownloadInfoList() {
|
||||
return mAllInfoList;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public List<DownloadInfo> getDefaultDownloadInfoList() {
|
||||
return mDefaultInfoList;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public List<DownloadInfo> getLabelDownloadInfoList(String label) {
|
||||
return mMap.get(label);
|
||||
}
|
||||
|
||||
public void setDownloadInfoListener(DownloadInfoListener downloadInfoListener) {
|
||||
mDownloadInfoListener = downloadInfoListener;
|
||||
}
|
||||
|
||||
public void setDownloadListener(DownloadListener listener) {
|
||||
mDownloadListener = listener;
|
||||
}
|
||||
|
||||
private void ensureDownload() {
|
||||
if (mCurrentTask != null) {
|
||||
// Only one download
|
||||
return;
|
||||
}
|
||||
|
||||
// Get download from wait list
|
||||
if (!mWaitList.isEmpty()) {
|
||||
DownloadInfo info = mWaitList.removeFirst();
|
||||
SpiderQueen spider = SpiderQueen.obtainSpiderQueen(mContext, info.galleryInfo, SpiderQueen.MODE_DOWNLOAD);
|
||||
mCurrentTask = info;
|
||||
mCurrentSpider = spider;
|
||||
spider.addOnSpiderListener(this);
|
||||
info.state = DownloadInfo.STATE_DOWNLOAD;
|
||||
info.speed = -1;
|
||||
info.total = -1;
|
||||
info.download = 0;
|
||||
info.legacy = -1;
|
||||
// Update in DB
|
||||
EhDB.updateDownloadInfo(info);
|
||||
// Start speed count
|
||||
mSpeedReminder.start();
|
||||
// Notify start downloading
|
||||
if (mDownloadListener != null) {
|
||||
mDownloadListener.onStart(info);
|
||||
}
|
||||
// Notify state update
|
||||
if (mDownloadInfoListener != null) {
|
||||
mDownloadInfoListener.onUpdate(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void startDownload(GalleryInfo galleryInfo, @Nullable String label) {
|
||||
if (mCurrentTask != null && mCurrentTask.galleryInfo.gid == galleryInfo.gid) {
|
||||
// It is current task
|
||||
return;
|
||||
}
|
||||
|
||||
// Check in download list
|
||||
DownloadInfo info = mAllInfoMap.get(galleryInfo.gid);
|
||||
if (info != null) { // Get it in download list
|
||||
if (info.state != DownloadInfo.STATE_WAIT) {
|
||||
// Set state DownloadInfo.STATE_WAIT
|
||||
info.state = DownloadInfo.STATE_WAIT;
|
||||
// Add to wait list
|
||||
mWaitList.add(info);
|
||||
// Update in DB
|
||||
EhDB.updateDownloadInfo(info);
|
||||
// Notify state update
|
||||
if (mDownloadInfoListener != null) {
|
||||
mDownloadInfoListener.onUpdate(info);
|
||||
}
|
||||
// Make sure download is running
|
||||
ensureDownload();
|
||||
}
|
||||
} else {
|
||||
// It is new download info
|
||||
info = new DownloadInfo();
|
||||
info.galleryInfo = galleryInfo;
|
||||
info.label = label;
|
||||
info.state = DownloadInfo.STATE_WAIT;
|
||||
info.date = System.currentTimeMillis();
|
||||
// Add to all download list and map
|
||||
mAllInfoList.add(info);
|
||||
mAllInfoMap.put(galleryInfo.gid, info);
|
||||
// Add to label download list
|
||||
LinkedList<DownloadInfo> list;
|
||||
if (label == null) {
|
||||
list = mDefaultInfoList;
|
||||
} else {
|
||||
list = mMap.get(label);
|
||||
if (list == null) {
|
||||
Log.e(TAG, "Can't find download info list with label: " + label);
|
||||
list = new LinkedList<>();
|
||||
mMap.put(label, list);
|
||||
// Maybe label is missing in mLabelList
|
||||
if (!mLabelList.contains(label)) {
|
||||
mLabelList.add(label);
|
||||
}
|
||||
}
|
||||
}
|
||||
list.add(info);
|
||||
// Add to wait list
|
||||
mWaitList.add(info);
|
||||
// Save to
|
||||
EhDB.addDownloadInfo(info);
|
||||
// Notify
|
||||
if (mDownloadInfoListener != null) {
|
||||
mDownloadInfoListener.onAdd(info);
|
||||
}
|
||||
// Make sure download is running
|
||||
ensureDownload();
|
||||
}
|
||||
}
|
||||
|
||||
void stopDownload(int gid) {
|
||||
DownloadInfo info = stopDownloadInternal(gid);
|
||||
if (info != null) {
|
||||
// Update listener
|
||||
if (mDownloadInfoListener != null) {
|
||||
mDownloadInfoListener.onUpdate(info);
|
||||
}
|
||||
// Ensure download
|
||||
ensureDownload();
|
||||
}
|
||||
}
|
||||
|
||||
void stopCurrentDownload() {
|
||||
DownloadInfo info = stopCurrentDownloadInternal();
|
||||
if (info != null) {
|
||||
// Update listener
|
||||
if (mDownloadInfoListener != null) {
|
||||
mDownloadInfoListener.onUpdate(info);
|
||||
}
|
||||
// Ensure download
|
||||
ensureDownload();
|
||||
}
|
||||
}
|
||||
|
||||
void stopAllDownload() {
|
||||
// Stop all in wait list
|
||||
for (DownloadInfo info : mWaitList) {
|
||||
info.state = DownloadInfo.STATE_NONE;
|
||||
// Update in DB
|
||||
EhDB.updateDownloadInfo(info);
|
||||
}
|
||||
mWaitList.clear();
|
||||
|
||||
// Stop current
|
||||
stopCurrentDownloadInternal();
|
||||
|
||||
// Notify mDownloadInfoListener
|
||||
if (mDownloadInfoListener != null) {
|
||||
mDownloadInfoListener.onUpdateAll();
|
||||
}
|
||||
}
|
||||
|
||||
// Update in DB
|
||||
// Update listener
|
||||
// No ensureDownload
|
||||
private DownloadInfo stopDownloadInternal(int gid) {
|
||||
// Check current task
|
||||
if (mCurrentTask != null && mCurrentTask.galleryInfo.gid == gid) {
|
||||
// Stop current
|
||||
return stopCurrentDownloadInternal();
|
||||
}
|
||||
|
||||
for (Iterator<DownloadInfo> iterator = mWaitList.iterator(); iterator.hasNext();) {
|
||||
DownloadInfo info = iterator.next();
|
||||
if (info.galleryInfo.gid == gid) {
|
||||
// Remove from wait list
|
||||
iterator.remove();
|
||||
// Update state
|
||||
info.state = DownloadInfo.STATE_NONE;
|
||||
// Update in DB
|
||||
EhDB.updateDownloadInfo(info);
|
||||
return info;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Update in DB
|
||||
// Update mDownloadListener
|
||||
private DownloadInfo stopCurrentDownloadInternal() {
|
||||
DownloadInfo info = mCurrentTask;
|
||||
SpiderQueen spider = mCurrentSpider;
|
||||
// Release spider
|
||||
if (spider != null) {
|
||||
spider.removeOnSpiderListener(DownloadManager.this);
|
||||
SpiderQueen.releaseSpiderQueen(spider, SpiderQueen.MODE_DOWNLOAD);
|
||||
}
|
||||
mCurrentTask = null;
|
||||
mCurrentSpider = null;
|
||||
// Stop speed reminder
|
||||
mSpeedReminder.stop();
|
||||
if (info == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Update state
|
||||
info.state = DownloadInfo.STATE_NONE;
|
||||
// Update in DB
|
||||
EhDB.updateDownloadInfo(info);
|
||||
// Listener
|
||||
if (mDownloadListener != null) {
|
||||
mDownloadListener.onCancel(info);
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
boolean isIdle() {
|
||||
return mCurrentTask == null && mWaitList.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGetPages(int pages) {
|
||||
NotifyTask task = mNotifyTaskPool.pop();
|
||||
if (task == null) {
|
||||
task = new NotifyTask();
|
||||
}
|
||||
task.setOnGetPagesData(pages);
|
||||
SimpleHandler.getInstance().post(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGet509(int index) {
|
||||
NotifyTask task = mNotifyTaskPool.pop();
|
||||
if (task == null) {
|
||||
task = new NotifyTask();
|
||||
}
|
||||
task.setOnGet509Data(index);
|
||||
SimpleHandler.getInstance().post(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageDownload(int index, long contentLength, long receivedSize, int bytesRead) {
|
||||
NotifyTask task = mNotifyTaskPool.pop();
|
||||
if (task == null) {
|
||||
task = new NotifyTask();
|
||||
}
|
||||
task.setOnPageDownloadData(index, contentLength, receivedSize, bytesRead);
|
||||
SimpleHandler.getInstance().post(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageSuccess(int index, int downloaded, int total) {
|
||||
NotifyTask task = mNotifyTaskPool.pop();
|
||||
if (task == null) {
|
||||
task = new NotifyTask();
|
||||
}
|
||||
task.setOnPageSuccessData(index, downloaded, total);
|
||||
SimpleHandler.getInstance().post(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPageFailure(int index, String error, int downloaded, int total) {
|
||||
NotifyTask task = mNotifyTaskPool.pop();
|
||||
if (task == null) {
|
||||
task = new NotifyTask();
|
||||
}
|
||||
task.setOnPageFailureDate(index, error, downloaded, total);
|
||||
SimpleHandler.getInstance().post(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish(int downloaded, int total) {
|
||||
NotifyTask task = mNotifyTaskPool.pop();
|
||||
if (task == null) {
|
||||
task = new NotifyTask();
|
||||
}
|
||||
task.setOnFinishDate(downloaded, total);
|
||||
SimpleHandler.getInstance().post(task);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGetImageSuccess(int index, Image image) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGetImageFailure(int index, String error) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
private class NotifyTask implements Runnable {
|
||||
|
||||
public static final int TYPE_ON_GET_PAGES = 0;
|
||||
public static final int TYPE_ON_GET_509 = 1;
|
||||
public static final int TYPE_ON_PAGE_DOWNLOAD = 2;
|
||||
public static final int TYPE_ON_PAGE_SUCCESS = 3;
|
||||
public static final int TYPE_ON_PAGE_FAILURE = 4;
|
||||
public static final int TYPE_ON_FINISH = 5;
|
||||
|
||||
private int mType;
|
||||
private int mPages;
|
||||
private int mIndex;
|
||||
private long mContentLength;
|
||||
private long mReceivedSize;
|
||||
private int mBytesRead;
|
||||
private String mError;
|
||||
private int mDownloaded;
|
||||
private int mTotal;
|
||||
|
||||
public void setOnGetPagesData(int pages) {
|
||||
mType = TYPE_ON_GET_PAGES;
|
||||
mPages = pages;
|
||||
}
|
||||
|
||||
public void setOnGet509Data(int index) {
|
||||
mType = TYPE_ON_GET_509;
|
||||
mIndex = index;
|
||||
}
|
||||
|
||||
public void setOnPageDownloadData(int index, long contentLength, long receivedSize, int bytesRead) {
|
||||
mType = TYPE_ON_PAGE_DOWNLOAD;
|
||||
mIndex = index;
|
||||
mContentLength = contentLength;
|
||||
mReceivedSize = receivedSize;
|
||||
mBytesRead = bytesRead;
|
||||
}
|
||||
|
||||
public void setOnPageSuccessData(int index, int downloaded, int total) {
|
||||
mType = TYPE_ON_PAGE_SUCCESS;
|
||||
mIndex = index;
|
||||
mDownloaded = downloaded;
|
||||
mTotal = total;
|
||||
}
|
||||
|
||||
public void setOnPageFailureDate(int index, String error, int downloaded, int total) {
|
||||
mType = TYPE_ON_PAGE_FAILURE;
|
||||
mIndex = index;
|
||||
mError = error;
|
||||
mDownloaded = downloaded;
|
||||
mTotal = total;
|
||||
}
|
||||
|
||||
public void setOnFinishDate(int downloaded, int total) {
|
||||
mType = TYPE_ON_FINISH;
|
||||
mDownloaded = downloaded;
|
||||
mTotal = total;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
switch (mType) {
|
||||
case TYPE_ON_GET_PAGES: {
|
||||
DownloadInfo info = mCurrentTask;
|
||||
if (info == null) {
|
||||
Log.e(TAG, "Current task is null, but it should not be");
|
||||
} else {
|
||||
info.total = mPages;
|
||||
if (mDownloadInfoListener != null) {
|
||||
mDownloadInfoListener.onUpdate(info);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TYPE_ON_GET_509: {
|
||||
if (mDownloadListener != null) {
|
||||
mDownloadListener.onGet509();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TYPE_ON_PAGE_DOWNLOAD: {
|
||||
mSpeedReminder.up(mBytesRead);
|
||||
break;
|
||||
}
|
||||
case TYPE_ON_PAGE_SUCCESS: {
|
||||
DownloadInfo info = mCurrentTask;
|
||||
if (info == null) {
|
||||
Log.e(TAG, "Current task is null, but it should not be");
|
||||
} else {
|
||||
info.download = mDownloaded;
|
||||
info.total = mTotal;
|
||||
if (mDownloadListener != null) {
|
||||
mDownloadListener.onGetPage(info);
|
||||
}
|
||||
if (mDownloadInfoListener != null) {
|
||||
mDownloadInfoListener.onUpdate(info);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TYPE_ON_PAGE_FAILURE: {
|
||||
DownloadInfo info = mCurrentTask;
|
||||
if (info == null) {
|
||||
Log.e(TAG, "Current task is null, but it should not be");
|
||||
} else {
|
||||
info.download = mDownloaded;
|
||||
info.total = mTotal;
|
||||
if (mDownloadInfoListener != null) {
|
||||
mDownloadInfoListener.onUpdate(info);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TYPE_ON_FINISH: {
|
||||
// Download done
|
||||
DownloadInfo info = mCurrentTask;
|
||||
mCurrentTask = null;
|
||||
SpiderQueen spider = mCurrentSpider;
|
||||
mCurrentSpider = null;
|
||||
// Release spider
|
||||
if (spider != null) {
|
||||
spider.removeOnSpiderListener(DownloadManager.this);
|
||||
SpiderQueen.releaseSpiderQueen(spider, SpiderQueen.MODE_DOWNLOAD);
|
||||
}
|
||||
// Check null
|
||||
if (info == null || spider == null) {
|
||||
Log.e(TAG, "Current stuff is null, but it should not be");
|
||||
break;
|
||||
}
|
||||
// Stop speed count
|
||||
mSpeedReminder.stop();
|
||||
// Update state
|
||||
info.download = mDownloaded;
|
||||
info.total = mTotal;
|
||||
info.legacy = mTotal - mDownloaded;
|
||||
if (info.legacy == 0) {
|
||||
info.state = DownloadInfo.STATE_FINISH;
|
||||
} else {
|
||||
info.state = DownloadInfo.STATE_FAILED;
|
||||
}
|
||||
// Update in DB
|
||||
EhDB.updateDownloadInfo(info);
|
||||
// Notify
|
||||
if (mDownloadListener != null) {
|
||||
mDownloadListener.onFinish(info);
|
||||
}
|
||||
if (mDownloadInfoListener != null) {
|
||||
mDownloadInfoListener.onUpdate(info);
|
||||
}
|
||||
// Start next download
|
||||
ensureDownload();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mNotifyTaskPool.push(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class SpeedReminder implements Runnable {
|
||||
|
||||
private boolean mStop = true;
|
||||
|
||||
private final AtomicLong mBytesRead = new AtomicLong();
|
||||
|
||||
public void start() {
|
||||
if (mStop) {
|
||||
mStop = false;
|
||||
SimpleHandler.getInstance().post(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (!mStop) {
|
||||
mStop = true;
|
||||
mBytesRead.lazySet(0L);
|
||||
SimpleHandler.getInstance().removeCallbacks(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void up(int bytesRead) {
|
||||
mBytesRead.addAndGet(bytesRead);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
DownloadInfo info = mCurrentTask;
|
||||
if (info != null) {
|
||||
info.speed = mBytesRead.getAndSet(0) / 2;
|
||||
if (mDownloadListener != null) {
|
||||
mDownloadListener.onDownload(info);
|
||||
}
|
||||
if (mDownloadInfoListener != null) {
|
||||
mDownloadInfoListener.onUpdate(info);
|
||||
}
|
||||
}
|
||||
|
||||
if (!mStop) {
|
||||
SimpleHandler.getInstance().postDelayed(this, 2000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface DownloadInfoListener {
|
||||
|
||||
void onAdd(DownloadInfo info);
|
||||
|
||||
void onUpdate(DownloadInfo info);
|
||||
|
||||
void onUpdateAll();
|
||||
|
||||
void onRemove(DownloadInfo info);
|
||||
}
|
||||
|
||||
public interface DownloadListener {
|
||||
|
||||
/**
|
||||
* Get 509 error
|
||||
*/
|
||||
void onGet509();
|
||||
|
||||
/**
|
||||
* Start download
|
||||
*/
|
||||
void onStart(DownloadInfo info);
|
||||
|
||||
/**
|
||||
* Update download speed
|
||||
*/
|
||||
void onDownload(DownloadInfo info);
|
||||
|
||||
/**
|
||||
* Update page downloaded
|
||||
*/
|
||||
void onGetPage(DownloadInfo info);
|
||||
|
||||
/**
|
||||
* Download done
|
||||
*/
|
||||
void onFinish(DownloadInfo info);
|
||||
|
||||
/**
|
||||
* Download done
|
||||
*/
|
||||
void onCancel(DownloadInfo info);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,369 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.download;
|
||||
|
||||
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 android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.util.SparseBooleanArray;
|
||||
|
||||
import com.hippo.ehviewer.EhApplication;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo;
|
||||
import com.hippo.yorozuya.FileUtils;
|
||||
|
||||
public class DownloadService extends Service implements DownloadManager.DownloadListener {
|
||||
|
||||
public static final String ACTION_START = "start";
|
||||
public static final String ACTION_START_ALL = "start_all";
|
||||
public static final String ACTION_STOP = "stop";
|
||||
public static final String ACTION_STOP_CURRENT = "stop_current";
|
||||
public static final String ACTION_STOP_ALL = "stop_all";
|
||||
|
||||
public static final String ACTION_CLEAR = "clear";
|
||||
|
||||
public static final String KEY_GALLERY_INFO = "gallery_info";
|
||||
public static final String KEY_LABEL = "label";
|
||||
public static final String KEY_GID = "gid";
|
||||
|
||||
private static final int ID_DOWNLOADING = 1;
|
||||
private static final int ID_DOWNLOADED = 2;
|
||||
private static final int ID_509 = 3;
|
||||
|
||||
@Nullable
|
||||
private NotificationManager mNotifyManager;
|
||||
@Nullable
|
||||
private DownloadManager mDownloadManager;
|
||||
private NotificationCompat.Builder mDownloadingBuilder;
|
||||
private NotificationCompat.Builder mDownloadedBuilder;
|
||||
private NotificationCompat.Builder m509dBuilder;
|
||||
|
||||
@Nullable
|
||||
private SparseBooleanArray mItemStateArray;
|
||||
@Nullable
|
||||
private SparseArray<String> mItemTitleArray;
|
||||
|
||||
private int mFailedCount;
|
||||
private int mFinishedCount;
|
||||
private int mDownloadedCount;
|
||||
|
||||
public void init(SparseBooleanArray stateArray, SparseArray<String> titleArray,
|
||||
int failedCount, int finishedCount, int downloadedCount) {
|
||||
mItemStateArray = stateArray;
|
||||
mItemTitleArray = titleArray;
|
||||
mFailedCount = failedCount;
|
||||
mFinishedCount = finishedCount;
|
||||
mDownloadedCount = downloadedCount;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
mFailedCount = 0;
|
||||
mFinishedCount = 0;
|
||||
mDownloadedCount = 0;
|
||||
if (mItemStateArray != null) {
|
||||
mItemStateArray.clear();
|
||||
}
|
||||
if (mItemTitleArray != null) {
|
||||
mItemTitleArray.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
mDownloadManager = EhApplication.getDownloadManager(getApplicationContext());
|
||||
mDownloadManager.setDownloadListener(this);
|
||||
EhApplication.initDownloadService(getApplicationContext(), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
mNotifyManager = null;
|
||||
if (mDownloadManager != null) {
|
||||
mDownloadManager.setDownloadListener(null);
|
||||
mDownloadManager = null;
|
||||
}
|
||||
mDownloadingBuilder = null;
|
||||
mDownloadedBuilder = null;
|
||||
m509dBuilder = null;
|
||||
EhApplication.backupDownloadService(getApplicationContext(),
|
||||
mFailedCount, mFinishedCount, mDownloadedCount);
|
||||
mItemStateArray = null;
|
||||
mItemTitleArray = null;
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
|
||||
if (ACTION_START.equals(action)) {
|
||||
GalleryInfo gi= intent.getParcelableExtra(KEY_GALLERY_INFO);
|
||||
String label = intent.getStringExtra(KEY_LABEL);
|
||||
if (gi != null && mDownloadManager != null) {
|
||||
mDownloadManager.startDownload(gi, label);
|
||||
}
|
||||
} else if (ACTION_STOP.equals(action)) {
|
||||
int gid = intent.getIntExtra(KEY_GID, -1);
|
||||
if (gid != -1 && mDownloadManager != null) {
|
||||
mDownloadManager.stopDownload(gid);
|
||||
}
|
||||
} else if (ACTION_STOP_CURRENT.equals(action)) {
|
||||
if (mDownloadManager != null) {
|
||||
mDownloadManager.stopCurrentDownload();
|
||||
}
|
||||
} else if (ACTION_STOP_ALL.equals(action)) {
|
||||
if (mDownloadManager != null) {
|
||||
mDownloadManager.stopAllDownload();
|
||||
}
|
||||
} else if (ACTION_CLEAR.equals(action)) {
|
||||
EhApplication.clearDownloadService(getApplicationContext(), this);
|
||||
}
|
||||
|
||||
checkStopSelf();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
throw new IllegalStateException("No bindService");
|
||||
}
|
||||
|
||||
private void ensureDownloadingBuilder() {
|
||||
if (mDownloadingBuilder != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mDownloadingBuilder = new NotificationCompat.Builder(getApplicationContext())
|
||||
.setSmallIcon(android.R.drawable.stat_sys_download)
|
||||
.setOngoing(true)
|
||||
.setAutoCancel(false);
|
||||
}
|
||||
|
||||
private void ensureDownloadedBuilder() {
|
||||
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())
|
||||
.setSmallIcon(android.R.drawable.stat_sys_download_done)
|
||||
.setContentTitle(getString(R.string.stat_download_done_title))
|
||||
.setDeleteIntent(piClear)
|
||||
.setOngoing(false)
|
||||
.setAutoCancel(true);
|
||||
}
|
||||
|
||||
private void ensure509Builder() {
|
||||
if (m509dBuilder != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
m509dBuilder = new NotificationCompat.Builder(getApplicationContext())
|
||||
.setSmallIcon(R.drawable.ic_stat_alert)
|
||||
.setContentText(getString(R.string.stat_509_alert_title))
|
||||
.setContentText(getString(R.string.stat_509_alert_text))
|
||||
.setAutoCancel(true)
|
||||
.setOngoing(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGet509() {
|
||||
if (mNotifyManager == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ensure509Builder();
|
||||
|
||||
mNotifyManager.notify(ID_509, m509dBuilder.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart(DownloadInfo info) {
|
||||
if (mNotifyManager == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ensureDownloadingBuilder();
|
||||
|
||||
mDownloadingBuilder.setContentTitle(info.galleryInfo.title)
|
||||
.setContentText(null)
|
||||
.setProgress(0, 0, true);
|
||||
|
||||
startForeground(ID_DOWNLOADING, mDownloadingBuilder.build());
|
||||
}
|
||||
|
||||
private void onUpdate(DownloadInfo info) {
|
||||
if (mNotifyManager == null) {
|
||||
return;
|
||||
}
|
||||
ensureDownloadingBuilder();
|
||||
|
||||
long speed = info.speed;
|
||||
if (speed < 0) {
|
||||
speed = 0;
|
||||
}
|
||||
String text = FileUtils.humanReadableByteCount(speed, false) + "/S";
|
||||
mDownloadingBuilder.setContentTitle(info.galleryInfo.title)
|
||||
.setContentText(text)
|
||||
.setProgress(info.total, info.download, false);
|
||||
|
||||
startForeground(ID_DOWNLOADING, mDownloadingBuilder.build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDownload(DownloadInfo info) {
|
||||
onUpdate(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGetPage(DownloadInfo info) {
|
||||
onUpdate(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish(DownloadInfo info) {
|
||||
if (mNotifyManager == null || mItemStateArray == null || mItemTitleArray == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mNotifyManager.cancel(ID_DOWNLOADING);
|
||||
|
||||
ensureDownloadedBuilder();
|
||||
|
||||
boolean finish = info.state == DownloadInfo.STATE_FINISH;
|
||||
int gid = info.galleryInfo.gid;
|
||||
int index = mItemStateArray.indexOfKey(gid);
|
||||
if (index < 0) { // Not contain
|
||||
mItemStateArray.put(gid, finish);
|
||||
mItemTitleArray.put(gid, info.galleryInfo.title);
|
||||
mDownloadedCount++;
|
||||
if (finish) {
|
||||
mFinishedCount++;
|
||||
} else {
|
||||
mFailedCount++;
|
||||
}
|
||||
} else { // Contain
|
||||
boolean oldFinish = mItemStateArray.valueAt(index);
|
||||
mItemStateArray.put(gid, finish);
|
||||
mItemTitleArray.put(gid, info.galleryInfo.title);
|
||||
if (oldFinish && !finish) {
|
||||
mFinishedCount--;
|
||||
mFailedCount++;
|
||||
} else if (!oldFinish && finish) {
|
||||
mFinishedCount++;
|
||||
mFailedCount--;
|
||||
}
|
||||
}
|
||||
|
||||
String text;
|
||||
boolean needStyle;
|
||||
if (mFinishedCount != 0 && mFailedCount == 0) {
|
||||
if (mFinishedCount == 1) {
|
||||
if (mItemTitleArray.size() >= 1) {
|
||||
text = getString(R.string.stat_download_done_line_succeeded, mItemTitleArray.valueAt(0));
|
||||
} else {
|
||||
Log.d("TAG", "WTF, mItemTitleArray is null");
|
||||
text = getString(R.string.error_unknown);
|
||||
}
|
||||
needStyle = false;
|
||||
} else {
|
||||
text = getString(R.string.stat_download_done_text_succeeded, mFinishedCount);
|
||||
needStyle = true;
|
||||
}
|
||||
} else if (mFinishedCount == 0 && mFailedCount != 0) {
|
||||
if (mFailedCount == 1) {
|
||||
if (mItemTitleArray.size() >= 1) {
|
||||
text = getString(R.string.stat_download_done_line_failed, mItemTitleArray.valueAt(0));
|
||||
} else {
|
||||
Log.d("TAG", "WTF, mItemTitleArray is null");
|
||||
text = getString(R.string.error_unknown);
|
||||
}
|
||||
needStyle = false;
|
||||
} else {
|
||||
text = getString(R.string.stat_download_done_text_failed, mFailedCount);
|
||||
needStyle = true;
|
||||
}
|
||||
} else {
|
||||
text = getString(R.string.stat_download_done_text_mix, mFinishedCount, mFailedCount);
|
||||
needStyle = true;
|
||||
}
|
||||
|
||||
NotificationCompat.InboxStyle style;
|
||||
if (needStyle) {
|
||||
style = new NotificationCompat.InboxStyle();
|
||||
style.setBigContentTitle(getString(R.string.stat_download_done_title));
|
||||
SparseBooleanArray stateArray = mItemStateArray;
|
||||
SparseArray<String> titleArray = mItemTitleArray;
|
||||
for (int i = 0, n = stateArray.size(); i < n; i++) {
|
||||
int id = stateArray.keyAt(i);
|
||||
boolean fin = stateArray.valueAt(i);
|
||||
String title = titleArray.get(id);
|
||||
if (title == null) {
|
||||
continue;
|
||||
}
|
||||
style.addLine(getString(fin ? R.string.stat_download_done_line_succeeded :
|
||||
R.string.stat_download_done_line_failed, title));
|
||||
}
|
||||
} else {
|
||||
style = null;
|
||||
}
|
||||
|
||||
mDownloadedBuilder.setContentText(text).setStyle(style);
|
||||
|
||||
mNotifyManager.notify(ID_DOWNLOADED, mDownloadedBuilder.build());
|
||||
|
||||
checkStopSelf();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel(DownloadInfo info) {
|
||||
if (mNotifyManager == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mNotifyManager.cancel(ID_DOWNLOADING);
|
||||
checkStopSelf();
|
||||
}
|
||||
|
||||
private void checkStopSelf() {
|
||||
if (mDownloadManager == null || mDownloadManager.isIdle()) {
|
||||
stopForeground(true);
|
||||
stopSelf();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -119,22 +119,26 @@ public class EhGalleryProvider extends GalleryProvider implements SpiderQueen.On
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDownload(int index, long contentLength, long receivedSize, int bytesRead) {
|
||||
public void onPageDownload(int index, long contentLength, long receivedSize, int bytesRead) {
|
||||
if (contentLength > 0) {
|
||||
notifyPagePercent(index, (float) receivedSize / contentLength);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(int index) {
|
||||
public void onPageSuccess(int index, int downloaded, int total) {
|
||||
notifyDataChanged(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(int index, String error) {
|
||||
public void onPageFailure(int index, String error, int downloaded, int total) {
|
||||
notifyPageFailed(index, error);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish(int downloaded, int total) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGetImageSuccess(int index, Image image) {
|
||||
notifyPageSucceed(index, image);
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.support.annotation.Nullable;
|
||||
import android.webkit.MimeTypeMap;
|
||||
|
||||
import com.hippo.beerbelly.SimpleDiskCache;
|
||||
import com.hippo.ehviewer.EhDB;
|
||||
import com.hippo.ehviewer.Settings;
|
||||
import com.hippo.ehviewer.client.EhCacheKeyFactory;
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo;
|
||||
@@ -42,7 +43,8 @@ import java.util.Locale;
|
||||
|
||||
public final class SpiderDen {
|
||||
|
||||
private UniFile mDownloadDir;
|
||||
@Nullable
|
||||
private final UniFile mDownloadDir;
|
||||
private volatile int mMode = SpiderQueen.MODE_READ;
|
||||
private final int mGid;
|
||||
|
||||
@@ -57,14 +59,24 @@ public final class SpiderDen {
|
||||
}
|
||||
}
|
||||
|
||||
public SpiderDen(GalleryInfo galleryInfo) {
|
||||
mGid = galleryInfo.gid;
|
||||
public static UniFile getGalleryDownloadDir(GalleryInfo galleryInfo) {
|
||||
UniFile dir = Settings.getDownloadLocation();
|
||||
if (dir != null) {
|
||||
mDownloadDir = dir.subFile(FileUtils.sanitizeFilename(galleryInfo.gid + "-" + galleryInfo.title));
|
||||
GalleryInfo info = EhDB.getGalleryInfo(galleryInfo.gid);
|
||||
if (info == null) {
|
||||
info = galleryInfo;
|
||||
}
|
||||
return dir.subFile(FileUtils.sanitizeFilename(info.gid + "-" + info.title));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public SpiderDen(GalleryInfo galleryInfo) {
|
||||
mGid = galleryInfo.gid;
|
||||
mDownloadDir = getGalleryDownloadDir(galleryInfo);
|
||||
}
|
||||
|
||||
public void setMode(@SpiderQueen.Mode int mode) {
|
||||
mMode = mode;
|
||||
|
||||
|
||||
@@ -71,7 +71,6 @@ import java.util.Stack;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReferenceArray;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
@@ -82,6 +81,7 @@ public class SpiderQueen implements Runnable {
|
||||
|
||||
private static final String TAG = SpiderQueen.class.getSimpleName();
|
||||
private static final AtomicInteger sIdGenerator = new AtomicInteger();
|
||||
private static final boolean DEBUG_LOG = false;
|
||||
|
||||
@IntDef({MODE_READ, MODE_DOWNLOAD})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@@ -132,7 +132,7 @@ public class SpiderQueen implements Runnable {
|
||||
private final Stack<Integer> mDecodeRequestStack = new Stack<>();
|
||||
private final AtomicInteger mDecodeIndex = new AtomicInteger(GalleryPageView.INVALID_INDEX);
|
||||
|
||||
private volatile AtomicReferenceArray<Thread> mWorkers;
|
||||
private volatile Thread[] mWorkers;
|
||||
private final Object mWorkerLock = new Object();
|
||||
|
||||
private final Object mPTokenLock = new Object();
|
||||
@@ -196,26 +196,49 @@ public class SpiderQueen implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyDownload(int index, long contentLength, long receivedSize, int bytesRead) {
|
||||
private void notifyPageDownload(int index, long contentLength, long receivedSize, int bytesRead) {
|
||||
synchronized (mSpiderListeners) {
|
||||
for (OnSpiderListener listener : mSpiderListeners) {
|
||||
listener.onDownload(index, contentLength, receivedSize, bytesRead);
|
||||
listener.onPageDownload(index, contentLength, receivedSize, bytesRead);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void notifySuccess(int index) {
|
||||
private void notifyPageSuccess(int index) {
|
||||
int size = -1;
|
||||
int[] temp = mPageStateArray;
|
||||
if (temp != null) {
|
||||
size = temp.length;
|
||||
}
|
||||
synchronized (mSpiderListeners) {
|
||||
for (OnSpiderListener listener : mSpiderListeners) {
|
||||
listener.onSuccess(index);
|
||||
listener.onPageSuccess(index, mFinishedPages.get(), size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyFailure(int index, String error) {
|
||||
private void notifyPageFailure(int index, String error) {
|
||||
int size = -1;
|
||||
int[] temp = mPageStateArray;
|
||||
if (temp != null) {
|
||||
size = temp.length;
|
||||
}
|
||||
synchronized (mSpiderListeners) {
|
||||
for (OnSpiderListener listener : mSpiderListeners) {
|
||||
listener.onFailure(index, error);
|
||||
listener.onPageFailure(index, error, mFinishedPages.get(), size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyFinish() {
|
||||
int size = -1;
|
||||
int[] temp = mPageStateArray;
|
||||
if (temp != null) {
|
||||
size = temp.length;
|
||||
}
|
||||
synchronized (mSpiderListeners) {
|
||||
for (OnSpiderListener listener : mSpiderListeners) {
|
||||
listener.onFinish(mFinishedPages.get(), size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -283,10 +306,19 @@ public class SpiderQueen implements Runnable {
|
||||
}
|
||||
|
||||
// Update download page
|
||||
if (mMode == MODE_DOWNLOAD) {
|
||||
mDownloadPage = 0;
|
||||
} else {
|
||||
mDownloadPage = -1;
|
||||
boolean startWorkers;
|
||||
synchronized (mRequestPageQueue) {
|
||||
if (mMode == MODE_DOWNLOAD) {
|
||||
mDownloadPage = 0;
|
||||
startWorkers = true;
|
||||
} else {
|
||||
mDownloadPage = -1;
|
||||
startWorkers = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (startWorkers && mPageStateArray != null) {
|
||||
ensureWorkers();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -439,14 +471,14 @@ public class SpiderQueen implements Runnable {
|
||||
private void ensureWorkers() {
|
||||
synchronized (mWorkerLock) {
|
||||
if (mWorkers == null) {
|
||||
mWorkers = new AtomicReferenceArray<>(NUMBER_SPIDER_WORKER);
|
||||
mWorkers = new Thread[NUMBER_SPIDER_WORKER];
|
||||
}
|
||||
|
||||
for (int i = 0, n = mWorkers.length(); i < n; i++) {
|
||||
if (mWorkers.get(i) == null) {
|
||||
for (int i = 0, n = mWorkers.length; i < n; i++) {
|
||||
if (mWorkers[i] == null) {
|
||||
SpiderWorker worker = new SpiderWorker(i);
|
||||
Thread thread = mThreadFactory.newThread(worker);
|
||||
mWorkers.lazySet(i, thread);
|
||||
mWorkers[i] = thread;
|
||||
thread.start();
|
||||
}
|
||||
}
|
||||
@@ -521,7 +553,9 @@ public class SpiderQueen implements Runnable {
|
||||
try {
|
||||
String url = EhUrl.getGalleryDetailUrl(
|
||||
mGalleryInfo.gid, mGalleryInfo.token, previewIndex, false);
|
||||
Log.d(TAG, url);
|
||||
if (DEBUG_LOG) {
|
||||
Log.d(TAG, url);
|
||||
}
|
||||
Request request = new EhRequestBuilder(url, config).build();
|
||||
Response response = mHttpClient.newCall(request).execute();
|
||||
String body = response.body().string();
|
||||
@@ -688,7 +722,9 @@ public class SpiderQueen implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Log.i(TAG, Thread.currentThread().getName() + ": start");
|
||||
if (DEBUG_LOG) {
|
||||
Log.i(TAG, Thread.currentThread().getName() + ": start");
|
||||
}
|
||||
|
||||
runInternal();
|
||||
|
||||
@@ -704,24 +740,28 @@ public class SpiderQueen implements Runnable {
|
||||
// Interrupt all workers
|
||||
synchronized (mWorkerLock) {
|
||||
if (mWorkers != null) {
|
||||
for (int i = 0, n = mWorkers.length(); i < n; i++) {
|
||||
Thread thread = mWorkers.get(i);
|
||||
for (int i = 0, n = mWorkers.length; i < n; i++) {
|
||||
Thread thread = mWorkers[i];
|
||||
if (thread != null) {
|
||||
thread.interrupt();
|
||||
mWorkers.set(i, null);
|
||||
mWorkers[i] = null;
|
||||
}
|
||||
}
|
||||
mWorkers = null;
|
||||
}
|
||||
}
|
||||
|
||||
Log.i(TAG, Thread.currentThread().getName() + ": end");
|
||||
notifyFinish();
|
||||
|
||||
if (DEBUG_LOG) {
|
||||
Log.i(TAG, Thread.currentThread().getName() + ": end");
|
||||
}
|
||||
}
|
||||
|
||||
private class SpiderWorker implements Runnable {
|
||||
|
||||
private int mWorkerIndex;
|
||||
private int mGid;
|
||||
private final int mWorkerIndex;
|
||||
private final int mGid;
|
||||
|
||||
public SpiderWorker(int workerIndex) {
|
||||
mWorkerIndex = workerIndex;
|
||||
@@ -732,6 +772,10 @@ public class SpiderQueen implements Runnable {
|
||||
updatePageState(index, state, null);
|
||||
}
|
||||
|
||||
private boolean isStateDone(int state) {
|
||||
return state == STATE_FINISHED || state == STATE_FAILED;
|
||||
}
|
||||
|
||||
private void updatePageState(int index, @State int state, String error) {
|
||||
int oldState;
|
||||
synchronized (mPageStateLock) {
|
||||
@@ -739,9 +783,9 @@ public class SpiderQueen implements Runnable {
|
||||
mPageStateArray[index] = state;
|
||||
}
|
||||
|
||||
if (oldState == STATE_NONE && state != STATE_NONE) {
|
||||
if (!isStateDone(oldState) && isStateDone(state)) {
|
||||
mDownloadedPages.incrementAndGet();
|
||||
} else if (oldState != STATE_NONE && state == STATE_NONE) {
|
||||
} else if (isStateDone(oldState) && !isStateDone(state)) {
|
||||
mDownloadedPages.decrementAndGet();
|
||||
}
|
||||
if (oldState != STATE_FINISHED && state == STATE_FINISHED) {
|
||||
@@ -763,9 +807,9 @@ public class SpiderQueen implements Runnable {
|
||||
error = GetText.getString(R.string.error_unknown);
|
||||
}
|
||||
mPageErrorMap.put(index, error);
|
||||
notifyFailure(index, error);
|
||||
notifyPageFailure(index, error);
|
||||
} else if (state == STATE_FINISHED) {
|
||||
notifySuccess(index);
|
||||
notifyPageSuccess(index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -775,7 +819,9 @@ public class SpiderQueen implements Runnable {
|
||||
if (skipHathKey != null) {
|
||||
url = url + "?nl=" + skipHathKey;
|
||||
}
|
||||
Log.d(TAG, url);
|
||||
if (DEBUG_LOG) {
|
||||
Log.d(TAG, url);
|
||||
}
|
||||
Response response = mHttpClient.newCall(new EhRequestBuilder(url).build()).execute();
|
||||
String body = response.body().string();
|
||||
GalleryPageParser.Result result = GalleryPageParser.parse(body);
|
||||
@@ -828,7 +874,9 @@ public class SpiderQueen implements Runnable {
|
||||
continue;
|
||||
}
|
||||
|
||||
Log.d(TAG, imageUrl);
|
||||
if (DEBUG_LOG) {
|
||||
Log.d(TAG, imageUrl);
|
||||
}
|
||||
|
||||
// Start download image
|
||||
OutputStreamPipe pipe = mSpiderDen.openOutputStreamPipe(
|
||||
@@ -842,7 +890,9 @@ public class SpiderQueen implements Runnable {
|
||||
// Download image
|
||||
InputStream is = null;
|
||||
try {
|
||||
Log.d(TAG, "Start download image " + index);
|
||||
if (DEBUG_LOG) {
|
||||
Log.d(TAG, "Start download image " + index);
|
||||
}
|
||||
|
||||
Response response = mHttpClient.newCall(new EhRequestBuilder(imageUrl).build()).execute();
|
||||
ResponseBody responseBody = response.body();
|
||||
@@ -866,7 +916,7 @@ public class SpiderQueen implements Runnable {
|
||||
mPagePercentMap.put(index, (float) receivedSize / contentLength);
|
||||
}
|
||||
// Notify listener
|
||||
notifyDownload(index, contentLength, receivedSize, bytesRead);
|
||||
notifyPageDownload(index, contentLength, receivedSize, bytesRead);
|
||||
}
|
||||
os.flush();
|
||||
|
||||
@@ -876,7 +926,9 @@ public class SpiderQueen implements Runnable {
|
||||
break;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Download image succeed " + index);
|
||||
if (DEBUG_LOG) {
|
||||
Log.d(TAG, "Download image succeed " + index);
|
||||
}
|
||||
|
||||
// Download finished
|
||||
updatePageState(index, STATE_FINISHED);
|
||||
@@ -888,7 +940,9 @@ public class SpiderQueen implements Runnable {
|
||||
pipe.close();
|
||||
pipe.release();
|
||||
|
||||
Log.d(TAG, "End download image " + index);
|
||||
if (DEBUG_LOG) {
|
||||
Log.d(TAG, "End download image " + index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -976,7 +1030,9 @@ public class SpiderQueen implements Runnable {
|
||||
mWorkerLock.wait();
|
||||
} catch (InterruptedException e) {
|
||||
// Interrupted
|
||||
Log.d(TAG, Thread.currentThread().getName() + " Interrupted");
|
||||
if (DEBUG_LOG) {
|
||||
Log.d(TAG, Thread.currentThread().getName() + " Interrupted");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1005,19 +1061,40 @@ public class SpiderQueen implements Runnable {
|
||||
@Override
|
||||
@SuppressWarnings("StatementWithEmptyBody")
|
||||
public void run() {
|
||||
Log.i(TAG, Thread.currentThread().getName() + ": start");
|
||||
if (DEBUG_LOG) {
|
||||
Log.i(TAG, Thread.currentThread().getName() + ": start");
|
||||
}
|
||||
|
||||
while (!Thread.currentThread().isInterrupted() && runInternal());
|
||||
|
||||
|
||||
boolean finish = true;
|
||||
// Clear in spider worker array
|
||||
synchronized (mWorkerLock) {
|
||||
if (mWorkers != null && mWorkerIndex < mWorkers.length() &&
|
||||
mWorkers.get(mWorkerIndex) == Thread.currentThread()) {
|
||||
mWorkers.lazySet(mWorkerIndex, null);
|
||||
if (mWorkers != null && mWorkerIndex < mWorkers.length &&
|
||||
mWorkers[mWorkerIndex] == Thread.currentThread()) {
|
||||
mWorkers[mWorkerIndex] = null;
|
||||
}
|
||||
if (mWorkers != null) {
|
||||
for (Thread mWorker : mWorkers) {
|
||||
if (null != mWorker) {
|
||||
finish = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (finish) {
|
||||
mWorkers = null;
|
||||
}
|
||||
}
|
||||
|
||||
Log.i(TAG, Thread.currentThread().getName() + ": end");
|
||||
if (finish) {
|
||||
notifyFinish();
|
||||
}
|
||||
|
||||
if (DEBUG_LOG) {
|
||||
Log.i(TAG, Thread.currentThread().getName() + ": end");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1025,7 +1102,9 @@ public class SpiderQueen implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
Log.i(TAG, Thread.currentThread().getName() + ": start");
|
||||
if (DEBUG_LOG) {
|
||||
Log.i(TAG, Thread.currentThread().getName() + ": start");
|
||||
}
|
||||
|
||||
while (!Thread.currentThread().isInterrupted()) {
|
||||
int index;
|
||||
@@ -1076,7 +1155,9 @@ public class SpiderQueen implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
Log.i(TAG, Thread.currentThread().getName() + ": end");
|
||||
if (DEBUG_LOG) {
|
||||
Log.i(TAG, Thread.currentThread().getName() + ": end");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1089,11 +1170,16 @@ public class SpiderQueen implements Runnable {
|
||||
/**
|
||||
* @param contentLength -1 for unknown
|
||||
*/
|
||||
void onDownload(int index, long contentLength, long receivedSize, int bytesRead);
|
||||
void onPageDownload(int index, long contentLength, long receivedSize, int bytesRead);
|
||||
|
||||
void onSuccess(int index);
|
||||
void onPageSuccess(int index, int downloaded, int total);
|
||||
|
||||
void onFailure(int index, String error);
|
||||
void onPageFailure(int index, String error, int downloaded, int total);
|
||||
|
||||
/**
|
||||
* All workers end
|
||||
*/
|
||||
void onFinish(int downloaded, int total);
|
||||
|
||||
void onGetImageSuccess(int index, Image image);
|
||||
|
||||
|
||||
@@ -26,15 +26,18 @@ import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.NavigationView;
|
||||
import android.support.v4.widget.DrawerLayout;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.Settings;
|
||||
import com.hippo.ehviewer.client.EhUrlOpener;
|
||||
import com.hippo.ehviewer.client.EhUtils;
|
||||
import com.hippo.ehviewer.ui.scene.BaseScene;
|
||||
import com.hippo.ehviewer.ui.scene.DownloadScene;
|
||||
import com.hippo.ehviewer.ui.scene.GalleryListScene;
|
||||
import com.hippo.ehviewer.ui.scene.LoginScene;
|
||||
import com.hippo.ehviewer.ui.scene.WarningScene;
|
||||
@@ -50,8 +53,12 @@ public final class MainActivity extends StageActivity
|
||||
|
||||
private static final String KEY_NAV_CHECKED_ITEM = "nav_checked_item";
|
||||
|
||||
@Nullable
|
||||
private DrawerLayout mDrawerLayout;
|
||||
@Nullable
|
||||
private NavigationView mNavView;
|
||||
@Nullable
|
||||
private FrameLayout mRightDrawer;
|
||||
private int mNavCheckedItem = 0;
|
||||
|
||||
@Override
|
||||
@@ -66,8 +73,11 @@ public final class MainActivity extends StageActivity
|
||||
|
||||
mDrawerLayout = (DrawerLayout) findViewById(R.id.draw_view);
|
||||
mNavView = (NavigationView) findViewById(R.id.nav_view);
|
||||
mRightDrawer = (FrameLayout) findViewById(R.id.right_drawer);
|
||||
|
||||
mNavView.setNavigationItemSelectedListener(this);
|
||||
if (mNavView != null) {
|
||||
mNavView.setNavigationItemSelectedListener(this);
|
||||
}
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
onInit();
|
||||
@@ -76,6 +86,15 @@ public final class MainActivity extends StageActivity
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
mDrawerLayout = null;
|
||||
mNavView = null;
|
||||
mRightDrawer = null;
|
||||
}
|
||||
|
||||
private boolean handleIntent(Intent intent) {
|
||||
if (intent == null) {
|
||||
return false;
|
||||
@@ -126,10 +145,6 @@ public final class MainActivity extends StageActivity
|
||||
}
|
||||
|
||||
private void onRestore(Bundle savedInstanceState) {
|
||||
Log.d("TAG", "onRestore");
|
||||
|
||||
Log.d("TAG", "action = " + getIntent().getAction());
|
||||
|
||||
mNavCheckedItem = savedInstanceState.getInt(KEY_NAV_CHECKED_ITEM);
|
||||
}
|
||||
|
||||
@@ -158,34 +173,69 @@ public final class MainActivity extends StageActivity
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSceneViewCreated(SceneFragment scene, Bundle savedInstanceState) {
|
||||
super.onSceneViewCreated(scene, savedInstanceState);
|
||||
|
||||
if (scene instanceof BaseScene && mRightDrawer != null && mDrawerLayout != null) {
|
||||
BaseScene baseScene = (BaseScene) scene;
|
||||
mRightDrawer.removeAllViews();
|
||||
View drawerView = baseScene.onCreateDrawerView(
|
||||
getLayoutInflater(), mRightDrawer, savedInstanceState);
|
||||
if (drawerView != null) {
|
||||
mRightDrawer.addView(drawerView);
|
||||
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED, Gravity.RIGHT);
|
||||
} else {
|
||||
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, Gravity.RIGHT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSceneViewDestroyed(SceneFragment scene) {
|
||||
super.onSceneViewDestroyed(scene);
|
||||
|
||||
if (scene instanceof BaseScene) {
|
||||
BaseScene baseScene = (BaseScene) scene;
|
||||
baseScene.onDestroyDrawerView();
|
||||
}
|
||||
}
|
||||
|
||||
public void setDrawerLayoutEnable(boolean enable) {
|
||||
if (enable) {
|
||||
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
|
||||
} else {
|
||||
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
|
||||
if (mDrawerLayout != null) {
|
||||
if (enable) {
|
||||
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
|
||||
} else {
|
||||
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void toggleDrawer(int drawerGravity) {
|
||||
if (mDrawerLayout.isDrawerOpen(drawerGravity)) {
|
||||
mDrawerLayout.closeDrawer(drawerGravity);
|
||||
} else {
|
||||
mDrawerLayout.openDrawer(drawerGravity);
|
||||
if (mDrawerLayout != null) {
|
||||
if (mDrawerLayout.isDrawerOpen(drawerGravity)) {
|
||||
mDrawerLayout.closeDrawer(drawerGravity);
|
||||
} else {
|
||||
mDrawerLayout.openDrawer(drawerGravity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setNavCheckedItem(@IdRes int resId) {
|
||||
mNavCheckedItem = resId;
|
||||
if (resId == 0) {
|
||||
mNavView.setCheckedItem(R.id.nav_stub);
|
||||
} else {
|
||||
mNavView.setCheckedItem(resId);
|
||||
if (mNavView != null) {
|
||||
if (resId == 0) {
|
||||
mNavView.setCheckedItem(R.id.nav_stub);
|
||||
} else {
|
||||
mNavView.setCheckedItem(resId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (mDrawerLayout.isDrawerOpen(Gravity.LEFT) || mDrawerLayout.isDrawerOpen(Gravity.RIGHT)) {
|
||||
if (mDrawerLayout != null && (mDrawerLayout.isDrawerOpen(Gravity.LEFT) ||
|
||||
mDrawerLayout.isDrawerOpen(Gravity.RIGHT))) {
|
||||
mDrawerLayout.closeDrawers();
|
||||
} else {
|
||||
super.onBackPressed();
|
||||
@@ -214,13 +264,13 @@ public final class MainActivity extends StageActivity
|
||||
} else if (id == R.id.nav_history) {
|
||||
|
||||
} else if (id == R.id.nav_download) {
|
||||
|
||||
startScene(new Announcer(DownloadScene.class));
|
||||
} else if (id == R.id.nav_settings) {
|
||||
Intent intent = new Intent(this, SettingsActivity.class);
|
||||
startActivity(intent);
|
||||
}
|
||||
|
||||
if (id != R.id.nav_stub) {
|
||||
if (id != R.id.nav_stub && mDrawerLayout != null) {
|
||||
mDrawerLayout.closeDrawers();
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,9 @@ import android.os.Bundle;
|
||||
import android.support.annotation.IdRes;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.hippo.ehviewer.ui.MainActivity;
|
||||
import com.hippo.scene.SceneFragment;
|
||||
@@ -53,6 +55,14 @@ public class BaseScene extends SceneFragment {
|
||||
}
|
||||
}
|
||||
|
||||
public View onCreateDrawerView(LayoutInflater inflater,
|
||||
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void onDestroyDrawerView() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
@@ -0,0 +1,503 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.ui.scene;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.transition.TransitionInflater;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.hippo.easyrecyclerview.EasyRecyclerView;
|
||||
import com.hippo.ehviewer.EhApplication;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.Settings;
|
||||
import com.hippo.ehviewer.client.EhCacheKeyFactory;
|
||||
import com.hippo.ehviewer.client.EhUtils;
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo;
|
||||
import com.hippo.ehviewer.download.DownloadInfo;
|
||||
import com.hippo.ehviewer.download.DownloadManager;
|
||||
import com.hippo.ehviewer.download.DownloadService;
|
||||
import com.hippo.ehviewer.ui.GalleryActivity;
|
||||
import com.hippo.ehviewer.widget.SimpleRatingView;
|
||||
import com.hippo.rippleold.RippleSalon;
|
||||
import com.hippo.scene.Announcer;
|
||||
import com.hippo.scene.TransitionHelper;
|
||||
import com.hippo.util.ActivityHelper;
|
||||
import com.hippo.util.ApiHelper;
|
||||
import com.hippo.vector.VectorDrawable;
|
||||
import com.hippo.view.ViewTransition;
|
||||
import com.hippo.widget.LoadImageView;
|
||||
import com.hippo.widget.SimpleImageView;
|
||||
import com.hippo.yorozuya.FileUtils;
|
||||
import com.hippo.yorozuya.ObjectUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class DownloadScene extends ToolbarScene
|
||||
implements DownloadManager.DownloadInfoListener,
|
||||
EasyRecyclerView.OnItemClickListener {
|
||||
|
||||
private static final String KEY_LABEL = "label";
|
||||
|
||||
@Nullable
|
||||
private EasyRecyclerView mRecyclerView;
|
||||
@Nullable
|
||||
private ViewTransition mViewTransition;
|
||||
|
||||
@Nullable
|
||||
private DownloadAdapter mAdapter;
|
||||
|
||||
@Nullable
|
||||
private String mLabel;
|
||||
@Nullable
|
||||
private List<DownloadInfo> mList;
|
||||
|
||||
// TODO Only single instance
|
||||
@Override
|
||||
public int getLaunchMode() {
|
||||
return LAUNCH_MODE_SINGLE_TOP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
DownloadManager manager = EhApplication.getDownloadManager(getContext());
|
||||
manager.setDownloadInfoListener(this);
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
onInit();
|
||||
} else {
|
||||
onRestore(savedInstanceState);
|
||||
}
|
||||
}
|
||||
|
||||
private void onInit() {
|
||||
mLabel = Settings.getRecentDownloadLabel();
|
||||
DownloadManager manager = EhApplication.getDownloadManager(getContext());
|
||||
if (mLabel == null) {
|
||||
mList = manager.getDefaultDownloadInfoList();
|
||||
} else {
|
||||
mList = manager.getLabelDownloadInfoList(mLabel);
|
||||
if (mList == null) {
|
||||
mLabel = null;
|
||||
mList = manager.getDefaultDownloadInfoList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void onRestore(@NonNull Bundle savedInstanceState) {
|
||||
mLabel = savedInstanceState.getString(KEY_LABEL);
|
||||
DownloadManager manager = EhApplication.getDownloadManager(getContext());
|
||||
if (mLabel == null) {
|
||||
mList = manager.getDefaultDownloadInfoList();
|
||||
} else {
|
||||
mList = manager.getLabelDownloadInfoList(mLabel);
|
||||
if (mList == null) {
|
||||
mLabel = null;
|
||||
mList = manager.getDefaultDownloadInfoList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putString(KEY_LABEL, mLabel);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView2(LayoutInflater inflater,
|
||||
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.scene_download, container, false);
|
||||
mRecyclerView = (EasyRecyclerView) view.findViewById(R.id.recycler_view);
|
||||
View tip = view.findViewById(R.id.tip);
|
||||
SimpleImageView tipImage = (SimpleImageView) tip.findViewById(R.id.tip_image);
|
||||
tipImage.setDrawable(VectorDrawable.create(getContext(), R.xml.sadpanda_head));
|
||||
mViewTransition = new ViewTransition(mRecyclerView, tip);
|
||||
|
||||
if (mRecyclerView != null) {
|
||||
mAdapter = new DownloadAdapter();
|
||||
mRecyclerView.setAdapter(mAdapter);
|
||||
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
mRecyclerView.setSelector(RippleSalon.generateRippleDrawable(false));
|
||||
mRecyclerView.setDrawSelectorOnTop(true);
|
||||
mRecyclerView.hasFixedSize();
|
||||
mRecyclerView.setClipToPadding(false);
|
||||
mRecyclerView.setOnItemClickListener(this);
|
||||
int paddingH = getResources().getDimensionPixelOffset(R.dimen.list_content_margin_h);
|
||||
int paddingV = getResources().getDimensionPixelOffset(R.dimen.list_content_margin_v);
|
||||
mRecyclerView.setPadding(paddingV, paddingH, paddingV, paddingH);
|
||||
}
|
||||
|
||||
if (mList == null || mList.isEmpty()) {
|
||||
mViewTransition.showView(1);
|
||||
} else {
|
||||
mViewTransition.showView(0);
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
setTitle(R.string.download);
|
||||
setNavigationIcon(VectorDrawable.create(getContext(), R.xml.ic_arrow_left_dark_x24));
|
||||
|
||||
// Clear nav checked item
|
||||
setNavCheckedItem(R.id.nav_download);
|
||||
|
||||
// Hide IME
|
||||
ActivityHelper.hideSoftInput(getActivity());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNavigationClick() {
|
||||
finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
|
||||
DownloadManager manager = EhApplication.getDownloadManager(getContext());
|
||||
manager.setDownloadInfoListener(null);
|
||||
mRecyclerView = null;
|
||||
mViewTransition = null;
|
||||
mAdapter = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
mList = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onItemClick(EasyRecyclerView parent, View view, int position, long id) {
|
||||
List<DownloadInfo> list = mList;
|
||||
if (list == null) {
|
||||
return false;
|
||||
}
|
||||
if (position < 0 && position >= list.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Intent intent = new Intent(getActivity(), GalleryActivity.class);
|
||||
intent.setAction(GalleryActivity.ACTION_EH);
|
||||
intent.putExtra(GalleryActivity.KEY_GALLERY_INFO, list.get(position).galleryInfo);
|
||||
startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAdd(DownloadInfo info) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdate(DownloadInfo info) {
|
||||
if (!ObjectUtils.equal(info.label, mLabel)) {
|
||||
return;
|
||||
}
|
||||
RecyclerView recyclerView = mRecyclerView;
|
||||
if (recyclerView == null) {
|
||||
return;
|
||||
}
|
||||
List<DownloadInfo> list = mList;
|
||||
if (list == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int size = list.size();
|
||||
for (int i = 0, n = recyclerView.getChildCount(); i < n; i++) {
|
||||
View child = recyclerView.getChildAt(i);
|
||||
int index = recyclerView.getChildAdapterPosition(child);
|
||||
if (index >= 0 && index < size && list.get(index) == info) {
|
||||
DownloadHolder holder = (DownloadHolder) recyclerView.getChildViewHolder(child);
|
||||
if (holder != null) {
|
||||
bindForState(holder, info);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpdateAll() {
|
||||
RecyclerView recyclerView = mRecyclerView;
|
||||
if (recyclerView == null) {
|
||||
return;
|
||||
}
|
||||
List<DownloadInfo> list = mList;
|
||||
if (list == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int size = list.size();
|
||||
for (int i = 0, n = recyclerView.getChildCount(); i < n; i++) {
|
||||
View child = recyclerView.getChildAt(i);
|
||||
int index = recyclerView.getChildAdapterPosition(child);
|
||||
if (index >= 0 && index < size) {
|
||||
DownloadHolder holder = (DownloadHolder) recyclerView.getChildViewHolder(child);
|
||||
bindForState(holder, list.get(index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemove(DownloadInfo info) {
|
||||
|
||||
}
|
||||
|
||||
private void bindForState(DownloadHolder holder, DownloadInfo info) {
|
||||
switch (info.state) {
|
||||
case DownloadInfo.STATE_NONE:
|
||||
bindState(holder, info, getContext().getString(R.string.download_state_none));
|
||||
break;
|
||||
case DownloadInfo.STATE_WAIT:
|
||||
bindState(holder, info, getContext().getString(R.string.download_state_wait));
|
||||
break;
|
||||
case DownloadInfo.STATE_DOWNLOAD:
|
||||
bindProgress(holder, info);
|
||||
break;
|
||||
case DownloadInfo.STATE_FAILED:
|
||||
String text;
|
||||
if (info.legacy <= 0) {
|
||||
text = getContext().getString(R.string.download_state_failed);
|
||||
} else {
|
||||
text = getContext().getString(R.string.download_state_failed_2, info.legacy);
|
||||
}
|
||||
bindState(holder, info, text);
|
||||
break;
|
||||
case DownloadInfo.STATE_FINISH:
|
||||
bindState(holder, info, getContext().getString(R.string.download_state_finish));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void bindState(DownloadHolder holder, DownloadInfo info, String state) {
|
||||
holder.uploader.setVisibility(View.VISIBLE);
|
||||
holder.rating.setVisibility(View.VISIBLE);
|
||||
holder.category.setVisibility(View.VISIBLE);
|
||||
holder.state.setVisibility(View.VISIBLE);
|
||||
holder.progressBar.setVisibility(View.INVISIBLE);
|
||||
holder.percent.setVisibility(View.INVISIBLE);
|
||||
holder.speed.setVisibility(View.INVISIBLE);
|
||||
|
||||
holder.state.setText(state);
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
private void bindProgress(DownloadHolder holder, DownloadInfo info) {
|
||||
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);
|
||||
holder.percent.setVisibility(View.VISIBLE);
|
||||
holder.speed.setVisibility(View.VISIBLE);
|
||||
|
||||
if (info.total <= 0 || info.download < 0) {
|
||||
holder.percent.setText(null);
|
||||
holder.progressBar.setIndeterminate(true);
|
||||
} else {
|
||||
holder.percent.setText(info.download + "/" + info.total);
|
||||
holder.progressBar.setIndeterminate(false);
|
||||
holder.progressBar.setMax(info.total);
|
||||
holder.progressBar.setProgress(info.download);
|
||||
}
|
||||
long speed = info.speed;
|
||||
if (speed < 0) {
|
||||
speed = 0;
|
||||
}
|
||||
holder.speed.setText(FileUtils.humanReadableByteCount(speed, false) + "/S");
|
||||
}
|
||||
|
||||
private class DownloadHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
|
||||
|
||||
public final LoadImageView thumb;
|
||||
public final TextView title;
|
||||
public final TextView uploader;
|
||||
public final SimpleRatingView rating;
|
||||
public final TextView category;
|
||||
public final View start;
|
||||
public final View stop;
|
||||
public final View delete;
|
||||
public final TextView state;
|
||||
public final ProgressBar progressBar;
|
||||
public final TextView percent;
|
||||
public final TextView speed;
|
||||
|
||||
public DownloadHolder(View itemView) {
|
||||
super(itemView);
|
||||
|
||||
thumb = (LoadImageView) itemView.findViewById(R.id.thumb);
|
||||
title = (TextView) itemView.findViewById(R.id.title);
|
||||
uploader = (TextView) itemView.findViewById(R.id.uploader);
|
||||
rating = (SimpleRatingView) itemView.findViewById(R.id.rating);
|
||||
category = (TextView) itemView.findViewById(R.id.category);
|
||||
start = itemView.findViewById(R.id.start);
|
||||
stop = itemView.findViewById(R.id.stop);
|
||||
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);
|
||||
|
||||
thumb.setOnClickListener(this);
|
||||
start.setOnClickListener(this);
|
||||
stop.setOnClickListener(this);
|
||||
delete.setOnClickListener(this);
|
||||
RippleSalon.addRipple(start, false);
|
||||
RippleSalon.addRipple(stop, false);
|
||||
RippleSalon.addRipple(delete, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
RecyclerView recyclerView = mRecyclerView;
|
||||
if (recyclerView == null) {
|
||||
return;
|
||||
}
|
||||
List<DownloadInfo> list = mList;
|
||||
if (list == null) {
|
||||
return;
|
||||
}
|
||||
int size = list.size();
|
||||
int index = recyclerView.getChildAdapterPosition(itemView);
|
||||
if (index < 0 && index >= size) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (thumb == v) {
|
||||
Bundle args = new Bundle();
|
||||
args.putString(GalleryDetailScene.KEY_ACTION, GalleryDetailScene.ACTION_GALLERY_INFO);
|
||||
args.putParcelable(GalleryDetailScene.KEY_GALLERY_INFO, list.get(index).galleryInfo);
|
||||
Announcer announcer = new Announcer(GalleryDetailScene.class).setArgs(args);
|
||||
if (ApiHelper.SUPPORT_TRANSITION) {
|
||||
DownloadHolder holder = (DownloadHolder) recyclerView.getChildViewHolder(itemView);
|
||||
announcer.setTranHelper(new EnterGalleryDetailTransaction(holder));
|
||||
}
|
||||
startScene(announcer);
|
||||
} else if (start == v) {
|
||||
Intent intent = new Intent(getActivity(), DownloadService.class);
|
||||
intent.setAction(DownloadService.ACTION_START);
|
||||
intent.putExtra(DownloadService.KEY_GALLERY_INFO, list.get(index).galleryInfo);
|
||||
getActivity().startService(intent);
|
||||
} else if (stop == v) {
|
||||
Intent intent = new Intent(getActivity(), DownloadService.class);
|
||||
intent.setAction(DownloadService.ACTION_STOP);
|
||||
intent.putExtra(DownloadService.KEY_GID, list.get(index).galleryInfo.gid);
|
||||
getActivity().startService(intent);
|
||||
} else if (delete == v) {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class EnterGalleryDetailTransaction implements TransitionHelper {
|
||||
|
||||
private final DownloadHolder mHolder;
|
||||
|
||||
public EnterGalleryDetailTransaction(DownloadHolder holder) {
|
||||
mHolder = holder;
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
@Override
|
||||
public boolean onTransition(Context context, FragmentTransaction transaction,
|
||||
Fragment exit, Fragment enter) {
|
||||
if (!(enter instanceof GalleryDetailScene)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
exit.setSharedElementReturnTransition(
|
||||
TransitionInflater.from(context).inflateTransition(R.transition.trans_move));
|
||||
exit.setExitTransition(
|
||||
TransitionInflater.from(context).inflateTransition(android.R.transition.fade));
|
||||
enter.setSharedElementEnterTransition(
|
||||
TransitionInflater.from(context).inflateTransition(R.transition.trans_move));
|
||||
enter.setEnterTransition(
|
||||
TransitionInflater.from(context).inflateTransition(android.R.transition.fade));
|
||||
transaction.addSharedElement(mHolder.thumb, mHolder.thumb.getTransitionName());
|
||||
transaction.addSharedElement(mHolder.title, mHolder.title.getTransitionName());
|
||||
transaction.addSharedElement(mHolder.uploader, mHolder.uploader.getTransitionName());
|
||||
transaction.addSharedElement(mHolder.category, mHolder.category.getTransitionName());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class DownloadAdapter extends RecyclerView.Adapter<DownloadHolder> {
|
||||
|
||||
@Override
|
||||
public DownloadHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
return new DownloadHolder(getActivity().getLayoutInflater().inflate(R.layout.item_download, parent, false));
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
@Override
|
||||
public void onBindViewHolder(DownloadHolder holder, int position) {
|
||||
if (mList == null) {
|
||||
return;
|
||||
}
|
||||
DownloadInfo info = mList.get(position);
|
||||
GalleryInfo gi = info.galleryInfo;
|
||||
holder.thumb.load(EhCacheKeyFactory.getThumbKey(gi.gid), gi.thumb, true);
|
||||
holder.title.setText(gi.title);
|
||||
holder.uploader.setText(gi.uploader);
|
||||
holder.rating.setRating(gi.rating);
|
||||
TextView category = holder.category;
|
||||
String newCategoryText = EhUtils.getCategory(gi.category);
|
||||
if (!newCategoryText.equals(category.getText())) {
|
||||
category.setText(newCategoryText);
|
||||
category.setBackgroundColor(EhUtils.getCategoryColor(gi.category));
|
||||
}
|
||||
bindForState(holder, info);
|
||||
|
||||
// Update transition name
|
||||
if (ApiHelper.SUPPORT_TRANSITION) {
|
||||
int gid = gi.gid;
|
||||
holder.thumb.setTransitionName(TransitionNameFactory.getThumbTransitionName(gid));
|
||||
holder.title.setTransitionName(TransitionNameFactory.getTitleTransitionName(gid));
|
||||
holder.uploader.setTransitionName(TransitionNameFactory.getUploaderTransitionName(gid));
|
||||
holder.category.setTransitionName(TransitionNameFactory.getCategoryTransitionName(gid));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mList == null ? 0 : mList.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,6 +61,7 @@ import com.hippo.ehviewer.client.data.GalleryTagGroup;
|
||||
import com.hippo.ehviewer.client.data.LargePreviewSet;
|
||||
import com.hippo.ehviewer.client.data.ListUrlBuilder;
|
||||
import com.hippo.ehviewer.client.parser.RateGalleryParser;
|
||||
import com.hippo.ehviewer.download.DownloadService;
|
||||
import com.hippo.ehviewer.ui.GalleryActivity;
|
||||
import com.hippo.rippleold.RippleSalon;
|
||||
import com.hippo.scene.Announcer;
|
||||
@@ -870,7 +871,19 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene
|
||||
lub.setCategory(category);
|
||||
GalleryListScene.startScene(this, lub);
|
||||
} else if (mDownload == v) {
|
||||
// TODO
|
||||
// Add download
|
||||
GalleryInfo galleryInfo = null;
|
||||
if (mGalleryInfo != null) {
|
||||
galleryInfo = mGalleryInfo;
|
||||
} else if (mGalleryDetail != null) {
|
||||
galleryInfo = mGalleryDetail;
|
||||
}
|
||||
if (galleryInfo != null) {
|
||||
Intent intent = new Intent(getActivity(), DownloadService.class);
|
||||
intent.setAction(DownloadService.ACTION_START);
|
||||
intent.putExtra(DownloadService.KEY_GALLERY_INFO, galleryInfo);
|
||||
getActivity().startService(intent);
|
||||
}
|
||||
} else if (mRead == v) {
|
||||
GalleryInfo galleryInfo = null;
|
||||
if (mGalleryInfo != null) {
|
||||
@@ -946,7 +959,7 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene
|
||||
// Only show transaction when thumb can be seen
|
||||
if (location[1] + mThumb.getHeight() > 0) {
|
||||
setTransitionName();
|
||||
finish(new EnterGalleryListTransaction(mThumb, mTitle, mUploader, mCategory));
|
||||
finish(new ExitTransaction(mThumb, mTitle, mUploader, mCategory));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -980,14 +993,14 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene
|
||||
}
|
||||
}
|
||||
|
||||
private static class EnterGalleryListTransaction implements TransitionHelper {
|
||||
private static class ExitTransaction implements TransitionHelper {
|
||||
|
||||
private View mThumb;
|
||||
private View mTitle;
|
||||
private View mUploader;
|
||||
private View mCategory;
|
||||
private final View mThumb;
|
||||
private final View mTitle;
|
||||
private final View mUploader;
|
||||
private final View mCategory;
|
||||
|
||||
public EnterGalleryListTransaction(View thumb, View title, View uploader, View category) {
|
||||
public ExitTransaction(View thumb, View title, View uploader, View category) {
|
||||
mThumb = thumb;
|
||||
mTitle = title;
|
||||
mUploader = uploader;
|
||||
@@ -998,7 +1011,7 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public boolean onTransition(Context context,
|
||||
FragmentTransaction transaction, Fragment exit, Fragment enter) {
|
||||
if (!(enter instanceof GalleryListScene)) {
|
||||
if (!(enter instanceof GalleryListScene) && !(enter instanceof DownloadScene)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -204,6 +204,14 @@ public final class GalleryListScene extends BaseScene
|
||||
mState = savedInstanceState.getInt(KEY_STATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putBoolean(KEY_HAS_FIRST_REFRESH, mHasFirstRefresh);
|
||||
outState.putParcelable(KEY_LIST_URL_BUILDER, mUrlBuilder);
|
||||
outState.putInt(KEY_STATE, mState);
|
||||
}
|
||||
|
||||
private void setSearchBarHint(Context context, SearchBar searchBar) {
|
||||
Resources resources = context.getResources();
|
||||
Drawable searchImage = VectorDrawable.create(context, R.xml.ic_magnify_x24);
|
||||
@@ -355,14 +363,6 @@ public final class GalleryListScene extends BaseScene
|
||||
mFabAnimatorListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putBoolean(KEY_HAS_FIRST_REFRESH, mHasFirstRefresh);
|
||||
outState.putParcelable(KEY_LIST_URL_BUILDER, mUrlBuilder);
|
||||
outState.putInt(KEY_STATE, mState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (mFab == v) {
|
||||
@@ -417,7 +417,7 @@ public final class GalleryListScene extends BaseScene
|
||||
|
||||
private static class EnterGalleryDetailTransaction implements TransitionHelper {
|
||||
|
||||
private GalleryListHolder mHolder;
|
||||
private final GalleryListHolder mHolder;
|
||||
|
||||
public EnterGalleryDetailTransaction(GalleryListHolder holder) {
|
||||
mHolder = holder;
|
||||
@@ -494,85 +494,69 @@ public final class GalleryListScene extends BaseScene
|
||||
|
||||
switch (oldState) {
|
||||
case STATE_NORMAL:
|
||||
switch (state) {
|
||||
case STATE_SIMPLE_SEARCH:
|
||||
mSearchBar.setState(SearchBar.STATE_SEARCH_LIST, animation);
|
||||
mSearchBarMoveHelper.returnSearchBarPosition();
|
||||
showFab();
|
||||
break;
|
||||
case STATE_SEARCH:
|
||||
mViewTransition.showView(1, animation);
|
||||
mSearchLayout.scrollSearchContainerToTop();
|
||||
mSearchBar.setState(SearchBar.STATE_SEARCH, animation);
|
||||
mSearchBarMoveHelper.returnSearchBarPosition();
|
||||
showFab();
|
||||
break;
|
||||
case STATE_SEARCH_SHOW_LIST:
|
||||
mViewTransition.showView(1, animation);
|
||||
mSearchLayout.scrollSearchContainerToTop();
|
||||
mSearchBar.setState(SearchBar.STATE_SEARCH_LIST, animation);
|
||||
mSearchBarMoveHelper.returnSearchBarPosition();
|
||||
showFab();
|
||||
break;
|
||||
if (state == STATE_SIMPLE_SEARCH) {
|
||||
mSearchBar.setState(SearchBar.STATE_SEARCH_LIST, animation);
|
||||
mSearchBarMoveHelper.returnSearchBarPosition();
|
||||
showFab();
|
||||
} else if (state == STATE_SEARCH) {
|
||||
mViewTransition.showView(1, animation);
|
||||
mSearchLayout.scrollSearchContainerToTop();
|
||||
mSearchBar.setState(SearchBar.STATE_SEARCH, animation);
|
||||
mSearchBarMoveHelper.returnSearchBarPosition();
|
||||
showFab();
|
||||
} else if (state == STATE_SEARCH_SHOW_LIST) {
|
||||
mViewTransition.showView(1, animation);
|
||||
mSearchLayout.scrollSearchContainerToTop();
|
||||
mSearchBar.setState(SearchBar.STATE_SEARCH_LIST, animation);
|
||||
mSearchBarMoveHelper.returnSearchBarPosition();
|
||||
showFab();
|
||||
}
|
||||
break;
|
||||
case STATE_SIMPLE_SEARCH:
|
||||
switch (state) {
|
||||
case STATE_NORMAL:
|
||||
mSearchBar.setState(SearchBar.STATE_NORMAL, animation);
|
||||
mSearchBarMoveHelper.returnSearchBarPosition();
|
||||
hideFab();
|
||||
break;
|
||||
case STATE_SEARCH:
|
||||
mViewTransition.showView(1, animation);
|
||||
mSearchLayout.scrollSearchContainerToTop();
|
||||
mSearchBar.setState(SearchBar.STATE_SEARCH, animation);
|
||||
mSearchBarMoveHelper.returnSearchBarPosition();
|
||||
break;
|
||||
case STATE_SEARCH_SHOW_LIST:
|
||||
mViewTransition.showView(1, animation);
|
||||
mSearchLayout.scrollSearchContainerToTop();
|
||||
mSearchBar.setState(SearchBar.STATE_SEARCH_LIST, animation);
|
||||
mSearchBarMoveHelper.returnSearchBarPosition();
|
||||
break;
|
||||
if (state == STATE_NORMAL) {
|
||||
mSearchBar.setState(SearchBar.STATE_NORMAL, animation);
|
||||
mSearchBarMoveHelper.returnSearchBarPosition();
|
||||
hideFab();
|
||||
} else if (state == STATE_SEARCH) {
|
||||
mViewTransition.showView(1, animation);
|
||||
mSearchLayout.scrollSearchContainerToTop();
|
||||
mSearchBar.setState(SearchBar.STATE_SEARCH, animation);
|
||||
mSearchBarMoveHelper.returnSearchBarPosition();
|
||||
} else if (state == STATE_SEARCH_SHOW_LIST) {
|
||||
mViewTransition.showView(1, animation);
|
||||
mSearchLayout.scrollSearchContainerToTop();
|
||||
mSearchBar.setState(SearchBar.STATE_SEARCH_LIST, animation);
|
||||
mSearchBarMoveHelper.returnSearchBarPosition();
|
||||
}
|
||||
break;
|
||||
case STATE_SEARCH:
|
||||
switch (state) {
|
||||
case STATE_NORMAL:
|
||||
mViewTransition.showView(0, animation);
|
||||
mSearchBar.setState(SearchBar.STATE_NORMAL, animation);
|
||||
mSearchBarMoveHelper.returnSearchBarPosition();
|
||||
hideFab();
|
||||
break;
|
||||
case STATE_SIMPLE_SEARCH:
|
||||
mViewTransition.showView(0, animation);
|
||||
mSearchBar.setState(SearchBar.STATE_SEARCH_LIST, animation);
|
||||
mSearchBarMoveHelper.returnSearchBarPosition();
|
||||
break;
|
||||
case STATE_SEARCH_SHOW_LIST:
|
||||
mSearchBar.setState(SearchBar.STATE_SEARCH_LIST, animation);
|
||||
mSearchBarMoveHelper.returnSearchBarPosition();
|
||||
break;
|
||||
if (state == STATE_NORMAL) {
|
||||
mViewTransition.showView(0, animation);
|
||||
mSearchBar.setState(SearchBar.STATE_NORMAL, animation);
|
||||
mSearchBarMoveHelper.returnSearchBarPosition();
|
||||
hideFab();
|
||||
} else if (state == STATE_SIMPLE_SEARCH) {
|
||||
mViewTransition.showView(0, animation);
|
||||
mSearchBar.setState(SearchBar.STATE_SEARCH_LIST, animation);
|
||||
mSearchBarMoveHelper.returnSearchBarPosition();
|
||||
} else if (state == STATE_SEARCH_SHOW_LIST) {
|
||||
mSearchBar.setState(SearchBar.STATE_SEARCH_LIST, animation);
|
||||
mSearchBarMoveHelper.returnSearchBarPosition();
|
||||
}
|
||||
break;
|
||||
case STATE_SEARCH_SHOW_LIST:
|
||||
switch (state) {
|
||||
case STATE_NORMAL:
|
||||
mViewTransition.showView(0, animation);
|
||||
mSearchBar.setState(SearchBar.STATE_NORMAL, animation);
|
||||
mSearchBarMoveHelper.returnSearchBarPosition();
|
||||
hideFab();
|
||||
break;
|
||||
case STATE_SIMPLE_SEARCH:
|
||||
mViewTransition.showView(0, animation);
|
||||
mSearchBar.setState(SearchBar.STATE_SEARCH_LIST, animation);
|
||||
mSearchBarMoveHelper.returnSearchBarPosition();
|
||||
break;
|
||||
case STATE_SEARCH:
|
||||
mSearchBar.setState(SearchBar.STATE_SEARCH, animation);
|
||||
mSearchBarMoveHelper.returnSearchBarPosition();
|
||||
break;
|
||||
if (state == STATE_NORMAL) {
|
||||
mViewTransition.showView(0, animation);
|
||||
mSearchBar.setState(SearchBar.STATE_NORMAL, animation);
|
||||
mSearchBarMoveHelper.returnSearchBarPosition();
|
||||
hideFab();
|
||||
} else if (state == STATE_SIMPLE_SEARCH) {
|
||||
mViewTransition.showView(0, animation);
|
||||
mSearchBar.setState(SearchBar.STATE_SEARCH_LIST, animation);
|
||||
mSearchBarMoveHelper.returnSearchBarPosition();
|
||||
} else if (state == STATE_SEARCH) {
|
||||
mSearchBar.setState(SearchBar.STATE_SEARCH, animation);
|
||||
mSearchBarMoveHelper.returnSearchBarPosition();
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -757,6 +741,7 @@ public final class GalleryListScene extends BaseScene
|
||||
returnSearchBarPosition(true);
|
||||
}
|
||||
|
||||
@SuppressWarnings("SimplifiableIfStatement")
|
||||
private void returnSearchBarPosition(boolean animation) {
|
||||
if (mSearchBar.getHeight() == 0) {
|
||||
// Layout not called
|
||||
@@ -919,13 +904,13 @@ public final class GalleryListScene extends BaseScene
|
||||
|
||||
private class GalleryListHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private LoadImageView thumb;
|
||||
private TextView title;
|
||||
private TextView uploader;
|
||||
private SimpleRatingView rating;
|
||||
private TextView category;
|
||||
private TextView posted;
|
||||
private TextView simpleLanguage;
|
||||
private final LoadImageView thumb;
|
||||
private final TextView title;
|
||||
private final TextView uploader;
|
||||
private final SimpleRatingView rating;
|
||||
private final TextView category;
|
||||
private final TextView posted;
|
||||
private final TextView simpleLanguage;
|
||||
|
||||
public GalleryListHolder(View itemView) {
|
||||
super(itemView);
|
||||
@@ -942,7 +927,7 @@ public final class GalleryListScene extends BaseScene
|
||||
|
||||
private class GalleryListAdapter extends RecyclerView.Adapter<GalleryListHolder> {
|
||||
|
||||
private LayoutInflater mInflater;
|
||||
private final LayoutInflater mInflater;
|
||||
|
||||
public GalleryListAdapter() {
|
||||
mInflater = getActivity().getLayoutInflater();
|
||||
@@ -1053,7 +1038,7 @@ public final class GalleryListScene extends BaseScene
|
||||
|
||||
private static class GetGalleryListListener extends EhCallback<GalleryListScene, GalleryListParser.Result> {
|
||||
|
||||
private int mTaskId;
|
||||
private final int mTaskId;
|
||||
|
||||
public GetGalleryListListener(Context context, int stageId, String sceneTag, int taskId) {
|
||||
super(context, stageId, sceneTag);
|
||||
|
||||
@@ -35,7 +35,7 @@ public class CookieDB {
|
||||
|
||||
private static DaoSession sDaoSession;
|
||||
|
||||
public static class DBOpenHelper extends DaoMaster.OpenHelper {
|
||||
private static class DBOpenHelper extends DaoMaster.OpenHelper {
|
||||
|
||||
public DBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
|
||||
super(context, name, factory);
|
||||
@@ -56,7 +56,7 @@ public class CookieDB {
|
||||
sDaoSession = daoMaster.newSession();
|
||||
}
|
||||
|
||||
public static Map<String, List<CookieWithID>> getAllCookies() {
|
||||
static Map<String, List<CookieWithID>> getAllCookies() {
|
||||
OkHttp3CookieDao dao = sDaoSession.getOkHttp3CookieDao();
|
||||
List<OkHttp3CookieRaw> list = dao.queryBuilder().list();
|
||||
|
||||
@@ -107,11 +107,11 @@ public class CookieDB {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void removeCookie(long id) {
|
||||
static void removeCookie(long id) {
|
||||
sDaoSession.getOkHttp3CookieDao().deleteByKey(id);
|
||||
}
|
||||
|
||||
public static long addCookie(Cookie cookie) {
|
||||
static long addCookie(Cookie cookie) {
|
||||
OkHttp3CookieDao dao = sDaoSession.getOkHttp3CookieDao();
|
||||
|
||||
OkHttp3CookieRaw raw = new OkHttp3CookieRaw();
|
||||
|
||||
@@ -25,6 +25,7 @@ import android.support.v4.app.FragmentActivity;
|
||||
import android.view.View;
|
||||
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.ui.MainActivity;
|
||||
import com.hippo.yorozuya.IntList;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -113,6 +114,17 @@ public class SceneFragment extends Fragment {
|
||||
|
||||
view.setTag(R.id.fragment_tag, getTag());
|
||||
view.setBackgroundColor(getContext().getResources().getColor(R.color.background_light));
|
||||
|
||||
// Notify
|
||||
((MainActivity) getActivity()).onSceneViewCreated(this, savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
|
||||
// Notify
|
||||
((MainActivity) getActivity()).onSceneViewDestroyed(this);
|
||||
}
|
||||
|
||||
void addRequest(String requestSceneTag, int requestCode) {
|
||||
|
||||
@@ -30,6 +30,7 @@ import com.hippo.ehviewer.R;
|
||||
import com.hippo.yorozuya.IntIdGenerator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
public abstract class StageActivity extends AppCompatActivity {
|
||||
|
||||
@@ -44,7 +45,7 @@ public abstract class StageActivity extends AppCompatActivity {
|
||||
|
||||
// TODO ArrayList or LinkedList
|
||||
private ArrayList<String> mSceneTagList = new ArrayList<>();
|
||||
private IntIdGenerator mIdGenerator = new IntIdGenerator();
|
||||
private final AtomicInteger mIdGenerator = new AtomicInteger();
|
||||
|
||||
private int mStageId = IntIdGenerator.INVALID_ID;
|
||||
|
||||
@@ -81,7 +82,7 @@ public abstract class StageActivity extends AppCompatActivity {
|
||||
if (savedInstanceState != null) {
|
||||
mStageId = savedInstanceState.getInt(KEY_STAGE_ID, IntIdGenerator.INVALID_ID);
|
||||
mSceneTagList = savedInstanceState.getStringArrayList(KEY_SCENE_TAG_LIST);
|
||||
mIdGenerator.setNextId(savedInstanceState.getInt(KEY_NEXT_ID));
|
||||
mIdGenerator.lazySet(savedInstanceState.getInt(KEY_NEXT_ID));
|
||||
}
|
||||
|
||||
if (mStageId == IntIdGenerator.INVALID_ID) {
|
||||
@@ -97,6 +98,12 @@ public abstract class StageActivity extends AppCompatActivity {
|
||||
((SceneApplication) getApplicationContext()).unregisterStageActivity(mStageId);
|
||||
}
|
||||
|
||||
public void onSceneViewCreated(SceneFragment scene, Bundle savedInstanceState) {
|
||||
}
|
||||
|
||||
public void onSceneViewDestroyed(SceneFragment scene) {
|
||||
}
|
||||
|
||||
protected void onRegister(int id) {
|
||||
mStageId = id;
|
||||
}
|
||||
@@ -165,7 +172,7 @@ public abstract class StageActivity extends AppCompatActivity {
|
||||
newScene.setArguments(args);
|
||||
|
||||
// Create new scene tag
|
||||
newTag = Integer.toString(mIdGenerator.nextId());
|
||||
newTag = Integer.toString(mIdGenerator.getAndIncrement());
|
||||
|
||||
// Add new tag to list
|
||||
mSceneTagList.add(newTag);
|
||||
@@ -359,6 +366,6 @@ public abstract class StageActivity extends AppCompatActivity {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putInt(KEY_STAGE_ID, mStageId);
|
||||
outState.putStringArrayList(KEY_SCENE_TAG_LIST, mSceneTagList);
|
||||
outState.putInt(KEY_NEXT_ID, mIdGenerator.nextId());
|
||||
outState.putInt(KEY_NEXT_ID, mIdGenerator.getAndIncrement());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.util;
|
||||
|
||||
import android.database.Cursor;
|
||||
import android.database.SQLException;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SqlUtils {
|
||||
|
||||
public static void exeSQLSafely(SQLiteDatabase db, String sql) {
|
||||
try {
|
||||
db.execSQL(sql);
|
||||
} catch (SQLException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
|
||||
public static void dropTable(SQLiteDatabase db, String tableName) {
|
||||
exeSQLSafely(db, "DROP TABLE IF EXISTS " + tableName);
|
||||
}
|
||||
|
||||
public static void dropAllTable(SQLiteDatabase db) {
|
||||
List<String> tables = new ArrayList<String>();
|
||||
Cursor cursor = db.rawQuery("SELECT * FROM sqlite_master WHERE type='table';", null);
|
||||
cursor.moveToFirst();
|
||||
while (!cursor.isAfterLast()) {
|
||||
String tableName = cursor.getString(1);
|
||||
if (!tableName.equals("android_metadata") &&
|
||||
!tableName.equals("sqlite_sequence"))
|
||||
tables.add(tableName);
|
||||
cursor.moveToNext();
|
||||
}
|
||||
cursor.close();
|
||||
|
||||
for(String tableName : tables) {
|
||||
dropTable(db, tableName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,351 @@
|
||||
/*
|
||||
* Copyright (C) 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.widget;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.PropertyValuesHolder;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.hippo.anani.AnimationUtils;
|
||||
import com.hippo.anani.SimpleAnimatorListener;
|
||||
import com.hippo.ehviewer.R;
|
||||
|
||||
public class FabLayout extends ViewGroup implements View.OnClickListener {
|
||||
|
||||
private static final long ANIMATE_TIME = 300L;
|
||||
|
||||
private static final String STATE_KEY_SUPER = "super";
|
||||
private static final String STATE_KEY_AUTO_CANCEL = "auto_cancel";
|
||||
private static final String STATE_KEY_EXPANDED = "expanded";
|
||||
|
||||
private int mInterval;
|
||||
|
||||
private boolean mFirst = true;
|
||||
private boolean mExpanded = false;
|
||||
private boolean mAutoCancel = true;
|
||||
private float mMainFabCenterY = -1f;
|
||||
|
||||
private OnExpandListener mOnExpandListener;
|
||||
|
||||
public FabLayout(Context context) {
|
||||
super(context);
|
||||
init(context);
|
||||
}
|
||||
|
||||
public FabLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(context);
|
||||
}
|
||||
|
||||
public FabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
init(context);
|
||||
}
|
||||
|
||||
private void init(Context context) {
|
||||
setSoundEffectsEnabled(false);
|
||||
mInterval = context.getResources().getDimensionPixelOffset(R.dimen.keyline_margin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addView(@NonNull View child, int index, ViewGroup.LayoutParams params) {
|
||||
if (!(child instanceof FloatingActionButton)) {
|
||||
throw new IllegalStateException("FloatingActionBarLayout should only " +
|
||||
"contain FloatingActionButton, but try to add "+ child.getClass().getName());
|
||||
}
|
||||
super.addView(child, index, params);
|
||||
}
|
||||
|
||||
public FloatingActionButton getPrimaryFab() {
|
||||
View v = getChildAt(getChildCount() - 1);
|
||||
if (v == null) {
|
||||
return null;
|
||||
} else {
|
||||
return (FloatingActionButton) v;
|
||||
}
|
||||
}
|
||||
|
||||
public int getSecondaryFabCount() {
|
||||
return Math.max(0, getChildCount() - 1);
|
||||
}
|
||||
|
||||
public FloatingActionButton getSecondaryFabAt(int index) {
|
||||
if (index < 0 || index >= getSecondaryFabCount()) {
|
||||
return null;
|
||||
}
|
||||
return (FloatingActionButton) getChildAt(index);
|
||||
}
|
||||
|
||||
private int getChildMeasureSpec(int parentMeasureSpec) {
|
||||
int parentMode = MeasureSpec.getMode(parentMeasureSpec);
|
||||
int parentSize = MeasureSpec.getSize(parentMeasureSpec);
|
||||
int childMode;
|
||||
int childSize;
|
||||
switch (parentMode) {
|
||||
default:
|
||||
case MeasureSpec.AT_MOST:
|
||||
case MeasureSpec.EXACTLY:
|
||||
childMode = MeasureSpec.AT_MOST;
|
||||
childSize = parentSize;
|
||||
break;
|
||||
case MeasureSpec.UNSPECIFIED:
|
||||
childMode = MeasureSpec.UNSPECIFIED;
|
||||
childSize = parentSize;
|
||||
}
|
||||
return MeasureSpec.makeMeasureSpec(childSize, childMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
if (mFirst) {
|
||||
mFirst = false;
|
||||
boolean expanded = mExpanded;
|
||||
int count = getChildCount() - 1;
|
||||
for (int i = 0; i < count; i++) {
|
||||
getChildAt(i).setVisibility(expanded ? View.VISIBLE : View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec);
|
||||
int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec);
|
||||
measureChildren(childWidthMeasureSpec, childHeightMeasureSpec);
|
||||
|
||||
int maxWidth = 0;
|
||||
int maxHeight = 0;
|
||||
boolean firstChild = true;
|
||||
int count = getChildCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
View child = getChildAt(i);
|
||||
if (child.getVisibility() == View.GONE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
maxWidth = Math.max(maxWidth, child.getMeasuredWidth());
|
||||
maxHeight = maxHeight + child.getMeasuredHeight();
|
||||
if (firstChild) {
|
||||
firstChild = false;
|
||||
} else {
|
||||
maxHeight += mInterval;
|
||||
}
|
||||
}
|
||||
|
||||
// Account for padding too
|
||||
maxWidth += getPaddingLeft() + getPaddingRight();
|
||||
maxHeight += getPaddingTop() + getPaddingBottom();
|
||||
|
||||
// Check against minimum height and width
|
||||
maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
|
||||
maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
|
||||
|
||||
setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, 0),
|
||||
resolveSizeAndState(maxHeight, heightMeasureSpec, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
int interval = mInterval;
|
||||
int centerX = 0;
|
||||
int bottom = getMeasuredHeight() - getPaddingBottom();
|
||||
int count = getChildCount();
|
||||
int i = count;
|
||||
while(--i >= 0) {
|
||||
View child = getChildAt(i);
|
||||
if (child.getVisibility() == View.GONE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int childWidth = child.getMeasuredWidth();
|
||||
int childHeight = child.getMeasuredHeight();
|
||||
int right;
|
||||
if (i == count - 1) {
|
||||
right = getMeasuredWidth() - getPaddingRight();
|
||||
} else {
|
||||
right = centerX + (childWidth / 2);
|
||||
}
|
||||
child.layout(right - childWidth, bottom - childHeight, right, bottom);
|
||||
|
||||
if (i == count - 1) {
|
||||
centerX = right - (childWidth / 2);
|
||||
mMainFabCenterY = bottom - (childHeight / 2f);
|
||||
}
|
||||
|
||||
bottom -= (childHeight + interval);
|
||||
}
|
||||
}
|
||||
|
||||
public void setOnExpandListener(OnExpandListener listener) {
|
||||
mOnExpandListener = listener;
|
||||
}
|
||||
|
||||
public void setAutoCancel(boolean autoCancel) {
|
||||
if (mAutoCancel != autoCancel) {
|
||||
mAutoCancel = autoCancel;
|
||||
|
||||
if (mExpanded) {
|
||||
if (autoCancel) {
|
||||
setOnClickListener(this);
|
||||
} else {
|
||||
setClickable(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void toggle() {
|
||||
setExpanded(!mExpanded);
|
||||
}
|
||||
|
||||
public boolean isExpanded() {
|
||||
return mExpanded;
|
||||
}
|
||||
|
||||
public void setExpanded(boolean expanded) {
|
||||
setExpanded(expanded, true);
|
||||
}
|
||||
|
||||
public void setExpanded(boolean expanded, boolean animation) {
|
||||
if (mExpanded != expanded) {
|
||||
mExpanded = expanded;
|
||||
|
||||
if (mAutoCancel) {
|
||||
if (expanded) {
|
||||
setOnClickListener(this);
|
||||
} else {
|
||||
setClickable(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (mMainFabCenterY == -1f) {
|
||||
// It is before first onLayout
|
||||
int count = getChildCount() - 1;
|
||||
for (int i = 0; i < count; i++) {
|
||||
getChildAt(i).setVisibility(expanded ? View.VISIBLE : View.INVISIBLE);
|
||||
}
|
||||
} else {
|
||||
int count = getChildCount() - 1;
|
||||
for (int i = 0; i < count; i++) {
|
||||
View child = getChildAt(i);
|
||||
if (animation) {
|
||||
setChildAnimation(child, expanded);
|
||||
} else {
|
||||
child.setVisibility(expanded ? View.VISIBLE : View.INVISIBLE);
|
||||
if (expanded) {
|
||||
child.setAlpha(1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mOnExpandListener != null) {
|
||||
mOnExpandListener.onExpand(expanded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setChildAnimation(final View child, final boolean expanded) {
|
||||
float startTranslationY;
|
||||
float endTranslationY;
|
||||
float startAlpha;
|
||||
float endAlpha;
|
||||
Interpolator interpolator;
|
||||
if (expanded) {
|
||||
startTranslationY = mMainFabCenterY -
|
||||
(child.getTop() + (child.getHeight() / 2));
|
||||
endTranslationY = 0f;
|
||||
startAlpha = 0f;
|
||||
endAlpha = 1f;
|
||||
interpolator = AnimationUtils.FAST_SLOW_INTERPOLATOR;
|
||||
} else {
|
||||
startTranslationY = 0f;
|
||||
endTranslationY = mMainFabCenterY -
|
||||
(child.getTop() + (child.getHeight() / 2));
|
||||
startAlpha = 1f;
|
||||
endAlpha = 0f;
|
||||
interpolator = AnimationUtils.SLOW_FAST_INTERPOLATOR;
|
||||
}
|
||||
|
||||
PropertyValuesHolder translationYPvh = PropertyValuesHolder.ofFloat(
|
||||
"translationY", startTranslationY, endTranslationY);
|
||||
PropertyValuesHolder alphaPvh = PropertyValuesHolder.ofFloat(
|
||||
"alpha", startAlpha, endAlpha);
|
||||
ObjectAnimator oa = ObjectAnimator.ofPropertyValuesHolder(child, translationYPvh, alphaPvh);
|
||||
oa.setDuration(ANIMATE_TIME);
|
||||
oa.setInterpolator(interpolator);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||
oa.setAutoCancel(true);
|
||||
}
|
||||
oa.addListener(new SimpleAnimatorListener() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
if (expanded) {
|
||||
child.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (!expanded) {
|
||||
child.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
});
|
||||
oa.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
setExpanded(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void dispatchSetPressed(boolean pressed) {
|
||||
// Don't dispatch it to children
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parcelable onSaveInstanceState() {
|
||||
final Bundle state = new Bundle();
|
||||
state.putParcelable(STATE_KEY_SUPER, super.onSaveInstanceState());
|
||||
state.putBoolean(STATE_KEY_AUTO_CANCEL, mAutoCancel);
|
||||
state.putBoolean(STATE_KEY_EXPANDED, mExpanded);
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreInstanceState(Parcelable state) {
|
||||
if (state instanceof Bundle) {
|
||||
final Bundle savedState = (Bundle) state;
|
||||
super.onRestoreInstanceState(savedState.getParcelable(STATE_KEY_SUPER));
|
||||
setAutoCancel(savedState.getBoolean(STATE_KEY_AUTO_CANCEL));
|
||||
setExpanded(savedState.getBoolean(STATE_KEY_EXPANDED), false);
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnExpandListener {
|
||||
void onExpand(boolean expanded);
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 179 B |
|
After Width: | Height: | Size: 278 B |
|
After Width: | Height: | Size: 104 B |
|
After Width: | Height: | Size: 183 B |
|
After Width: | Height: | Size: 251 B |
|
After Width: | Height: | Size: 134 B |
|
After Width: | Height: | Size: 207 B |
|
After Width: | Height: | Size: 85 B |
|
After Width: | Height: | Size: 150 B |
|
After Width: | Height: | Size: 196 B |
|
After Width: | Height: | Size: 198 B |
|
After Width: | Height: | Size: 340 B |
|
After Width: | Height: | Size: 115 B |
|
After Width: | Height: | Size: 208 B |
|
After Width: | Height: | Size: 298 B |
|
After Width: | Height: | Size: 255 B |
|
After Width: | Height: | Size: 488 B |
|
After Width: | Height: | Size: 133 B |
|
After Width: | Height: | Size: 271 B |
|
After Width: | Height: | Size: 392 B |
@@ -15,10 +15,8 @@
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<merge
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<com.hippo.gl.view.GLRootView
|
||||
android:id="@+id/gl_root_view"
|
||||
@@ -80,4 +78,4 @@
|
||||
android:gravity="center_horizontal"/>
|
||||
|
||||
</com.hippo.ehviewer.widget.SliderPanel>
|
||||
</FrameLayout>
|
||||
</merge>
|
||||
@@ -38,4 +38,11 @@
|
||||
app:headerLayout="@layout/nav_header_main"
|
||||
app:menu="@menu/nav_drawer_main"/>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/right_drawer"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="right"
|
||||
android:minWidth="320dp"/>
|
||||
|
||||
</android.support.v4.widget.DrawerLayout>
|
||||
@@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2016 Hippo Seven
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/fragment_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
@@ -0,0 +1,143 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2016 Hippo Seven
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/card_white_2dp">
|
||||
|
||||
<com.hippo.ehviewer.widget.ThumbImageView
|
||||
android:id="@+id/thumb"
|
||||
android:layout_width="@dimen/list_thumb_width"
|
||||
android:layout_height="@dimen/list_thumb_height"/>
|
||||
|
||||
<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>
|
||||
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright 2016 Hippo Seven
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.hippo.easyrecyclerview.EasyRecyclerView
|
||||
android:id="@+id/recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingBottom="@dimen/corner_fab_margin"
|
||||
android:clipToPadding="false"/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/tip"
|
||||
android:layout_width="240dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.hippo.widget.SimpleImageView
|
||||
android:id="@+id/tip_image"
|
||||
android:layout_width="168dp"
|
||||
android:layout_height="168dp"
|
||||
android:layout_gravity="center_horizontal"/>
|
||||
|
||||
<TextView
|
||||
style="@style/TextAppearance.AppCompat.Medium"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:gravity="center_horizontal"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="16dp"
|
||||
android:text="@string/no_download_info"/>
|
||||
|
||||
</LinearLayout>
|
||||
</FrameLayout>
|
||||
@@ -53,6 +53,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/username"
|
||||
android:imeOptions="actionNext"
|
||||
android:inputType="text"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true"/>
|
||||
|
||||
@@ -172,6 +172,22 @@
|
||||
<string name="gallery_previews">画廊预览</string>
|
||||
<string name="go_to">跳页</string>
|
||||
|
||||
<!-- Download -->
|
||||
<string name="no_download_info">无下载项目</string>
|
||||
<string name="download_state_none">未启动</string>
|
||||
<string name="download_state_wait">等待中</string>
|
||||
<string name="download_state_failed">失败</string>
|
||||
<string name="download_state_failed_2">%d 未完成</string>
|
||||
<string name="download_state_finish">完成</string>
|
||||
<string name="stat_509_alert_title">509 警告</string>
|
||||
<string name="stat_509_alert_text">图片配额已用尽。请停止下载,休息一下。</string>
|
||||
<string name="stat_download_done_title">下载结束</string>
|
||||
<string name="stat_download_done_text_succeeded">%d 成功</string>
|
||||
<string name="stat_download_done_text_failed">%d 失败</string>
|
||||
<string name="stat_download_done_text_mix">%1$d 成功,%2$d 失败</string>
|
||||
<string name="stat_download_done_line_succeeded">成功:%s</string>
|
||||
<string name="stat_download_done_line_failed">失败:%s</string>
|
||||
|
||||
<!-- Gallery Activity -->
|
||||
<string name="page_menu_title">第 %d 页</string>
|
||||
<string name="page_menu_refresh">@string/refresh</string>
|
||||
|
||||
@@ -172,6 +172,22 @@
|
||||
<string name="gallery_previews">畫廊預覽</string>
|
||||
<string name="go_to">跳頁</string>
|
||||
|
||||
<!-- Download -->
|
||||
<string name="no_download_info">無下載項目</string>
|
||||
<string name="download_state_none">未啟動</string>
|
||||
<string name="download_state_wait">等待中</string>
|
||||
<string name="download_state_failed">失敗</string>
|
||||
<string name="download_state_failed_2">%d 未完成</string>
|
||||
<string name="download_state_finish">完成</string>
|
||||
<string name="stat_509_alert_title">509 警告</string>
|
||||
<string name="stat_509_alert_text">圖片配額已用盡。請停止下載,休息一下。</string>
|
||||
<string name="stat_download_done_title">下載結束</string>
|
||||
<string name="stat_download_done_text_succeeded">%d 成功</string>
|
||||
<string name="stat_download_done_text_failed">%d 失敗</string>
|
||||
<string name="stat_download_done_text_mix">%1$d 成功,%2$d 失敗</string>
|
||||
<string name="stat_download_done_line_succeeded">成功:%s</string>
|
||||
<string name="stat_download_done_line_failed">失敗:%s</string>
|
||||
|
||||
<!-- Gallery Activity -->
|
||||
<string name="page_menu_title">第 %d 頁</string>
|
||||
<string name="page_menu_refresh">@string/refresh</string>
|
||||
@@ -191,6 +207,21 @@
|
||||
<string name="settings_read_reading_direction_left_to_right">從左至右</string>
|
||||
<string name="settings_read_reading_direction_right_to_Left">從右至左</string>
|
||||
<string name="settings_read_reading_direction_top_to_bottom">從上至下</string>
|
||||
<string name="settings_read_page_scaling_title">頁面縮放</string>
|
||||
<string name="settings_read_page_scaling_actual_size">原始尺寸</string>
|
||||
<string name="settings_read_page_scaling_fit_to_width">匹配寬度</string>
|
||||
<string name="settings_read_page_scaling_fit_to_height">匹配長度</string>
|
||||
<string name="settings_read_page_scaling_fit_to_screen">匹配屏幕</string>
|
||||
<string name="settings_read_page_scaling_fixed_scale">固定縮放</string>
|
||||
<string name="settings_read_start_position_title">開頁位置</string>
|
||||
<string name="settings_read_start_position_top_left">左上角</string>
|
||||
<string name="settings_read_start_position_top_right">右上角</string>
|
||||
<string name="settings_read_start_position_bottom_left">左下角</string>
|
||||
<string name="settings_read_start_position_bottom_right">右下角</string>
|
||||
<string name="settings_read_start_position_center">中心</string>
|
||||
<string name="settings_read_keep_screen_on_title">屏幕常亮</string>
|
||||
<string name="settings_read_show_clock_title">顯示時鐘</string>
|
||||
<string name="settings_read_show_battery_title">顯示電量</string>
|
||||
<string name="settings_read_volume_page_title">使用音量鍵翻頁</string>
|
||||
|
||||
<!-- Progress Scene -->
|
||||
|
||||
@@ -172,6 +172,22 @@
|
||||
<string name="gallery_previews">畫廊預覽</string>
|
||||
<string name="go_to">跳頁</string>
|
||||
|
||||
<!-- Download -->
|
||||
<string name="no_download_info">無下載項目</string>
|
||||
<string name="download_state_none">未啟動</string>
|
||||
<string name="download_state_wait">等待中</string>
|
||||
<string name="download_state_failed">失敗</string>
|
||||
<string name="download_state_failed_2">%d 未完成</string>
|
||||
<string name="download_state_finish">完成</string>
|
||||
<string name="stat_509_alert_title">509 警告</string>
|
||||
<string name="stat_509_alert_text">圖片配額已用盡。請停止下載,休息一下。</string>
|
||||
<string name="stat_download_done_title">下載結束</string>
|
||||
<string name="stat_download_done_text_succeeded">%d 成功</string>
|
||||
<string name="stat_download_done_text_failed">%d 失敗</string>
|
||||
<string name="stat_download_done_text_mix">%1$d 成功,%2$d 失敗</string>
|
||||
<string name="stat_download_done_line_succeeded">成功:%s</string>
|
||||
<string name="stat_download_done_line_failed">失敗:%s</string>
|
||||
|
||||
<!-- Gallery Activity -->
|
||||
<string name="page_menu_title">第 %d 頁</string>
|
||||
<string name="page_menu_refresh">@string/refresh</string>
|
||||
@@ -191,6 +207,21 @@
|
||||
<string name="settings_read_reading_direction_left_to_right">從左至右</string>
|
||||
<string name="settings_read_reading_direction_right_to_Left">從右至左</string>
|
||||
<string name="settings_read_reading_direction_top_to_bottom">從上至下</string>
|
||||
<string name="settings_read_page_scaling_title">頁面縮放</string>
|
||||
<string name="settings_read_page_scaling_actual_size">原始尺寸</string>
|
||||
<string name="settings_read_page_scaling_fit_to_width">匹配寬度</string>
|
||||
<string name="settings_read_page_scaling_fit_to_height">匹配長度</string>
|
||||
<string name="settings_read_page_scaling_fit_to_screen">匹配螢幕</string>
|
||||
<string name="settings_read_page_scaling_fixed_scale">固定縮放</string>
|
||||
<string name="settings_read_start_position_title">開頁位置</string>
|
||||
<string name="settings_read_start_position_top_left">左上角</string>
|
||||
<string name="settings_read_start_position_top_right">右上角</string>
|
||||
<string name="settings_read_start_position_bottom_left">左下角</string>
|
||||
<string name="settings_read_start_position_bottom_right">右下角</string>
|
||||
<string name="settings_read_start_position_center">中心</string>
|
||||
<string name="settings_read_keep_screen_on_title">螢幕常亮</string>
|
||||
<string name="settings_read_show_clock_title">顯示時鐘</string>
|
||||
<string name="settings_read_show_battery_title">顯示電量</string>
|
||||
<string name="settings_read_volume_page_title">使用音量鍵翻頁</string>
|
||||
|
||||
<!-- Progress Scene -->
|
||||
|
||||
@@ -212,6 +212,22 @@
|
||||
<string name="gallery_previews">Gallery Previews</string>
|
||||
<string name="go_to">Go to</string>
|
||||
|
||||
<!-- Download -->
|
||||
<string name="no_download_info">No download items</string>
|
||||
<string name="download_state_none">Idle</string>
|
||||
<string name="download_state_wait">Waiting</string>
|
||||
<string name="download_state_failed">Failed</string>
|
||||
<string name="download_state_failed_2">%d incomplete</string>
|
||||
<string name="download_state_finish">Done</string>
|
||||
<string name="stat_509_alert_title">509 Alert</string>
|
||||
<string name="stat_509_alert_text">Image limit is reached. Please stop download and have a relax.</string>
|
||||
<string name="stat_download_done_title">Download Finished</string>
|
||||
<string name="stat_download_done_text_succeeded">%d succeeded</string>
|
||||
<string name="stat_download_done_text_failed">%d failed</string>
|
||||
<string name="stat_download_done_text_mix">%1$d succeeded, %2$d failed</string>
|
||||
<string name="stat_download_done_line_succeeded">Succeeded: %s</string>
|
||||
<string name="stat_download_done_line_failed">Failed: %s</string>
|
||||
|
||||
<!-- Gallery Activity -->
|
||||
<string name="page_menu_title">Page %d</string>
|
||||
<string name="page_menu_refresh">@string/refresh</string>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<!-- TextAppearance -->
|
||||
<style name="TextAppearance" parent="TextAppearance.AppCompat">
|
||||
@@ -129,4 +129,8 @@
|
||||
<item name="indicatorColor">@color/divider_dark</item>
|
||||
</style>
|
||||
|
||||
<style name="Widget.Design.FloatingActionButton.Mini">
|
||||
<item name="fabSize">mini</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright 2016 Hippo Seven
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.hippo.ehviewer.daogenerator;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import de.greenrobot.daogenerator.DaoGenerator;
|
||||
import de.greenrobot.daogenerator.Entity;
|
||||
import de.greenrobot.daogenerator.Schema;
|
||||
|
||||
public class EhDaoGenerator {
|
||||
|
||||
private static final String PACKAGE = "com.hippo.ehviewer.dao";
|
||||
private static final String OUT_DIR = "../app/src/main/java-gen";
|
||||
private static final String DELETE_DIR = "../app/src/main/java-gen/com/hippo/ehviewer/dao";
|
||||
|
||||
private static final int VERSION = 1;
|
||||
|
||||
public static void generate() throws Exception {
|
||||
Utilities.deleteContents(new File(DELETE_DIR));
|
||||
File outDir = new File(OUT_DIR);
|
||||
outDir.delete();
|
||||
outDir.mkdirs();
|
||||
|
||||
Schema schema = new Schema(VERSION, PACKAGE);
|
||||
addGalleryInfo(schema);
|
||||
addDownloadInfo(schema);
|
||||
addDownloadLabel(schema);
|
||||
addHistoryInfo(schema);
|
||||
addQuickSearch(schema);
|
||||
addLocalFavorite(schema);
|
||||
new DaoGenerator().generateAll(schema, OUT_DIR);
|
||||
}
|
||||
|
||||
private static void addGalleryInfo(Schema schema) {
|
||||
Entity entity = schema.addEntity("GalleryInfoRaw");
|
||||
entity.setTableName("GALLERY_INFO");
|
||||
entity.setClassNameDao("GalleryInfoDao");
|
||||
entity.addLongProperty("gid").primaryKey();
|
||||
entity.addStringProperty("token");
|
||||
entity.addStringProperty("title");
|
||||
entity.addStringProperty("posted");
|
||||
entity.addIntProperty("category");
|
||||
entity.addStringProperty("thumb");
|
||||
entity.addStringProperty("uploader");
|
||||
entity.addFloatProperty("rating");
|
||||
entity.addIntProperty("reference");
|
||||
}
|
||||
|
||||
private static void addDownloadInfo(Schema schema) {
|
||||
Entity entity = schema.addEntity("DownloadInfoRaw");
|
||||
entity.setTableName("DOWNLOAD_INFO");
|
||||
entity.setClassNameDao("DownloadInfoDao");
|
||||
entity.addLongProperty("gid").primaryKey();
|
||||
entity.addIntProperty("state");
|
||||
entity.addIntProperty("legacy");
|
||||
entity.addLongProperty("date");
|
||||
entity.addStringProperty("label");
|
||||
}
|
||||
|
||||
private static void addDownloadLabel(Schema schema) {
|
||||
Entity entity = schema.addEntity("DownloadLabelRaw");
|
||||
entity.setTableName("DOWNLOAD_LABEL");
|
||||
entity.setClassNameDao("DownloadLabelDao");
|
||||
entity.addIdProperty();
|
||||
entity.addStringProperty("label");
|
||||
entity.addLongProperty("time");
|
||||
}
|
||||
|
||||
private static void addHistoryInfo(Schema schema) {
|
||||
Entity entity = schema.addEntity("HistoryInfoRaw");
|
||||
entity.setTableName("HISTORY_INFO");
|
||||
entity.setClassNameDao("HistoryInfoDao");
|
||||
entity.addLongProperty("gid").primaryKey();
|
||||
entity.addIntProperty("mode");
|
||||
entity.addLongProperty("date");
|
||||
}
|
||||
|
||||
private static void addQuickSearch(Schema schema) {
|
||||
Entity entity = schema.addEntity("QuickSearchRaw");
|
||||
entity.setTableName("QUICK_SEARCH");
|
||||
entity.setClassNameDao("QuickSearchDao");
|
||||
entity.addIdProperty();
|
||||
entity.addStringProperty("name");
|
||||
entity.addIntProperty("mode");
|
||||
entity.addIntProperty("category");
|
||||
entity.addStringProperty("keyword");
|
||||
entity.addIntProperty("advanceSearch");
|
||||
entity.addIntProperty("minRating");
|
||||
entity.addLongProperty("date");
|
||||
}
|
||||
|
||||
private static void addLocalFavorite(Schema schema) {
|
||||
Entity entity = schema.addEntity("LocalFavoriteRaw");
|
||||
entity.setTableName("LOCAL_FAVORITE");
|
||||
entity.setClassNameDao("LocalFavoriteDao");
|
||||
entity.addLongProperty("gid").primaryKey();
|
||||
entity.addLongProperty("date");
|
||||
}
|
||||
}
|
||||
@@ -20,5 +20,6 @@ public class Main {
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
CookieDaoGenerator.generate();
|
||||
EhDaoGenerator.generate();
|
||||
}
|
||||
}
|
||||