Filter is back
This commit is contained in:
1 parent
3cd4fc7ce9
commit
58ac39cf2c
14 files changed
+476
-147
No files matched your search
@@ -82,7 +82,11 @@ public class EhEngine {
|
||||
|
||||
private static final Pattern PATTERN_NEED_HATH_CLIENT = Pattern.compile("(You must have a H@H client assigned to your account to use this feature\\.)");
|
||||
|
||||
public static void initialize() { }
|
||||
public static EhFilter sEhFilter;
|
||||
|
||||
public static void initialize() {
|
||||
sEhFilter = EhFilter.getInstance();
|
||||
}
|
||||
|
||||
private static void doThrowException(Call call, int code, @Nullable Headers headers,
|
||||
@Nullable String body, Throwable e) throws Throwable {
|
||||
@@ -170,6 +174,18 @@ public class EhEngine {
|
||||
}
|
||||
|
||||
private static void fillGalleryList(@Nullable EhClient.Task task, OkHttpClient okHttpClient, List<GalleryInfo> list, String url, boolean filter) throws Throwable {
|
||||
// Filter title and uploader
|
||||
if (filter) {
|
||||
for (int i = 0, n = list.size(); i < n; i++) {
|
||||
GalleryInfo info = list.get(i);
|
||||
if (!sEhFilter.filterTitle(info) || !sEhFilter.filterUploader(info)) {
|
||||
list.remove(i);
|
||||
i--;
|
||||
n--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasTags = false;
|
||||
boolean hasPages = false;
|
||||
boolean hasRated = false;
|
||||
@@ -185,11 +201,25 @@ public class EhEngine {
|
||||
}
|
||||
}
|
||||
|
||||
boolean needApi = (Settings.getShowGalleryPages() && !hasPages) || hasRated;
|
||||
boolean needApi = (filter && sEhFilter.needTags() && !hasTags) ||
|
||||
(Settings.getShowGalleryPages() && !hasPages) ||
|
||||
hasRated;
|
||||
if (needApi) {
|
||||
fillGalleryListByApi(task, okHttpClient, list, url);
|
||||
}
|
||||
|
||||
// Filter tag
|
||||
if (filter) {
|
||||
for (int i = 0, n = list.size(); i < n; i++) {
|
||||
GalleryInfo info = list.get(i);
|
||||
if (!sEhFilter.filterTag(info) || !sEhFilter.filterTagNamespace(info)) {
|
||||
list.remove(i);
|
||||
i--;
|
||||
n--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (GalleryInfo info : list) {
|
||||
info.thumb = EhUrl.getFixedPreviewThumbUrl(info.thumb);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019 Hippo Seven
|
||||
* 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.
|
||||
@@ -17,8 +17,11 @@
|
||||
package com.hippo.ehviewer.client;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.hippo.ehviewer.EhDB;
|
||||
import com.hippo.ehviewer.client.data.GalleryInfo;
|
||||
import com.hippo.ehviewer.dao.Filter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -87,4 +90,192 @@ public final class EhFilter {
|
||||
public List<Filter> getTagNamespaceFilterList() {
|
||||
return mTagNamespaceFilterList;
|
||||
}
|
||||
|
||||
public synchronized void addFilter(Filter filter) {
|
||||
// enable filter by default before it is added to database
|
||||
filter.enable = true;
|
||||
EhDB.addFilter(filter);
|
||||
|
||||
switch (filter.mode) {
|
||||
case MODE_TITLE:
|
||||
filter.text = filter.text.toLowerCase();
|
||||
mTitleFilterList.add(filter);
|
||||
break;
|
||||
case MODE_UPLOADER:
|
||||
mUploaderFilterList.add(filter);
|
||||
break;
|
||||
case MODE_TAG:
|
||||
filter.text = filter.text.toLowerCase();
|
||||
mTagFilterList.add(filter);
|
||||
break;
|
||||
case MODE_TAG_NAMESPACE:
|
||||
filter.text = filter.text.toLowerCase();
|
||||
mTagNamespaceFilterList.add(filter);
|
||||
break;
|
||||
default:
|
||||
Log.d(TAG, "Unknown mode: " + filter.mode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void triggerFilter(Filter filter) {
|
||||
EhDB.triggerFilter(filter);
|
||||
}
|
||||
|
||||
public synchronized void deleteFilter(Filter filter) {
|
||||
EhDB.deleteFilter(filter);
|
||||
|
||||
switch (filter.mode) {
|
||||
case MODE_TITLE:
|
||||
mTitleFilterList.remove(filter);
|
||||
break;
|
||||
case MODE_UPLOADER:
|
||||
mUploaderFilterList.remove(filter);
|
||||
break;
|
||||
case MODE_TAG:
|
||||
mTagFilterList.remove(filter);
|
||||
break;
|
||||
case MODE_TAG_NAMESPACE:
|
||||
mTagNamespaceFilterList.remove(filter);
|
||||
break;
|
||||
default:
|
||||
Log.d(TAG, "Unknown mode: " + filter.mode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized boolean needTags() {
|
||||
return 0 != mTagFilterList.size() || 0 != mTagNamespaceFilterList.size();
|
||||
}
|
||||
|
||||
public synchronized boolean filterTitle(GalleryInfo info) {
|
||||
if (null == info) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Title
|
||||
String title = info.title;
|
||||
List<Filter> filters = mTitleFilterList;
|
||||
if (null != title && filters.size() > 0) {
|
||||
for (int i = 0, n = filters.size(); i < n; i++) {
|
||||
if (filters.get(i).enable && title.contains(filters.get(i).text)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized boolean filterUploader(GalleryInfo info) {
|
||||
if (null == info) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Uploader
|
||||
String uploader = info.uploader;
|
||||
List<Filter> filters = mUploaderFilterList;
|
||||
if (null != uploader && filters.size() > 0) {
|
||||
for (int i = 0, n = filters.size(); i < n; i++) {
|
||||
if (filters.get(i).enable && uploader.equals(filters.get(i).text)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean matchTag(String tag, String filter) {
|
||||
if (null == tag || null == filter) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String tagNamespace;
|
||||
String tagName;
|
||||
String filterNamespace;
|
||||
String filterName;
|
||||
int index = tag.indexOf(':');
|
||||
if (index < 0) {
|
||||
tagNamespace = null;
|
||||
tagName = tag;
|
||||
} else {
|
||||
tagNamespace = tag.substring(0, index);
|
||||
tagName = tag.substring(index + 1);
|
||||
}
|
||||
index = filter.indexOf(':');
|
||||
if (index < 0) {
|
||||
filterNamespace = null;
|
||||
filterName = filter;
|
||||
} else {
|
||||
filterNamespace = filter.substring(0, index);
|
||||
filterName = filter.substring(index + 1);
|
||||
}
|
||||
|
||||
if (null != tagNamespace && null != filterNamespace &&
|
||||
!tagNamespace.equals(filterNamespace)) {
|
||||
return false;
|
||||
}
|
||||
if (!tagName.equals(filterName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized boolean filterTag(GalleryInfo info) {
|
||||
if (null == info) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Tag
|
||||
String[] tags = info.simpleTags;
|
||||
List<Filter> filters = mTagFilterList;
|
||||
if (null != tags && filters.size() > 0) {
|
||||
for (String tag: tags) {
|
||||
for (int i = 0, n = filters.size(); i < n; i++) {
|
||||
if (filters.get(i).enable && matchTag(tag, filters.get(i).text)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean matchTagNamespace(String tag, String filter) {
|
||||
if (null == tag || null == filter) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String tagNamespace;
|
||||
int index = tag.indexOf(':');
|
||||
if (index >= 0) {
|
||||
tagNamespace = tag.substring(0, index);
|
||||
return tagNamespace.equals(filter);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized boolean filterTagNamespace(GalleryInfo info) {
|
||||
if (null == info) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String[] tags = info.simpleTags;
|
||||
List<Filter> filters = mTagNamespaceFilterList;
|
||||
if (null != tags && filters.size() > 0) {
|
||||
for (String tag: tags) {
|
||||
for (int i = 0, n = filters.size(); i < n; i++) {
|
||||
if (filters.get(i).enable && matchTagNamespace(tag, filters.get(i).text)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019 Hippo Seven
|
||||
* 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.
|
||||
@@ -16,21 +16,24 @@
|
||||
|
||||
package com.hippo.ehviewer.ui;
|
||||
|
||||
import android.content.ClipData;
|
||||
import android.content.ClipboardManager;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.text.TextUtils;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
import com.google.android.material.textfield.TextInputLayout;
|
||||
import com.hippo.easyrecyclerview.EasyRecyclerView;
|
||||
import com.hippo.ehviewer.R;
|
||||
import com.hippo.ehviewer.client.EhFilter;
|
||||
@@ -100,17 +103,119 @@ public class FilterActivity extends ToolbarActivity {
|
||||
mFilterList = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
super.onCreateOptionsMenu(menu);
|
||||
getMenuInflater().inflate(R.menu.activity_filter, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
finish();
|
||||
return true;
|
||||
case R.id.action_add:
|
||||
showAddFilterDialog();
|
||||
return true;
|
||||
case R.id.action_tip:
|
||||
showTipDialog();
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
private void showTipDialog() {
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.filter)
|
||||
.setMessage(R.string.filter_tip)
|
||||
.show();
|
||||
}
|
||||
|
||||
private void showAddFilterDialog() {
|
||||
AlertDialog dialog = new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.add_filter)
|
||||
.setView(R.layout.dialog_add_filter)
|
||||
.setPositiveButton(R.string.add, null)
|
||||
.show();
|
||||
AddFilterDialogHelper helper = new AddFilterDialogHelper();
|
||||
helper.setDialog(dialog);
|
||||
}
|
||||
|
||||
private void showDeleteFilterDialog(final Filter filter) {
|
||||
String message = getString(R.string.delete_filter, filter.text);
|
||||
new AlertDialog.Builder(this)
|
||||
.setMessage(message)
|
||||
.setPositiveButton(R.string.delete, (dialog, which) -> {
|
||||
if (DialogInterface.BUTTON_POSITIVE != which || null == mFilterList) {
|
||||
return;
|
||||
}
|
||||
mFilterList.delete(filter);
|
||||
if (null != mAdapter) {
|
||||
mAdapter.notifyDataSetChanged();
|
||||
}
|
||||
updateView(true);
|
||||
}).show();
|
||||
}
|
||||
|
||||
private class AddFilterDialogHelper implements View.OnClickListener {
|
||||
|
||||
@Nullable
|
||||
private AlertDialog mDialog;
|
||||
@Nullable
|
||||
private Spinner mSpinner;
|
||||
@Nullable
|
||||
private TextInputLayout mInputLayout;
|
||||
@Nullable
|
||||
private EditText mEditText;
|
||||
|
||||
public void setDialog(AlertDialog dialog) {
|
||||
mDialog = dialog;
|
||||
mSpinner = (Spinner) ViewUtils.$$(dialog, R.id.spinner);
|
||||
mInputLayout = (TextInputLayout) ViewUtils.$$(dialog, R.id.text_input_layout);
|
||||
mEditText = mInputLayout.getEditText();
|
||||
View button = dialog.getButton(DialogInterface.BUTTON_POSITIVE);
|
||||
if (null != button) {
|
||||
button.setOnClickListener(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (null == mFilterList || null == mDialog || null == mSpinner ||
|
||||
null == mInputLayout || null == mEditText) {
|
||||
return;
|
||||
}
|
||||
|
||||
String text = mEditText.getText().toString().trim();
|
||||
if (TextUtils.isEmpty(text)) {
|
||||
mInputLayout.setError(getString(R.string.text_is_empty));
|
||||
return;
|
||||
} else {
|
||||
mInputLayout.setError(null);
|
||||
}
|
||||
int mode = mSpinner.getSelectedItemPosition();
|
||||
|
||||
Filter filter = new Filter();
|
||||
filter.mode = mode;
|
||||
filter.text = text;
|
||||
mFilterList.add(filter);
|
||||
|
||||
if (null != mAdapter) {
|
||||
mAdapter.notifyDataSetChanged();
|
||||
}
|
||||
updateView(true);
|
||||
|
||||
mDialog.dismiss();
|
||||
mDialog = null;
|
||||
mSpinner = null;
|
||||
mInputLayout = null;
|
||||
mEditText = null;
|
||||
}
|
||||
}
|
||||
|
||||
private class FilterHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
|
||||
|
||||
private final TextView text;
|
||||
@@ -124,14 +229,27 @@ public class FilterActivity extends ToolbarActivity {
|
||||
if (null != icon) {
|
||||
icon.setOnClickListener(this);
|
||||
}
|
||||
// click on the filter text to enable/disable it
|
||||
text.setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
|
||||
if (clipboard != null) {
|
||||
clipboard.setPrimaryClip(ClipData.newPlainText("filter", text.getText().toString()));
|
||||
Snackbar.make(v, R.string.copied_to_clipboard, 3000).show();
|
||||
int position = getAdapterPosition();
|
||||
if (position < 0 || null == mFilterList) {
|
||||
return;
|
||||
}
|
||||
Filter filter = mFilterList.get(position);
|
||||
if (FilterList.MODE_HEADER != filter.mode) {
|
||||
if (v instanceof ImageView) {
|
||||
showDeleteFilterDialog(filter);
|
||||
} else if (v instanceof TextView) {
|
||||
mFilterList.trigger(filter);
|
||||
|
||||
//for updating delete line on filter text
|
||||
mAdapter.notifyItemChanged(getAdapterPosition());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -167,7 +285,14 @@ public class FilterActivity extends ToolbarActivity {
|
||||
break;
|
||||
}
|
||||
|
||||
return new FilterHolder(getLayoutInflater().inflate(layoutId, parent, false));
|
||||
FilterHolder holder = new FilterHolder(getLayoutInflater().inflate(layoutId, parent, false));
|
||||
|
||||
if (R.layout.item_filter == layoutId) {
|
||||
holder.icon.setImageDrawable(
|
||||
DrawableManager.getVectorDrawable(FilterActivity.this, R.drawable.v_delete_x24));
|
||||
}
|
||||
|
||||
return holder;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -315,5 +440,17 @@ public class FilterActivity extends ToolbarActivity {
|
||||
|
||||
throw new IndexOutOfBoundsException();
|
||||
}
|
||||
|
||||
public void add(Filter filter) {
|
||||
mEhFilter.addFilter(filter);
|
||||
}
|
||||
|
||||
public void delete(Filter filter) {
|
||||
mEhFilter.deleteFilter(filter);
|
||||
}
|
||||
|
||||
public void trigger(Filter filter) {
|
||||
mEhFilter.triggerFilter(filter);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,6 +67,7 @@ import com.hippo.ehviewer.Settings;
|
||||
import com.hippo.ehviewer.UrlOpener;
|
||||
import com.hippo.ehviewer.client.EhCacheKeyFactory;
|
||||
import com.hippo.ehviewer.client.EhClient;
|
||||
import com.hippo.ehviewer.client.EhFilter;
|
||||
import com.hippo.ehviewer.client.EhRequest;
|
||||
import com.hippo.ehviewer.client.EhTagDatabase;
|
||||
import com.hippo.ehviewer.client.EhUrl;
|
||||
@@ -80,6 +81,7 @@ import com.hippo.ehviewer.client.data.PreviewSet;
|
||||
import com.hippo.ehviewer.client.exception.NoHAtHClientException;
|
||||
import com.hippo.ehviewer.client.parser.RateGalleryParser;
|
||||
import com.hippo.ehviewer.dao.DownloadInfo;
|
||||
import com.hippo.ehviewer.dao.Filter;
|
||||
import com.hippo.ehviewer.ui.CommonOperations;
|
||||
import com.hippo.ehviewer.ui.GalleryActivity;
|
||||
import com.hippo.ehviewer.ui.MainActivity;
|
||||
@@ -480,6 +482,8 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene
|
||||
mDownload.setOnLongClickListener(this);
|
||||
mRead.setOnClickListener(this);
|
||||
|
||||
mUploader.setOnLongClickListener(this);
|
||||
|
||||
mBelowHeader = mainView.findViewById(R.id.below_header);
|
||||
View belowHeader = mBelowHeader;
|
||||
|
||||
@@ -1319,6 +1323,51 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene
|
||||
}
|
||||
}
|
||||
|
||||
private void showFilterUploaderDialog() {
|
||||
Context context = getContext2();
|
||||
String uploader = getUploader();
|
||||
if (context == null || uploader == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
new AlertDialog.Builder(context)
|
||||
.setMessage(getString(R.string.filter_the_uploader, uploader))
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||
if (which != DialogInterface.BUTTON_POSITIVE) {
|
||||
return;
|
||||
}
|
||||
|
||||
Filter filter = new Filter();
|
||||
filter.mode = EhFilter.MODE_UPLOADER;
|
||||
filter.text = uploader;
|
||||
EhFilter.getInstance().addFilter(filter);
|
||||
|
||||
showTip(R.string.filter_added, LENGTH_SHORT);
|
||||
}).show();
|
||||
}
|
||||
|
||||
private void showFilterTagDialog(String tag) {
|
||||
Context context = getContext2();
|
||||
if (context == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
new AlertDialog.Builder(context)
|
||||
.setMessage(getString(R.string.filter_the_tag, tag))
|
||||
.setPositiveButton(android.R.string.ok, (dialog, which) -> {
|
||||
if (which != DialogInterface.BUTTON_POSITIVE) {
|
||||
return;
|
||||
}
|
||||
|
||||
Filter filter = new Filter();
|
||||
filter.mode = EhFilter.MODE_TAG;
|
||||
filter.text = tag;
|
||||
EhFilter.getInstance().addFilter(filter);
|
||||
|
||||
showTip(R.string.filter_added, LENGTH_SHORT);
|
||||
}).show();
|
||||
}
|
||||
|
||||
private void showTagDialog(final String tag) {
|
||||
final Context context = getContext2();
|
||||
if (null == context) {
|
||||
@@ -1335,14 +1384,14 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene
|
||||
|
||||
new AlertDialog.Builder(context)
|
||||
.setTitle(tag)
|
||||
.setItems(R.array.tag_menu_entries, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
switch (which) {
|
||||
case 0:
|
||||
UrlOpener.openUrl(context, EhUrl.getTagDefinitionUrl(tag2), false);
|
||||
break;
|
||||
}
|
||||
.setItems(R.array.tag_menu_entries, (dialog, which) -> {
|
||||
switch (which) {
|
||||
case 0:
|
||||
UrlOpener.openUrl(context, EhUrl.getTagDefinitionUrl(tag2), false);
|
||||
break;
|
||||
case 1:
|
||||
showFilterTagDialog(tag);
|
||||
break;
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
@@ -1354,7 +1403,9 @@ public class GalleryDetailScene extends BaseScene implements View.OnClickListene
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mDownload == v) {
|
||||
if (mUploader == v) {
|
||||
showFilterUploaderDialog();
|
||||
} else if (mDownload == v) {
|
||||
GalleryInfo galleryInfo = getGalleryInfo();
|
||||
if (galleryInfo != null) {
|
||||
CommonOperations.startDownload(activity, galleryInfo, true);
|
||||
|
||||
Reference in new issue
Block a user