Add FavoritesScene
This commit is contained in:
1 parent
f402dd92b5
commit
35e48cb79b
32 files changed
+1730
-47
No files matched your search
@@ -77,4 +77,5 @@ dependencies {
|
||||
compile 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:0.8.6'
|
||||
compile 'de.greenrobot:greendao:2.0.0'
|
||||
compile 'org.ccil.cowan.tagsoup:tagsoup:1.2.1'
|
||||
compile 'org.jsoup:jsoup:1.8.3'
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Target({ElementType.METHOD})
|
||||
public @interface Implemented {
|
||||
Class value();
|
||||
}
|
||||
@@ -24,9 +24,11 @@ import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
import com.hippo.ehviewer.client.EhConfig;
|
||||
import com.hippo.ehviewer.client.data.FavListUrlBuilder;
|
||||
import com.hippo.ehviewer.gallery.gl.GalleryView;
|
||||
import com.hippo.ehviewer.gallery.gl.ImageView;
|
||||
import com.hippo.unifile.UniFile;
|
||||
import com.hippo.yorozuya.AssertUtils;
|
||||
import com.hippo.yorozuya.NumberUtils;
|
||||
|
||||
public class Settings {
|
||||
@@ -117,17 +119,6 @@ public class Settings {
|
||||
putBoolean(KEY_SHOW_WARNING, value);
|
||||
}
|
||||
|
||||
private 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);
|
||||
}
|
||||
|
||||
private static final String KEY_REMOVE_IMAGE_FILES = "include_pic";
|
||||
private static final boolean DEFAULT_REMOVE_IMAGE_FILES = true;
|
||||
|
||||
@@ -236,6 +227,9 @@ public class Settings {
|
||||
putBoolean(KEY_VOLUME_PAGE, value);
|
||||
}
|
||||
|
||||
/********************
|
||||
****** Download
|
||||
********************/
|
||||
public static final String KEY_DOWNLOAD_SAVE_SCHEME = "image_scheme";
|
||||
public static final String KEY_DOWNLOAD_SAVE_AUTHORITY = "image_authority";
|
||||
public static final String KEY_DOWNLOAD_SAVE_PATH = "image_path";
|
||||
@@ -267,4 +261,81 @@ public class Settings {
|
||||
putString(KEY_DOWNLOAD_SAVE_QUERY, uri.getEncodedQuery());
|
||||
putString(KEY_DOWNLOAD_SAVE_FRAGMENT, uri.getEncodedFragment());
|
||||
}
|
||||
|
||||
private 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);
|
||||
}
|
||||
|
||||
/********************
|
||||
****** Favorites
|
||||
********************/
|
||||
public static final String KEY_FAV_CAT_0 = "fav_cat_0";
|
||||
public static final String KEY_FAV_CAT_1 = "fav_cat_1";
|
||||
public static final String KEY_FAV_CAT_2 = "fav_cat_2";
|
||||
public static final String KEY_FAV_CAT_3 = "fav_cat_3";
|
||||
public static final String KEY_FAV_CAT_4 = "fav_cat_4";
|
||||
public static final String KEY_FAV_CAT_5 = "fav_cat_5";
|
||||
public static final String KEY_FAV_CAT_6 = "fav_cat_6";
|
||||
public static final String KEY_FAV_CAT_7 = "fav_cat_7";
|
||||
public static final String KEY_FAV_CAT_8 = "fav_cat_8";
|
||||
public static final String KEY_FAV_CAT_9 = "fav_cat_9";
|
||||
public static final String DEFAULT_FAV_CAT_0 = "Favorites 0";
|
||||
public static final String DEFAULT_FAV_CAT_1 = "Favorites 1";
|
||||
public static final String DEFAULT_FAV_CAT_2 = "Favorites 2";
|
||||
public static final String DEFAULT_FAV_CAT_3 = "Favorites 3";
|
||||
public static final String DEFAULT_FAV_CAT_4 = "Favorites 4";
|
||||
public static final String DEFAULT_FAV_CAT_5 = "Favorites 5";
|
||||
public static final String DEFAULT_FAV_CAT_6 = "Favorites 6";
|
||||
public static final String DEFAULT_FAV_CAT_7 = "Favorites 7";
|
||||
public static final String DEFAULT_FAV_CAT_8 = "Favorites 8";
|
||||
public static final String DEFAULT_FAV_CAT_9 = "Favorites 9";
|
||||
|
||||
public static String[] getFavCat() {
|
||||
String[] favCat = new String[10];
|
||||
favCat[0] = sSettingsPre.getString(KEY_FAV_CAT_0, DEFAULT_FAV_CAT_0);
|
||||
favCat[1] = sSettingsPre.getString(KEY_FAV_CAT_1, DEFAULT_FAV_CAT_1);
|
||||
favCat[2] = sSettingsPre.getString(KEY_FAV_CAT_2, DEFAULT_FAV_CAT_2);
|
||||
favCat[3] = sSettingsPre.getString(KEY_FAV_CAT_3, DEFAULT_FAV_CAT_3);
|
||||
favCat[4] = sSettingsPre.getString(KEY_FAV_CAT_4, DEFAULT_FAV_CAT_4);
|
||||
favCat[5] = sSettingsPre.getString(KEY_FAV_CAT_5, DEFAULT_FAV_CAT_5);
|
||||
favCat[6] = sSettingsPre.getString(KEY_FAV_CAT_6, DEFAULT_FAV_CAT_6);
|
||||
favCat[7] = sSettingsPre.getString(KEY_FAV_CAT_7, DEFAULT_FAV_CAT_7);
|
||||
favCat[8] = sSettingsPre.getString(KEY_FAV_CAT_8, DEFAULT_FAV_CAT_8);
|
||||
favCat[9] = sSettingsPre.getString(KEY_FAV_CAT_9, DEFAULT_FAV_CAT_9);
|
||||
return favCat;
|
||||
}
|
||||
|
||||
public static void putFavCat(String[] value) {
|
||||
AssertUtils.assertEquals(10, value.length);
|
||||
sSettingsPre.edit()
|
||||
.putString(KEY_FAV_CAT_0, value[0])
|
||||
.putString(KEY_FAV_CAT_1, value[1])
|
||||
.putString(KEY_FAV_CAT_2, value[2])
|
||||
.putString(KEY_FAV_CAT_3, value[3])
|
||||
.putString(KEY_FAV_CAT_4, value[4])
|
||||
.putString(KEY_FAV_CAT_5, value[5])
|
||||
.putString(KEY_FAV_CAT_6, value[6])
|
||||
.putString(KEY_FAV_CAT_7, value[7])
|
||||
.putString(KEY_FAV_CAT_8, value[8])
|
||||
.putString(KEY_FAV_CAT_9, value[9])
|
||||
.apply();
|
||||
}
|
||||
|
||||
private static final String KEY_RECENT_FAV_CAT = "recent_fav_cat";
|
||||
private static final int DEFAULT_RECENT_FAV_CAT = FavListUrlBuilder.FAV_CAT_ALL;
|
||||
|
||||
public static int getRecentFavCat() {
|
||||
return getInt(KEY_RECENT_FAV_CAT, DEFAULT_RECENT_FAV_CAT);
|
||||
}
|
||||
|
||||
public static void putRecentFavCat(int value) {
|
||||
putInt(KEY_RECENT_FAV_CAT, value);
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import android.os.AsyncTask;
|
||||
import com.hippo.ehviewer.EhApplication;
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo;
|
||||
import com.hippo.ehviewer.client.exception.CancelledException;
|
||||
import com.hippo.yorozuya.IntList;
|
||||
import com.hippo.yorozuya.PriorityThreadFactory;
|
||||
import com.hippo.yorozuya.SimpleHandler;
|
||||
|
||||
@@ -49,6 +50,8 @@ public class EhClient {
|
||||
public static final int METHOD_GET_RATE_GALLERY = 5;
|
||||
public static final int METHOD_GET_COMMENT_GALLERY = 6;
|
||||
public static final int METHOD_GET_GALLERY_TOKEN = 7;
|
||||
public static final int METHOD_GET_FAVORITES = 8;
|
||||
public static final int METHOD_MODIFY_FAVORITES = 9;
|
||||
|
||||
private final ThreadPoolExecutor mRequestThreadPool;
|
||||
private final OkHttpClient mOkHttpClient;
|
||||
@@ -156,6 +159,10 @@ public class EhClient {
|
||||
return EhEngine.commentGallery(this, mOkHttpClient, (String) params[0], (String) params[1]);
|
||||
case METHOD_GET_GALLERY_TOKEN:
|
||||
return EhEngine.getGalleryToken(this, mOkHttpClient, (Integer) params[0], (String) params[1], (Integer) params[2]);
|
||||
case METHOD_GET_FAVORITES:
|
||||
return EhEngine.getFavorites(this, mOkHttpClient, (String) params[0], (Boolean) params[1]);
|
||||
case METHOD_MODIFY_FAVORITES:
|
||||
return EhEngine.modifyFavorites(this, mOkHttpClient, (String) params[0], (IntList) params[1], (Integer) params[2], (Boolean) params[3]);
|
||||
default:
|
||||
return new IllegalStateException("Can't detect method " + mMethod);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,8 @@ import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.hippo.ehviewer.GetText;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.client.data.GalleryComment;
|
||||
import com.hippo.ehviewer.client.data.GalleryDetail;
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo;
|
||||
@@ -27,6 +29,7 @@ import com.hippo.ehviewer.client.data.LargePreviewSet;
|
||||
import com.hippo.ehviewer.client.exception.CancelledException;
|
||||
import com.hippo.ehviewer.client.exception.EhException;
|
||||
import com.hippo.ehviewer.client.exception.ParseException;
|
||||
import com.hippo.ehviewer.client.parser.FavoritesParser;
|
||||
import com.hippo.ehviewer.client.parser.GalleryApiParser;
|
||||
import com.hippo.ehviewer.client.parser.GalleryDetailParser;
|
||||
import com.hippo.ehviewer.client.parser.GalleryListParser;
|
||||
@@ -34,6 +37,7 @@ import com.hippo.ehviewer.client.parser.GalleryTokenApiParser;
|
||||
import com.hippo.ehviewer.client.parser.RateGalleryParser;
|
||||
import com.hippo.ehviewer.client.parser.SignInParser;
|
||||
import com.hippo.network.StatusCodeException;
|
||||
import com.hippo.yorozuya.IntList;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
@@ -76,8 +80,12 @@ public class EhEngine {
|
||||
throw new EhException("Sad Panda");
|
||||
}
|
||||
|
||||
if (e instanceof ParseException && body != null && !body.contains("<")) {
|
||||
throw new EhException(body);
|
||||
if (e instanceof ParseException) {
|
||||
if (body != null && !body.contains("<")){
|
||||
throw new EhException(body);
|
||||
} else {
|
||||
throw new EhException(GetText.getString(R.string.error_parse_error));
|
||||
}
|
||||
}
|
||||
|
||||
if (code >= 400) {
|
||||
@@ -349,4 +357,83 @@ public class EhEngine {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
public static FavoritesParser.Result getFavorites(EhClient.Task task, OkHttpClient okHttpClient,
|
||||
String url, boolean callApi) throws Exception {
|
||||
Log.d(TAG, url);
|
||||
Request request = new EhRequestBuilder(url, task.getEhConfig()).build();
|
||||
Call call = okHttpClient.newCall(request);
|
||||
|
||||
// Put call
|
||||
task.setCall(call);
|
||||
|
||||
String body = null;
|
||||
Headers headers = null;
|
||||
FavoritesParser.Result result;
|
||||
int code = -1;
|
||||
try {
|
||||
Response response = call.execute();
|
||||
code = response.code();
|
||||
headers = response.headers();
|
||||
body = response.body().string();
|
||||
result = FavoritesParser.parse(body);
|
||||
} catch (Exception e) {
|
||||
throwException(call, code, headers, body, e);
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (callApi && result.galleryInfoList.size() > 0) {
|
||||
fillGalleryListByApi(task, okHttpClient, result.galleryInfoList);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static FavoritesParser.Result modifyFavorites(EhClient.Task task, OkHttpClient okHttpClient,
|
||||
String url, IntList gidList, int dstCat, boolean callApi) throws Exception {
|
||||
String catStr;
|
||||
if (dstCat == -1) {
|
||||
catStr = "delete";
|
||||
} else if (dstCat >= 0 && dstCat <= 9) {
|
||||
catStr = "fav" + dstCat;
|
||||
} else {
|
||||
Log.w(TAG, "Invalid dstCat: " + dstCat);
|
||||
return null;
|
||||
}
|
||||
FormBody.Builder builder = new FormBody.Builder();
|
||||
builder.add("ddact", catStr);
|
||||
for (int i = 0, n = gidList.size(); i < n; i++) {
|
||||
builder.add("modifygids[]", Integer.toString(gidList.get(i)));
|
||||
}
|
||||
builder.add("apply", "Apply");
|
||||
Log.d(TAG, url);
|
||||
Request request = new EhRequestBuilder(url, task.getEhConfig())
|
||||
.post(builder.build())
|
||||
.build();
|
||||
Call call = okHttpClient.newCall(request);
|
||||
|
||||
// Put call
|
||||
task.setCall(call);
|
||||
|
||||
String body = null;
|
||||
Headers headers = null;
|
||||
FavoritesParser.Result result;
|
||||
int code = -1;
|
||||
try {
|
||||
Response response = call.execute();
|
||||
code = response.code();
|
||||
headers = response.headers();
|
||||
body = response.body().string();
|
||||
result = FavoritesParser.parse(body);
|
||||
} catch (Exception e) {
|
||||
throwException(call, code, headers, body, e);
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (callApi && result.galleryInfoList.size() > 0) {
|
||||
fillGalleryListByApi(task, okHttpClient, result.galleryInfoList);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,8 @@ public class EhUrl {
|
||||
|
||||
public static final String API_EX = HOST_EX + "api.php";
|
||||
|
||||
public static final String URL_FAVORITES = HOST_EX + "favorites.php";
|
||||
|
||||
public static String getGalleryDetailUrl(int gid, String token) {
|
||||
return getGalleryDetailUrl(gid, token, 0, false);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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.client.data;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.hippo.ehviewer.client.EhUrl;
|
||||
import com.hippo.network.UrlBuilder;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
|
||||
public class FavListUrlBuilder implements Parcelable {
|
||||
|
||||
private static final String TAG = FavListUrlBuilder.class.getSimpleName();
|
||||
public static final int FAV_CAT_ALL = -1;
|
||||
|
||||
private int mIndex;
|
||||
private String mKeyword;
|
||||
private int mFavCat = FAV_CAT_ALL;
|
||||
|
||||
public void setIndex(int index) {
|
||||
mIndex = index;
|
||||
}
|
||||
|
||||
public void setKeyword(String keyword) {
|
||||
mKeyword = keyword;
|
||||
}
|
||||
|
||||
public void setFavCat(int favCat) {
|
||||
mFavCat = favCat;
|
||||
}
|
||||
|
||||
public String getKeyword() {
|
||||
return mKeyword;
|
||||
}
|
||||
|
||||
public int getFavCat() {
|
||||
return mFavCat;
|
||||
}
|
||||
|
||||
public static boolean isValidFavCat(int favCat) {
|
||||
return favCat >= 0 && favCat <= 9;
|
||||
}
|
||||
|
||||
public String build() {
|
||||
UrlBuilder ub = new UrlBuilder(EhUrl.URL_FAVORITES);
|
||||
if (isValidFavCat(mFavCat)) {
|
||||
ub.addQuery("favcat", Integer.toString(mFavCat));
|
||||
}
|
||||
if (!TextUtils.isEmpty(mKeyword)) {
|
||||
try {
|
||||
ub.addQuery("f_search", URLEncoder.encode(mKeyword, "UTF-8"));
|
||||
ub.addQuery("f_apply", "Search+Favorites");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
Log.e(TAG, "Can't URLEncoder.encode " + mKeyword);
|
||||
}
|
||||
}
|
||||
if (mIndex > 0) {
|
||||
ub.addQuery("page", Integer.toString(mIndex));
|
||||
}
|
||||
return ub.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(this.mIndex);
|
||||
dest.writeString(this.mKeyword);
|
||||
dest.writeInt(this.mFavCat);
|
||||
}
|
||||
|
||||
public FavListUrlBuilder() {
|
||||
}
|
||||
|
||||
protected FavListUrlBuilder(Parcel in) {
|
||||
this.mIndex = in.readInt();
|
||||
this.mKeyword = in.readString();
|
||||
this.mFavCat = in.readInt();
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<FavListUrlBuilder> CREATOR = new Parcelable.Creator<FavListUrlBuilder>() {
|
||||
|
||||
@Override
|
||||
public FavListUrlBuilder createFromParcel(Parcel source) {
|
||||
return new FavListUrlBuilder(source);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FavListUrlBuilder[] newArray(int size) {
|
||||
return new FavListUrlBuilder[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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.client.parser;
|
||||
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo;
|
||||
import com.hippo.ehviewer.client.exception.ParseException;
|
||||
import com.hippo.util.JsoupUtils;
|
||||
import com.hippo.yorozuya.AssertUtils;
|
||||
|
||||
import org.jsoup.Jsoup;
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class FavoritesParser {
|
||||
|
||||
private static final Pattern LIMIT_PATTERN = Pattern.compile("Currently Used Favorite Slots: ([\\d,]+) / ([\\d,]+)");
|
||||
|
||||
public static class Result {
|
||||
public String[] catArray; // Size 10
|
||||
public int[] countArray; // Size 10
|
||||
public int current; // -1 for error
|
||||
public int limit; // -1 for error
|
||||
public int pages;
|
||||
public List<GalleryInfo> galleryInfoList;
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public static Result parse(String body) throws Exception {
|
||||
String[] catArray = new String[10];
|
||||
int[] countArray = new int[10];
|
||||
int current;
|
||||
int limit;
|
||||
|
||||
try {
|
||||
Document d = Jsoup.parse(body);
|
||||
Element ido = JsoupUtils.getElementByClass(d, "ido");
|
||||
Elements fps = ido.getElementsByClass("fp");
|
||||
// Last one is "fp fps"
|
||||
AssertUtils.assertEqualsEx(11, fps.size());
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Element fp = fps.get(i);
|
||||
countArray[i] = ParserUtils.parseInt(fp.child(0).text());
|
||||
catArray[i] = ParserUtils.trim(fp.child(2).text());
|
||||
}
|
||||
|
||||
Matcher m = LIMIT_PATTERN.matcher(body);
|
||||
if (m.find()) {
|
||||
current = ParserUtils.parseInt(m.group(1));
|
||||
limit = ParserUtils.parseInt(m.group(2));
|
||||
} else {
|
||||
current = -1;
|
||||
limit = -1;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw new ParseException("Parse favorites error", body);
|
||||
}
|
||||
|
||||
GalleryListParser.Result result = GalleryListParser.parse(body);
|
||||
|
||||
Result re = new Result();
|
||||
re.catArray = catArray;
|
||||
re.countArray = countArray;
|
||||
re.current = current;
|
||||
re.limit = limit;
|
||||
re.pages = result.pages;
|
||||
re.galleryInfoList = result.galleryInfos;
|
||||
|
||||
return re;
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,7 @@ 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.FavoritesScene;
|
||||
import com.hippo.ehviewer.ui.scene.GalleryListScene;
|
||||
import com.hippo.ehviewer.ui.scene.LoginScene;
|
||||
import com.hippo.ehviewer.ui.scene.WarningScene;
|
||||
@@ -272,7 +273,7 @@ public final class MainActivity extends StageActivity
|
||||
} else if (id == R.id.nav_whats_hot) {
|
||||
|
||||
} else if (id == R.id.nav_favourite) {
|
||||
|
||||
startScene(new Announcer(FavoritesScene.class));
|
||||
} else if (id == R.id.nav_history) {
|
||||
|
||||
} else if (id == R.id.nav_download) {
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.annotation;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Created in {@link Fragment#onCreateView(LayoutInflater, ViewGroup, Bundle)},
|
||||
* destroyed in {@link Fragment#onDestroyView()}.
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Target({ElementType.FIELD})
|
||||
public @interface DrawerLifeCircle {
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.annotation;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Created in {@link Fragment#onCreateView(LayoutInflater, ViewGroup, Bundle)},
|
||||
* destroyed in {@link Fragment#onDestroyView()}.
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Target({ElementType.FIELD})
|
||||
public @interface ViewLifeCircle {
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.annotation;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.os.Bundle;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Created in {@link Fragment#onCreate(Bundle)} or {@link Activity#onCreate(Bundle)},
|
||||
* destroyed in {@link Fragment#onDestroy()} or {@link Activity#onDestroy()}.
|
||||
*/
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@Target({ElementType.FIELD})
|
||||
public @interface WholeLifeCircle {
|
||||
}
|
||||
@@ -51,7 +51,6 @@ import com.hippo.ehviewer.EhApplication;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.dao.DownloadLabelRaw;
|
||||
import com.hippo.util.ActivityHelper;
|
||||
import com.hippo.util.DrawableManager;
|
||||
import com.hippo.view.ViewTransition;
|
||||
import com.hippo.yorozuya.ViewUtils;
|
||||
|
||||
@@ -140,7 +139,7 @@ public class DownloadLabelScene extends ToolbarScene {
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
setTitle(R.string.label);
|
||||
setNavigationIcon(DrawableManager.getDrawable(getContext(), R.drawable.v_arrow_left_dark_x24));
|
||||
setNavigationIcon(R.drawable.v_arrow_left_dark_x24);
|
||||
|
||||
// Clear nav checked item
|
||||
setNavCheckedItem(0);
|
||||
|
||||
@@ -69,7 +69,6 @@ import com.hippo.scene.TransitionHelper;
|
||||
import com.hippo.unifile.UniFile;
|
||||
import com.hippo.util.ActivityHelper;
|
||||
import com.hippo.util.ApiHelper;
|
||||
import com.hippo.util.DrawableManager;
|
||||
import com.hippo.view.ViewTransition;
|
||||
import com.hippo.widget.FabLayout;
|
||||
import com.hippo.widget.LoadImageView;
|
||||
@@ -226,7 +225,7 @@ public class DownloadScene extends ToolbarScene
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
updateTitle();
|
||||
setNavigationIcon(DrawableManager.getDrawable(getContext(), R.drawable.v_arrow_left_dark_x24));
|
||||
setNavigationIcon(R.drawable.v_arrow_left_dark_x24);
|
||||
|
||||
// Clear nav checked item
|
||||
setNavCheckedItem(R.id.nav_download);
|
||||
@@ -286,7 +285,7 @@ public class DownloadScene extends ToolbarScene
|
||||
@Override
|
||||
public View onCreateDrawerView(LayoutInflater inflater,
|
||||
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.drawer_download, container, false);
|
||||
View view = inflater.inflate(R.layout.drawer_list, container, false);
|
||||
|
||||
Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar);
|
||||
toolbar.setTitle(R.string.drawer_download_label_title);
|
||||
@@ -883,7 +882,7 @@ public class DownloadScene extends ToolbarScene
|
||||
@Override
|
||||
public boolean onTransition(Context context, FragmentTransaction transaction,
|
||||
Fragment exit, Fragment enter) {
|
||||
if (!(enter instanceof GalleryDetailScene)) {
|
||||
if (mHolder == null || !(enter instanceof GalleryDetailScene)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,9 +25,9 @@ import com.hippo.scene.StageActivity;
|
||||
|
||||
public abstract class EhCallback<E extends SceneFragment, T> implements EhClient.Callback<T> {
|
||||
|
||||
private EhApplication mApplication;
|
||||
private int mStageId;
|
||||
private String mSceneTag;
|
||||
private final EhApplication mApplication;
|
||||
private final int mStageId;
|
||||
private final String mSceneTag;
|
||||
|
||||
public EhCallback(Context context, int stageId, String sceneTag) {
|
||||
mApplication = (EhApplication) context.getApplicationContext();
|
||||
|
||||
@@ -0,0 +1,916 @@
|
||||
/*
|
||||
* 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.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.ImageSpan;
|
||||
import android.transition.TransitionInflater;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.hippo.annotation.Implemented;
|
||||
import com.hippo.drawable.DrawerArrowDrawable;
|
||||
import com.hippo.easyrecyclerview.EasyRecyclerView;
|
||||
import com.hippo.easyrecyclerview.FastScroller;
|
||||
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.EhClient;
|
||||
import com.hippo.ehviewer.client.EhRequest;
|
||||
import com.hippo.ehviewer.client.EhUtils;
|
||||
import com.hippo.ehviewer.client.data.FavListUrlBuilder;
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo;
|
||||
import com.hippo.ehviewer.client.parser.FavoritesParser;
|
||||
import com.hippo.ehviewer.ui.annotation.DrawerLifeCircle;
|
||||
import com.hippo.ehviewer.ui.annotation.ViewLifeCircle;
|
||||
import com.hippo.ehviewer.ui.annotation.WholeLifeCircle;
|
||||
import com.hippo.ehviewer.widget.SearchBar;
|
||||
import com.hippo.ehviewer.widget.SimpleRatingView;
|
||||
import com.hippo.rippleold.RippleSalon;
|
||||
import com.hippo.scene.Announcer;
|
||||
import com.hippo.scene.SceneFragment;
|
||||
import com.hippo.scene.StageActivity;
|
||||
import com.hippo.scene.TransitionHelper;
|
||||
import com.hippo.util.ApiHelper;
|
||||
import com.hippo.util.DrawableManager;
|
||||
import com.hippo.widget.ContentLayout;
|
||||
import com.hippo.widget.FabLayout;
|
||||
import com.hippo.widget.LoadImageView;
|
||||
import com.hippo.widget.SearchBarMover;
|
||||
import com.hippo.yorozuya.AssertUtils;
|
||||
import com.hippo.yorozuya.IntList;
|
||||
import com.hippo.yorozuya.ObjectUtils;
|
||||
import com.hippo.yorozuya.SimpleHandler;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FavoritesScene extends BaseScene implements
|
||||
EasyRecyclerView.OnItemClickListener, EasyRecyclerView.OnItemLongClickListener,
|
||||
FastScroller.OnDragHandlerListener, SearchBarMover.Helper, SearchBar.Helper,
|
||||
FabLayout.OnClickFabListener, EasyRecyclerView.CustomChoiceListener, AdapterView.OnItemClickListener {
|
||||
|
||||
private static final long ANIMATE_TIME = 300L;
|
||||
|
||||
private static final String KEY_URL_BUILDER = "url_builder";
|
||||
|
||||
@Nullable
|
||||
@ViewLifeCircle
|
||||
private EasyRecyclerView mRecyclerView;
|
||||
@Nullable
|
||||
@ViewLifeCircle
|
||||
private SearchBar mSearchBar;
|
||||
@Nullable
|
||||
@ViewLifeCircle
|
||||
private FabLayout mFabLayout;
|
||||
|
||||
@Nullable
|
||||
@ViewLifeCircle
|
||||
private FavoriteAdapter mAdapter;
|
||||
@Nullable
|
||||
@ViewLifeCircle
|
||||
private FavoriteHelper mHelper;
|
||||
@Nullable
|
||||
@ViewLifeCircle
|
||||
private SearchBarMover mSearchBarMover;
|
||||
@Nullable
|
||||
@ViewLifeCircle
|
||||
private DrawerArrowDrawable mLeftDrawable;
|
||||
|
||||
@Nullable
|
||||
@DrawerLifeCircle
|
||||
private ArrayAdapter<String> mDrawerAdapter;
|
||||
@Nullable
|
||||
@DrawerLifeCircle
|
||||
private List<String> mDrawerList;
|
||||
|
||||
@Nullable
|
||||
@WholeLifeCircle
|
||||
private EhClient mClient;
|
||||
@Nullable
|
||||
@WholeLifeCircle
|
||||
private String[] mFavCat;
|
||||
@Nullable
|
||||
@WholeLifeCircle
|
||||
private FavListUrlBuilder mUrlBuilder;
|
||||
|
||||
private boolean mHasFirstRefresh;
|
||||
private boolean mSearchMode;
|
||||
// Avoid unnecessary search bar update
|
||||
private String mOldFavCat;
|
||||
// Avoid unnecessary search bar update
|
||||
private String mOldKeyword;
|
||||
// For modify action
|
||||
private boolean mEnableModify;
|
||||
// For modify action
|
||||
private int mModifyFavCat;
|
||||
// For modify action
|
||||
private final IntList mModifyGidList = new IntList();
|
||||
|
||||
private final Runnable mReturnSearchBarRunnabel = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mSearchBarMover != null) {
|
||||
mSearchBarMover.returnSearchBarPosition();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// TODO Only single instance
|
||||
@Override
|
||||
public int getLaunchMode() {
|
||||
return LAUNCH_MODE_SINGLE_TOP;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mClient = EhApplication.getEhClient(getContext());
|
||||
mFavCat = Settings.getFavCat();
|
||||
|
||||
if (savedInstanceState == null) {
|
||||
onInit();
|
||||
} else {
|
||||
onRestore(savedInstanceState);
|
||||
}
|
||||
}
|
||||
|
||||
private void onInit() {
|
||||
mUrlBuilder = new FavListUrlBuilder();
|
||||
mUrlBuilder.setFavCat(Settings.getRecentFavCat());
|
||||
}
|
||||
|
||||
private void onRestore(Bundle savedInstanceState) {
|
||||
mUrlBuilder = savedInstanceState.getParcelable(KEY_URL_BUILDER);
|
||||
if (mUrlBuilder == null) {
|
||||
mUrlBuilder = new FavListUrlBuilder();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
outState.putParcelable(KEY_URL_BUILDER, mUrlBuilder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
mClient = null;
|
||||
mFavCat = null;
|
||||
mUrlBuilder = null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater,
|
||||
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
Resources resources = getResources();
|
||||
|
||||
View view = inflater.inflate(R.layout.scene_favorite, container, false);
|
||||
ContentLayout contentLayout = (ContentLayout) view.findViewById(R.id.content_layout);
|
||||
mRecyclerView = contentLayout.getRecyclerView();
|
||||
AssertUtils.assertNotNull(mRecyclerView);
|
||||
mSearchBar = (SearchBar) view.findViewById(R.id.search_bar);
|
||||
AssertUtils.assertNotNull(mSearchBar);
|
||||
mFabLayout = (FabLayout) view.findViewById(R.id.fab_layout);
|
||||
AssertUtils.assertNotNull(mFabLayout);
|
||||
|
||||
mHelper = new FavoriteHelper();
|
||||
mHelper.setEmptyString(getString(R.string.gallery_list_empty_hit)); // TODO wrong string
|
||||
contentLayout.setHelper(mHelper);
|
||||
contentLayout.getFastScroller().setOnDragHandlerListener(this);
|
||||
|
||||
mAdapter = new FavoriteAdapter();
|
||||
mRecyclerView.setAdapter(mAdapter);
|
||||
mRecyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
mRecyclerView.setSelector(RippleSalon.generateRippleDrawable(false));
|
||||
mRecyclerView.setDrawSelectorOnTop(true);
|
||||
mRecyclerView.hasFixedSize();
|
||||
mRecyclerView.setClipToPadding(false);
|
||||
mRecyclerView.setOnItemClickListener(this);
|
||||
mRecyclerView.setOnItemLongClickListener(this);
|
||||
mRecyclerView.setChoiceMode(EasyRecyclerView.CHOICE_MODE_MULTIPLE_CUSTOM);
|
||||
mRecyclerView.setCustomCheckedListener(this);
|
||||
int paddingH = resources.getDimensionPixelOffset(R.dimen.list_content_margin_h);
|
||||
int paddingV = resources.getDimensionPixelOffset(R.dimen.list_content_margin_v);
|
||||
mRecyclerView.setPadding(paddingV, paddingH, paddingV, paddingH);
|
||||
|
||||
mLeftDrawable = new DrawerArrowDrawable(getContext());
|
||||
mSearchBar.setLeftDrawable(mLeftDrawable);
|
||||
mSearchBar.setRightDrawable(DrawableManager.getDrawable(getContext(), R.drawable.v_magnify_x24));
|
||||
mSearchBar.setHelper(this);
|
||||
mSearchBar.setAllowEmptySearch(false);
|
||||
updateSearchBar();
|
||||
mSearchBarMover = new SearchBarMover(this, mSearchBar, mRecyclerView);
|
||||
|
||||
mFabLayout.setExpanded(false, false);
|
||||
mFabLayout.setAutoCancel(false);
|
||||
mFabLayout.setHidePrimaryFab(true);
|
||||
mFabLayout.setOnClickFabListener(this);
|
||||
|
||||
// Only refresh for the first time
|
||||
if (!mHasFirstRefresh) {
|
||||
mHasFirstRefresh = true;
|
||||
mHelper.firstRefresh();
|
||||
}
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
// keyword of mUrlBuilder, fav cat of mUrlBuilder, mFavCat.
|
||||
// They changed, call it
|
||||
private void updateSearchBar() {
|
||||
if (mUrlBuilder == null || mSearchBar == null || mFavCat == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update title
|
||||
int favCat = mUrlBuilder.getFavCat();
|
||||
String favCatName;
|
||||
if (favCat >= 0 && favCat < 10) {
|
||||
favCatName = mFavCat[favCat];
|
||||
} else {
|
||||
favCatName = getString(R.string.all_favorites);
|
||||
}
|
||||
String keyword = mUrlBuilder.getKeyword();
|
||||
if (TextUtils.isEmpty(keyword)) {
|
||||
if (!ObjectUtils.equal(favCatName, mOldFavCat)) {
|
||||
mSearchBar.setTitle(getString(R.string.favorites_title, favCatName));
|
||||
}
|
||||
} else {
|
||||
if (!ObjectUtils.equal(favCatName, mOldFavCat) || !ObjectUtils.equal(keyword, mOldKeyword)) {
|
||||
mSearchBar.setTitle(getString(R.string.favorites_title_2, favCatName, keyword));
|
||||
}
|
||||
}
|
||||
|
||||
// Update hint
|
||||
if (!ObjectUtils.equal(favCatName, mOldFavCat)) {
|
||||
Drawable searchImage = DrawableManager.getDrawable(getContext(), R.drawable.v_magnify_x24);
|
||||
SpannableStringBuilder ssb = new SpannableStringBuilder(" ");
|
||||
ssb.append(getString(R.string.favorites_search_bar_hint, favCatName));
|
||||
int textSize = (int) (mSearchBar.getEditTextTextSize() * 1.25);
|
||||
if (searchImage != null) {
|
||||
searchImage.setBounds(0, 0, textSize, textSize);
|
||||
ssb.setSpan(new ImageSpan(searchImage), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
}
|
||||
mSearchBar.setEditTextHint(ssb);
|
||||
}
|
||||
|
||||
mOldFavCat = favCatName;
|
||||
mOldKeyword = keyword;
|
||||
|
||||
// Save recent fav cat
|
||||
Settings.putRecentFavCat(mUrlBuilder.getFavCat());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
setNavCheckedItem(R.id.nav_whats_hot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
|
||||
mRecyclerView = null;
|
||||
mSearchBar = null;
|
||||
mFabLayout = null;
|
||||
|
||||
mAdapter = null;
|
||||
mHelper = null;
|
||||
mSearchBarMover = null;
|
||||
mLeftDrawable = null;
|
||||
|
||||
mOldFavCat = null;
|
||||
mOldKeyword = null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public View onCreateDrawerView(LayoutInflater inflater,
|
||||
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.drawer_list, container, false);
|
||||
ListView listView = (ListView) view.findViewById(R.id.list_view);
|
||||
|
||||
mDrawerList = new ArrayList<>(11);
|
||||
mDrawerList.add(getString(R.string.all_favorites));
|
||||
if (mFavCat != null) {
|
||||
for (String favCat: mFavCat) {
|
||||
mDrawerList.add(favCat);
|
||||
}
|
||||
}
|
||||
mDrawerAdapter = new ArrayAdapter<>(getContext(), R.layout.item_simple_list, mDrawerList);
|
||||
listView.setAdapter(mDrawerAdapter);
|
||||
listView.setOnItemClickListener(this);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyDrawerView() {
|
||||
super.onDestroyDrawerView();
|
||||
|
||||
mDrawerAdapter = null;
|
||||
mDrawerList = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (mRecyclerView != null && mRecyclerView.isInCustomChoice()) {
|
||||
mRecyclerView.outOfCustomChoiceMode();
|
||||
} else if (mSearchMode) {
|
||||
exitSearchMode(true);
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Implemented(FastScroller.OnDragHandlerListener.class)
|
||||
public void onStartDragHandler() {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Implemented(FastScroller.OnDragHandlerListener.class)
|
||||
public void onEndDragHandler() {
|
||||
if (mSearchBarMover != null) {
|
||||
mSearchBarMover.returnSearchBarPosition();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Implemented(EasyRecyclerView.OnItemClickListener.class)
|
||||
public boolean onItemClick(EasyRecyclerView parent, View view, int position, long id) {
|
||||
if (mRecyclerView != null && mRecyclerView.isInCustomChoice()) {
|
||||
mRecyclerView.toggleItemChecked(position);
|
||||
} else if (mHelper != null) {
|
||||
GalleryInfo gi = mHelper.getDataAt(position);
|
||||
Bundle args = new Bundle();
|
||||
args.putString(GalleryDetailScene.KEY_ACTION, GalleryDetailScene.ACTION_GALLERY_INFO);
|
||||
args.putParcelable(GalleryDetailScene.KEY_GALLERY_INFO, gi);
|
||||
Announcer announcer = new Announcer(GalleryDetailScene.class).setArgs(args);
|
||||
if (ApiHelper.SUPPORT_TRANSITION) {
|
||||
FavoriteHolder holder = (FavoriteHolder) mRecyclerView.getChildViewHolder(view);
|
||||
announcer.setTranHelper(new EnterGalleryDetailTransaction(holder));
|
||||
}
|
||||
startScene(announcer);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Implemented(EasyRecyclerView.OnItemLongClickListener.class)
|
||||
public boolean onItemLongClick(EasyRecyclerView parent, View view, int position, long id) {
|
||||
// Can not into
|
||||
if (mRecyclerView != null && !mSearchMode) {
|
||||
if (!mRecyclerView.isInCustomChoice()) {
|
||||
mRecyclerView.intoCustomChoiceMode();
|
||||
}
|
||||
mRecyclerView.toggleItemChecked(position);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Implemented(SearchBarMover.Helper.class)
|
||||
public boolean isValidView(RecyclerView recyclerView) {
|
||||
return recyclerView == mRecyclerView;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Implemented(SearchBarMover.Helper.class)
|
||||
public RecyclerView getValidRecyclerView() {
|
||||
return mRecyclerView;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Implemented(SearchBarMover.Helper.class)
|
||||
public boolean forceShowSearchBar() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Implemented(SearchBar.Helper.class)
|
||||
public void onClickTitle() {
|
||||
// Skip if in search mode
|
||||
if (mRecyclerView != null && mRecyclerView.isInCustomChoice()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mSearchMode) {
|
||||
enterSearchMode(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Implemented(SearchBar.Helper.class)
|
||||
public void onClickLeftIcon() {
|
||||
// Skip if in search mode
|
||||
if (mRecyclerView != null && mRecyclerView.isInCustomChoice()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mSearchMode) {
|
||||
exitSearchMode(true);
|
||||
} else {
|
||||
toggleDrawer(Gravity.LEFT);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Implemented(SearchBar.Helper.class)
|
||||
public void onClickRightIcon() {
|
||||
// Skip if in search mode
|
||||
if (mRecyclerView != null && mRecyclerView.isInCustomChoice()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mSearchMode) {
|
||||
enterSearchMode(true);
|
||||
} else {
|
||||
if (mSearchBar != null) {
|
||||
mSearchBar.applySearch();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Implemented(SearchBar.Helper.class)
|
||||
public void onSearchEditTextClick() {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Implemented(SearchBar.Helper.class)
|
||||
public void onApplySearch(String query) {
|
||||
// Skip if in search mode
|
||||
if (mRecyclerView != null && mRecyclerView.isInCustomChoice()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mUrlBuilder == null || mHelper == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure outOfCustomChoiceMode to avoid error
|
||||
if (mRecyclerView != null) {
|
||||
mRecyclerView.isInCustomChoice();
|
||||
}
|
||||
|
||||
exitSearchMode(true);
|
||||
|
||||
mUrlBuilder.setKeyword(query);
|
||||
updateSearchBar();
|
||||
mHelper.refresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Implemented(SearchBar.Helper.class)
|
||||
public void onSearchEditTextBackPressed() {
|
||||
onBackPressed();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Implemented(FabLayout.OnClickFabListener.class)
|
||||
public void onClickPrimaryFab(FabLayout view, FloatingActionButton fab) {
|
||||
if (mRecyclerView != null) {
|
||||
mRecyclerView.outOfCustomChoiceMode();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Implemented(FabLayout.OnClickFabListener.class)
|
||||
public void onClickSecondaryFab(FabLayout view, FloatingActionButton fab, int position) {
|
||||
if (mRecyclerView == null || mHelper == null || !mRecyclerView.isInCustomChoice()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mModifyGidList.clear();
|
||||
SparseBooleanArray stateArray = mRecyclerView.getCheckedItemPositions();
|
||||
for (int i = 0, n = stateArray.size(); i < n; i++) {
|
||||
if (stateArray.valueAt(i)) {
|
||||
mModifyGidList.add(mHelper.getDataAt(stateArray.keyAt(i)).gid);
|
||||
}
|
||||
}
|
||||
|
||||
switch (position) {
|
||||
case 0: { // Delete
|
||||
new AlertDialog.Builder(getContext())
|
||||
.setTitle(R.string.delete_favorites_dialog_title)
|
||||
.setMessage(getString(R.string.delete_favorites_dialog_message, mModifyGidList.size()))
|
||||
.setPositiveButton(android.R.string.ok, new DeleteDialogHelper())
|
||||
.show();
|
||||
break;
|
||||
}
|
||||
case 1: { // Move
|
||||
new AlertDialog.Builder(getContext())
|
||||
.setTitle(R.string.move_favorites_dialog_title)
|
||||
.setItems(Settings.getFavCat(), new MoveDialogHelper())
|
||||
.show();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Implemented(EasyRecyclerView.CustomChoiceListener.class)
|
||||
public void onIntoCustomChoice(EasyRecyclerView view) {
|
||||
if (mFabLayout != null) {
|
||||
mFabLayout.setExpanded(true);
|
||||
}
|
||||
if (mHelper != null) {
|
||||
mHelper.setRefreshLayoutEnable(false);
|
||||
}
|
||||
// Lock drawer
|
||||
setDrawerLayoutEnable(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Implemented(EasyRecyclerView.CustomChoiceListener.class)
|
||||
public void onOutOfCustomChoice(EasyRecyclerView view) {
|
||||
if (mFabLayout != null) {
|
||||
mFabLayout.setExpanded(false);
|
||||
}
|
||||
if (mHelper != null) {
|
||||
mHelper.setRefreshLayoutEnable(true);
|
||||
}
|
||||
// Unlock drawer
|
||||
setDrawerLayoutEnable(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Implemented(EasyRecyclerView.CustomChoiceListener.class)
|
||||
public void onItemCheckedStateChanged(EasyRecyclerView view, int position, long id, boolean checked) {
|
||||
if (view.getCheckedItemCount() == 0) {
|
||||
view.outOfCustomChoiceMode();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Implemented(AdapterView.OnItemClickListener.class)
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
// Skip if in search mode
|
||||
if (mRecyclerView != null && mRecyclerView.isInCustomChoice()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mUrlBuilder == null || mHelper == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// All favorite position is 0, so position - 1 is OK
|
||||
int newFavCat = position - 1;
|
||||
|
||||
// Check is the same
|
||||
if (mUrlBuilder.getFavCat() == newFavCat ||
|
||||
(!FavListUrlBuilder.isValidFavCat(mUrlBuilder.getFavCat()) &&
|
||||
!FavListUrlBuilder.isValidFavCat(newFavCat))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure outOfCustomChoiceMode to avoid error
|
||||
if (mRecyclerView != null) {
|
||||
mRecyclerView.isInCustomChoice();
|
||||
}
|
||||
|
||||
exitSearchMode(true);
|
||||
|
||||
mUrlBuilder.setKeyword(null);
|
||||
mUrlBuilder.setFavCat(newFavCat);
|
||||
updateSearchBar();
|
||||
mHelper.refresh();
|
||||
|
||||
closeDrawer(Gravity.RIGHT);
|
||||
}
|
||||
|
||||
private void enterSearchMode(boolean animation) {
|
||||
if (mSearchMode ||mSearchBar == null || mSearchBarMover == null || mLeftDrawable == null) {
|
||||
return;
|
||||
}
|
||||
mSearchMode = true;
|
||||
mSearchBar.setState(SearchBar.STATE_SEARCH_LIST, animation);
|
||||
mSearchBarMover.returnSearchBarPosition(animation);
|
||||
mLeftDrawable.setArrow(ANIMATE_TIME);
|
||||
}
|
||||
|
||||
private void exitSearchMode(boolean animation) {
|
||||
if (!mSearchMode || mSearchBar == null || mSearchBarMover == null || mLeftDrawable == null) {
|
||||
return;
|
||||
}
|
||||
mSearchMode = false;
|
||||
mSearchBar.setState(SearchBar.STATE_NORMAL, animation);
|
||||
mSearchBarMover.returnSearchBarPosition();
|
||||
mLeftDrawable.setMenu(ANIMATE_TIME);
|
||||
}
|
||||
|
||||
private void onGetFavoritesSuccess(FavoritesParser.Result result, int taskId) {
|
||||
if (mHelper != null && mSearchBarMover != null &&
|
||||
mHelper.isCurrentTask(taskId)) {
|
||||
|
||||
if (mFavCat != null && mDrawerList != null) {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
mFavCat[i] = result.catArray[i];
|
||||
mDrawerList.set(i + 1, result.catArray[i]);
|
||||
}
|
||||
|
||||
if (mDrawerAdapter != null) {
|
||||
mDrawerAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
updateSearchBar();
|
||||
mHelper.setPages(taskId, result.pages);
|
||||
mHelper.onGetPageData(taskId, result.galleryInfoList);
|
||||
SimpleHandler.getInstance().post(mReturnSearchBarRunnabel);
|
||||
}
|
||||
}
|
||||
|
||||
private void onGetFavoritesFailure(Exception e, int taskId) {
|
||||
if (mHelper != null && mSearchBarMover != null &&
|
||||
mHelper.isCurrentTask(taskId)) {
|
||||
mHelper.onGetExpection(taskId, e);
|
||||
}
|
||||
}
|
||||
|
||||
private class DeleteDialogHelper implements DialogInterface.OnClickListener {
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (which != DialogInterface.BUTTON_POSITIVE) {
|
||||
return;
|
||||
}
|
||||
if (mRecyclerView == null || mHelper == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mRecyclerView.outOfCustomChoiceMode();
|
||||
|
||||
mEnableModify = true;
|
||||
mModifyFavCat = -1;
|
||||
mHelper.justRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
private class MoveDialogHelper implements DialogInterface.OnClickListener {
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
if (mRecyclerView == null || mHelper == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mRecyclerView.outOfCustomChoiceMode();
|
||||
|
||||
mEnableModify = true;
|
||||
mModifyFavCat = which;
|
||||
mHelper.justRefresh();
|
||||
}
|
||||
}
|
||||
|
||||
private static class EnterGalleryDetailTransaction implements TransitionHelper {
|
||||
|
||||
private final FavoriteHolder mHolder;
|
||||
|
||||
public EnterGalleryDetailTransaction(FavoriteHolder holder) {
|
||||
mHolder = holder;
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
@Override
|
||||
public boolean onTransition(Context context, FragmentTransaction transaction,
|
||||
Fragment exit, Fragment enter) {
|
||||
if (mHolder == null || !(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 FavoriteHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
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 FavoriteHolder(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);
|
||||
posted = (TextView) itemView.findViewById(R.id.posted);
|
||||
simpleLanguage = (TextView) itemView.findViewById(R.id.simple_language);
|
||||
}
|
||||
}
|
||||
|
||||
private class FavoriteAdapter extends RecyclerView.Adapter<FavoriteHolder> {
|
||||
|
||||
@Override
|
||||
public FavoriteHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
return new FavoriteHolder(getActivity().getLayoutInflater()
|
||||
.inflate(R.layout.item_gallery_list, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
||||
public void onBindViewHolder(FavoriteHolder holder, int position) {
|
||||
if (mHelper == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
GalleryInfo gi = mHelper.getDataAt(position);
|
||||
holder.thumb.load(EhCacheKeyFactory.getThumbKey(gi.gid), gi.thumb, true);
|
||||
holder.title.setText(EhUtils.getSuitableTitle(gi));
|
||||
holder.uploader.setText(gi.uploader);
|
||||
holder.rating.setRating(gi.rating);
|
||||
TextView category = holder.category;
|
||||
String newCategoryText = EhUtils.getCategory(gi.category);
|
||||
if (!newCategoryText.equals(category.getText())) {
|
||||
category.setText(newCategoryText);
|
||||
category.setBackgroundColor(EhUtils.getCategoryColor(gi.category));
|
||||
}
|
||||
holder.posted.setText(gi.posted);
|
||||
holder.simpleLanguage.setText(gi.simpleLanguage);
|
||||
|
||||
// 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 mHelper != null ? mHelper.size() : 0;
|
||||
}
|
||||
}
|
||||
|
||||
private class FavoriteHelper extends ContentLayout.ContentHelper<GalleryInfo> {
|
||||
|
||||
@Override
|
||||
protected void getPageData(final int taskId, int type, int page) {
|
||||
if (mUrlBuilder == null || mClient == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mEnableModify) {
|
||||
mEnableModify = false;
|
||||
mUrlBuilder.setIndex(page);
|
||||
String url = mUrlBuilder.build();
|
||||
EhRequest request = new EhRequest();
|
||||
request.setMethod(EhClient.METHOD_MODIFY_FAVORITES);
|
||||
request.setCallback(new GetFavoritesListener(getContext(),
|
||||
((StageActivity) getActivity()).getStageId(), getTag(), taskId));
|
||||
request.setArgs(url, mModifyGidList, mModifyFavCat, Settings.getShowJpnTitle());
|
||||
mClient.execute(request);
|
||||
} else {
|
||||
mUrlBuilder.setIndex(page);
|
||||
String url = mUrlBuilder.build();
|
||||
EhRequest request = new EhRequest();
|
||||
request.setMethod(EhClient.METHOD_GET_FAVORITES);
|
||||
request.setCallback(new GetFavoritesListener(getContext(),
|
||||
((StageActivity) getActivity()).getStageId(), getTag(), taskId));
|
||||
request.setArgs(url, Settings.getShowJpnTitle());
|
||||
mClient.execute(request);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHideRecyclerView() {
|
||||
super.onHideRecyclerView();
|
||||
if (mSearchBarMover != null) {
|
||||
mSearchBarMover.showSearchBar();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Context getContext() {
|
||||
return FavoritesScene.this.getContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void notifyDataSetChanged() {
|
||||
// Ensure outOfCustomChoiceMode to avoid error
|
||||
if (mRecyclerView != null) {
|
||||
mRecyclerView.outOfCustomChoiceMode();
|
||||
}
|
||||
|
||||
if (mAdapter != null) {
|
||||
mAdapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void notifyItemRangeRemoved(int positionStart, int itemCount) {
|
||||
if (mAdapter != null) {
|
||||
mAdapter.notifyItemRangeRemoved(positionStart, itemCount);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void notifyItemRangeInserted(int positionStart, int itemCount) {
|
||||
if (mAdapter != null) {
|
||||
mAdapter.notifyItemRangeInserted(positionStart, itemCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class GetFavoritesListener extends EhCallback<FavoritesScene, FavoritesParser.Result> {
|
||||
|
||||
private final int mTaskId;
|
||||
|
||||
public GetFavoritesListener(Context context, int stageId, String sceneTag, int taskId) {
|
||||
super(context, stageId, sceneTag);
|
||||
mTaskId = taskId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(FavoritesParser.Result result) {
|
||||
// Put fav cat
|
||||
Settings.putFavCat(result.catArray);
|
||||
FavoritesScene scene = getScene();
|
||||
if (scene != null) {
|
||||
scene.onGetFavoritesSuccess(result, mTaskId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
FavoritesScene scene = getScene();
|
||||
if (scene != null) {
|
||||
scene.onGetFavoritesFailure(e, mTaskId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {}
|
||||
|
||||
@Override
|
||||
public boolean isInstance(SceneFragment scene) {
|
||||
return scene instanceof FavoritesScene;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,7 +54,6 @@ import com.hippo.scene.StageActivity;
|
||||
import com.hippo.text.Html;
|
||||
import com.hippo.text.URLImageGetter;
|
||||
import com.hippo.util.ActivityHelper;
|
||||
import com.hippo.util.DrawableManager;
|
||||
import com.hippo.util.ReadableTime;
|
||||
import com.hippo.util.TextUrl;
|
||||
import com.hippo.view.ViewTransition;
|
||||
@@ -181,7 +180,7 @@ public final class GalleryCommentsScene extends ToolbarScene
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
setTitle(R.string.gallery_comments);
|
||||
setNavigationIcon(DrawableManager.getDrawable(getContext(), R.drawable.v_arrow_left_dark_x24));
|
||||
setNavigationIcon(R.drawable.v_arrow_left_dark_x24);
|
||||
|
||||
// Clear nav checked item
|
||||
setNavCheckedItem(0);
|
||||
|
||||
@@ -996,7 +996,8 @@ 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) && !(enter instanceof DownloadScene)) {
|
||||
if (!(enter instanceof GalleryListScene) && !(enter instanceof DownloadScene) &&
|
||||
!(enter instanceof FavoritesScene)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,7 +39,6 @@ import com.hippo.ehviewer.client.EhUtils;
|
||||
import com.hippo.ehviewer.client.data.GalleryDetail;
|
||||
import com.hippo.rippleold.RippleSalon;
|
||||
import com.hippo.util.ActivityHelper;
|
||||
import com.hippo.util.DrawableManager;
|
||||
import com.hippo.yorozuya.LayoutUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -170,7 +169,7 @@ public final class GalleryInfoScene extends ToolbarScene implements EasyRecycler
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
setTitle(R.string.gallery_info);
|
||||
setNavigationIcon(DrawableManager.getDrawable(getContext(), R.drawable.v_arrow_left_dark_x24));
|
||||
setNavigationIcon(R.drawable.v_arrow_left_dark_x24);
|
||||
|
||||
// Clear nav checked item
|
||||
setNavCheckedItem(0);
|
||||
|
||||
@@ -427,7 +427,7 @@ public final class GalleryListScene extends BaseScene
|
||||
@Override
|
||||
public boolean onTransition(Context context, FragmentTransaction transaction,
|
||||
Fragment exit, Fragment enter) {
|
||||
if (!(enter instanceof GalleryDetailScene)) {
|
||||
if (mHolder == null || !(enter instanceof GalleryDetailScene)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -48,7 +48,6 @@ import com.hippo.ehviewer.client.exception.EhException;
|
||||
import com.hippo.scene.SceneFragment;
|
||||
import com.hippo.scene.StageActivity;
|
||||
import com.hippo.util.ActivityHelper;
|
||||
import com.hippo.util.DrawableManager;
|
||||
import com.hippo.widget.ContentLayout;
|
||||
import com.hippo.widget.LoadImageView;
|
||||
import com.hippo.widget.Slider;
|
||||
@@ -152,7 +151,7 @@ public class GalleryPreviewsScene extends ToolbarScene {
|
||||
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
setTitle(R.string.gallery_previews);
|
||||
setNavigationIcon(DrawableManager.getDrawable(getContext(), R.drawable.v_arrow_left_dark_x24));
|
||||
setNavigationIcon(R.drawable.v_arrow_left_dark_x24);
|
||||
|
||||
// Clear nav checked item
|
||||
setNavCheckedItem(0);
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.text.Editable;
|
||||
import android.text.TextUtils;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.KeyEvent;
|
||||
@@ -67,7 +68,7 @@ public class SearchBar extends FrameLayout implements View.OnClickListener,
|
||||
|
||||
private int mState = STATE_NORMAL;
|
||||
|
||||
private Path mPath = new Path();
|
||||
private final Path mPath = new Path();
|
||||
private int mWidth;
|
||||
private int mHeight;
|
||||
private int mBaseHeight;
|
||||
@@ -79,7 +80,7 @@ public class SearchBar extends FrameLayout implements View.OnClickListener,
|
||||
private SearchEditText mEditText;
|
||||
private ListView mList;
|
||||
private View mListHeader;
|
||||
private boolean mHeaderAttached = false;
|
||||
private boolean mHeaderAttached;
|
||||
|
||||
private ViewTransition mViewTransition;
|
||||
|
||||
@@ -90,7 +91,9 @@ public class SearchBar extends FrameLayout implements View.OnClickListener,
|
||||
private Helper mHelper;
|
||||
private OnStateChangeListener mOnStateChangeListener;
|
||||
|
||||
private boolean mInAnimation = false;
|
||||
private boolean mAllowEmptySearch = true;
|
||||
|
||||
private boolean mInAnimation;
|
||||
|
||||
public SearchBar(Context context) {
|
||||
super(context);
|
||||
@@ -187,6 +190,10 @@ public class SearchBar extends FrameLayout implements View.OnClickListener,
|
||||
mSuggestionAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void setAllowEmptySearch(boolean allowEmptySearch) {
|
||||
mAllowEmptySearch = allowEmptySearch;
|
||||
}
|
||||
|
||||
public float getEditTextTextSize() {
|
||||
return mEditText.getTextSize();
|
||||
}
|
||||
@@ -245,6 +252,11 @@ public class SearchBar extends FrameLayout implements View.OnClickListener,
|
||||
|
||||
public void applySearch() {
|
||||
String query = mEditText.getText().toString().trim();
|
||||
|
||||
if (!mAllowEmptySearch && TextUtils.isEmpty(query)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Put it into db
|
||||
mSearchDatabase.addQuery(query);
|
||||
// Callback
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.support.annotation.Nullable;
|
||||
|
||||
import org.jsoup.nodes.Document;
|
||||
import org.jsoup.nodes.Element;
|
||||
import org.jsoup.select.Elements;
|
||||
|
||||
public final class JsoupUtils {
|
||||
|
||||
@Nullable
|
||||
public static Element getElementByClass(Document doc, String className) {
|
||||
Elements elements = doc.getElementsByClass(className);
|
||||
if (elements != null && elements.size() > 0) {
|
||||
return elements.get(0);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Element getElementByClass(Element element, String className) {
|
||||
Elements elements = element.getElementsByClass(className);
|
||||
if (elements != null && elements.size() > 0) {
|
||||
return elements.get(0);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Element getElementByTag(Element element, String tagName) {
|
||||
Elements elements = element.getElementsByTag(tagName);
|
||||
if (elements != null && elements.size() > 0) {
|
||||
return elements.get(0);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -240,7 +240,7 @@ public class ContentLayout extends FrameLayout {
|
||||
|
||||
private String mEmptyString = "No hint";
|
||||
|
||||
private RecyclerView.OnScrollListener mOnScrollListener = new RecyclerView.OnScrollListener() {
|
||||
private final RecyclerView.OnScrollListener mOnScrollListener = new RecyclerView.OnScrollListener() {
|
||||
@Override
|
||||
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
|
||||
if (!mRefreshLayout.isRefreshing() && mRefreshLayout.isAlmostBottom() && mEndPage < mPages) {
|
||||
@@ -251,7 +251,7 @@ public class ContentLayout extends FrameLayout {
|
||||
}
|
||||
};
|
||||
|
||||
private RefreshLayout.OnRefreshListener mOnRefreshListener = new RefreshLayout.OnRefreshListener() {
|
||||
private final RefreshLayout.OnRefreshListener mOnRefreshListener = new RefreshLayout.OnRefreshListener() {
|
||||
@Override
|
||||
public void onHeaderRefresh() {
|
||||
if (mStartPage > 0) {
|
||||
@@ -284,7 +284,7 @@ public class ContentLayout extends FrameLayout {
|
||||
}
|
||||
};
|
||||
|
||||
private LayoutManagerUtils.OnScrollToPositionListener mOnScrollToPositionListener =
|
||||
private final LayoutManagerUtils.OnScrollToPositionListener mOnScrollToPositionListener =
|
||||
new LayoutManagerUtils.OnScrollToPositionListener() {
|
||||
@Override
|
||||
public void onScrollToPosition() {
|
||||
@@ -318,7 +318,6 @@ public class ContentLayout extends FrameLayout {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Call {@link #onGetPageData(int, List)} when get data
|
||||
*
|
||||
@@ -338,10 +337,11 @@ public class ContentLayout extends FrameLayout {
|
||||
protected void onScrollToPosition() {
|
||||
}
|
||||
|
||||
protected void onShowProgress() {
|
||||
protected void onHideRecyclerView() {
|
||||
}
|
||||
|
||||
protected void onShowText() {
|
||||
public void setRefreshLayoutEnable(boolean enable) {
|
||||
mRefreshLayout.setEnabled(enable);
|
||||
}
|
||||
|
||||
public void setEnable(boolean enable) {
|
||||
@@ -565,24 +565,24 @@ public class ContentLayout extends FrameLayout {
|
||||
mViewTransition.showView(0);
|
||||
}
|
||||
|
||||
private boolean isContentShowning() {
|
||||
private boolean isContentShowing() {
|
||||
return mViewTransition.getShownViewIndex() == 0;
|
||||
}
|
||||
|
||||
public void showProgressBar() {
|
||||
mViewTransition.showView(1, false);
|
||||
showProgressBar(true);
|
||||
}
|
||||
|
||||
public void showProgressBar(boolean animation) {
|
||||
if (mViewTransition.showView(1, animation)) {
|
||||
onShowProgress();
|
||||
onHideRecyclerView();
|
||||
}
|
||||
}
|
||||
|
||||
public void showText(CharSequence text) {
|
||||
mTextView.setText(text);
|
||||
if (mViewTransition.showView(2)) {
|
||||
onShowText();
|
||||
onHideRecyclerView();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -642,6 +642,14 @@ public class ContentLayout extends FrameLayout {
|
||||
doRefresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh header and refresh
|
||||
*/
|
||||
public void justRefresh() {
|
||||
mRefreshLayout.setHeaderRefreshing(true);
|
||||
doRefresh();
|
||||
}
|
||||
|
||||
private void cancelCurrentTask() {
|
||||
mCurrentTaskId = mIdGenerator.nextId();
|
||||
mRefreshLayout.setHeaderRefreshing(false);
|
||||
@@ -684,7 +692,7 @@ public class ContentLayout extends FrameLayout {
|
||||
}
|
||||
|
||||
public boolean canGoTo() {
|
||||
return isContentShowning();
|
||||
return isContentShowing();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.hippo.widget;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
|
||||
@@ -82,6 +83,9 @@ public class SearchBarMover extends RecyclerView.OnScrollListener {
|
||||
show = true;
|
||||
} else {
|
||||
RecyclerView recyclerView = mHelper.getValidRecyclerView();
|
||||
if (recyclerView == null) {
|
||||
return;
|
||||
}
|
||||
if (!recyclerView.isShown()) {
|
||||
show = true;
|
||||
} else if (recyclerView.computeVerticalScrollOffset() < mSearchBar.getBottom()){
|
||||
@@ -206,6 +210,7 @@ public class SearchBarMover extends RecyclerView.OnScrollListener {
|
||||
|
||||
boolean isValidView(RecyclerView recyclerView);
|
||||
|
||||
@Nullable
|
||||
RecyclerView getValidRecyclerView();
|
||||
|
||||
boolean forceShowSearchBar();
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<vector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
|
||||
<path
|
||||
android:fillColor="@color/primary_drawable_dark"
|
||||
android:pathData="@string/pd_delete"/>
|
||||
|
||||
</vector>
|
||||
@@ -0,0 +1,39 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<android.support.v7.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:layout_width="match_parent"
|
||||
android:background="?attr/colorPrimary"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
|
||||
android:elevation="8dp"
|
||||
android:saveEnabled="false"/>
|
||||
|
||||
<ListView
|
||||
android:id="@+id/list_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1"/>
|
||||
|
||||
</LinearLayout>
|
||||
+1
-1
@@ -36,7 +36,7 @@
|
||||
|
||||
<View
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="4dp"
|
||||
android:layout_height="8dp"
|
||||
android:background="@drawable/shadow_bottom"/>
|
||||
|
||||
<ListView
|
||||
@@ -19,7 +19,7 @@
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/card_white_2dp">
|
||||
android:background="@drawable/card_background">
|
||||
|
||||
<com.hippo.ehviewer.widget.ThumbImageView
|
||||
android:id="@+id/thumb"
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<com.hippo.ehviewer.widget.FitPaddingLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/main_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:content1="@+id/recycler_view"
|
||||
app:fitTop1="@+id/search_bar"
|
||||
app:content2="@+id/fast_scroller"
|
||||
app:fitTop2="@+id/search_bar"
|
||||
app:content3="@+id/search_layout"
|
||||
app:fitTop3="@+id/search_bar"
|
||||
app:once="true">
|
||||
|
||||
<com.hippo.widget.ContentLayout
|
||||
android:id="@+id/content_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
<com.hippo.ehviewer.widget.SearchBar
|
||||
android:id="@+id/search_bar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="@dimen/list_search_bar_margin"
|
||||
android:layout_marginRight="@dimen/list_search_bar_margin"
|
||||
android:layout_marginTop="8dp"/>
|
||||
|
||||
<com.hippo.widget.FabLayout
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/fab_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingRight="@dimen/corner_fab_margin"
|
||||
android:paddingBottom="@dimen/corner_fab_margin">
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
style="@style/Widget.Design.FloatingActionButton.Mini"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@drawable/v_delete_dark_x24"
|
||||
app:backgroundTint="?attr/colorPrimary"/>
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
style="@style/Widget.Design.FloatingActionButton.Mini"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@drawable/v_folder_move_dark_x24"
|
||||
app:backgroundTint="?attr/colorPrimary"/>
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
style="@style/Widget.Design.FloatingActionButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@drawable/v_close_dark_x24"/>
|
||||
|
||||
</com.hippo.widget.FabLayout>
|
||||
</com.hippo.ehviewer.widget.FitPaddingLayout>
|
||||
@@ -0,0 +1,29 @@
|
||||
<?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.
|
||||
-->
|
||||
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_search"
|
||||
android:icon="@drawable/v_magnify_dark_x24"
|
||||
android:title="@string/search"
|
||||
app:showAsAction="always"
|
||||
app:actionViewClass="android.support.v7.widget.SearchView"/>
|
||||
|
||||
</menu>
|
||||
@@ -303,6 +303,15 @@
|
||||
<string name="dir_picker">Dir picker</string>
|
||||
<string name="directory_not_writable">The directory is not writable</string>
|
||||
|
||||
<!-- Favorite -->
|
||||
<string name="all_favorites">All Favorites</string>
|
||||
<string name="favorites_search_bar_hint">Search %s</string>
|
||||
<string name="favorites_title">%s</string>
|
||||
<string name="favorites_title_2">%1$s - %2$s</string>
|
||||
<string name="delete_favorites_dialog_title">Delete favorites</string>
|
||||
<string name="delete_favorites_dialog_message">Delete %d items from favorites</string>
|
||||
<string name="move_favorites_dialog_title">Move favorites</string>
|
||||
|
||||
<!-- Progress Scene -->
|
||||
<string name="error_something_wrong_happened">Something wrong happened</string>
|
||||
|
||||
|
||||
Reference in new issue
Block a user