Refactor Search

This commit is contained in:
tarsin committed 2022-05-19 23:59:18 +08:00
1 parent 747c19c028
commit 8e1bacbfac
5 files changed
+297 -843

No files matched your search

@@ -1,163 +0,0 @@
/*
* Copyright (C) 2015 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.widget;
import android.content.Context;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TableLayout;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.client.EhConfig;
import com.hippo.widget.CheckTextView;
import com.hippo.yorozuya.NumberUtils;
public class CategoryTable extends TableLayout implements View.OnLongClickListener {
private static final String STATE_KEY_SUPER = "super";
private static final String STATE_KEY_CATEGORY = "category";
private CheckTextView mDoujinshi;
private CheckTextView mManga;
private CheckTextView mArtistCG;
private CheckTextView mGameCG;
private CheckTextView mWestern;
private CheckTextView mNonH;
private CheckTextView mImageSets;
private CheckTextView mCosplay;
private CheckTextView mAsianPorn;
private CheckTextView mMisc;
private CheckTextView[] mOptions;
public CategoryTable(Context context) {
super(context);
init();
}
public CategoryTable(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public void init() {
LayoutInflater inflater = LayoutInflater.from(getContext());
inflater.inflate(R.layout.widget_category_table, this);
ViewGroup row0 = (ViewGroup) getChildAt(0);
mDoujinshi = (CheckTextView) row0.getChildAt(0);
mManga = (CheckTextView) row0.getChildAt(1);
ViewGroup row1 = (ViewGroup) getChildAt(1);
mArtistCG = (CheckTextView) row1.getChildAt(0);
mGameCG = (CheckTextView) row1.getChildAt(1);
ViewGroup row2 = (ViewGroup) getChildAt(2);
mWestern = (CheckTextView) row2.getChildAt(0);
mNonH = (CheckTextView) row2.getChildAt(1);
ViewGroup row3 = (ViewGroup) getChildAt(3);
mImageSets = (CheckTextView) row3.getChildAt(0);
mCosplay = (CheckTextView) row3.getChildAt(1);
ViewGroup row4 = (ViewGroup) getChildAt(4);
mAsianPorn = (CheckTextView) row4.getChildAt(0);
mMisc = (CheckTextView) row4.getChildAt(1);
mOptions = new CheckTextView[]{
mDoujinshi, mManga, mArtistCG, mGameCG, mWestern,
mNonH, mImageSets, mCosplay, mAsianPorn, mMisc
};
for (CheckTextView option : mOptions) {
option.setOnLongClickListener(this);
}
}
@Override
public boolean onLongClick(View v) {
if (v instanceof CheckTextView) {
boolean checked = ((CheckTextView) v).isChecked();
for (CheckTextView option : mOptions) {
if (option != v) {
option.setChecked(!checked);
}
}
}
return true;
}
/**
* Get category according to button.
*
* @return the category of this view
*/
public int getCategory() {
int category = 0;
if (!mDoujinshi.isChecked()) category |= EhConfig.DOUJINSHI;
if (!mManga.isChecked()) category |= EhConfig.MANGA;
if (!mArtistCG.isChecked()) category |= EhConfig.ARTIST_CG;
if (!mGameCG.isChecked()) category |= EhConfig.GAME_CG;
if (!mWestern.isChecked()) category |= EhConfig.WESTERN;
if (!mNonH.isChecked()) category |= EhConfig.NON_H;
if (!mImageSets.isChecked()) category |= EhConfig.IMAGE_SET;
if (!mCosplay.isChecked()) category |= EhConfig.COSPLAY;
if (!mAsianPorn.isChecked()) category |= EhConfig.ASIAN_PORN;
if (!mMisc.isChecked()) category |= EhConfig.MISC;
return category;
}
/**
* Set each button checked or not according to category.
*
* @param category target category
*/
public void setCategory(int category) {
mDoujinshi.setChecked(!NumberUtils.int2boolean(category & EhConfig.DOUJINSHI));
mManga.setChecked(!NumberUtils.int2boolean(category & EhConfig.MANGA));
mArtistCG.setChecked(!NumberUtils.int2boolean(category & EhConfig.ARTIST_CG));
mGameCG.setChecked(!NumberUtils.int2boolean(category & EhConfig.GAME_CG));
mWestern.setChecked(!NumberUtils.int2boolean(category & EhConfig.WESTERN));
mNonH.setChecked(!NumberUtils.int2boolean(category & EhConfig.NON_H));
mImageSets.setChecked(!NumberUtils.int2boolean(category & EhConfig.IMAGE_SET));
mCosplay.setChecked(!NumberUtils.int2boolean(category & EhConfig.COSPLAY));
mAsianPorn.setChecked(!NumberUtils.int2boolean(category & EhConfig.ASIAN_PORN));
mMisc.setChecked(!NumberUtils.int2boolean(category & EhConfig.MISC));
}
@Override
public Parcelable onSaveInstanceState() {
final Bundle state = new Bundle();
state.putParcelable(STATE_KEY_SUPER, super.onSaveInstanceState());
state.putInt(STATE_KEY_CATEGORY, getCategory());
return state;
}
@Override
public void onRestoreInstanceState(Parcelable state) {
if (state instanceof Bundle) {
final Bundle savedState = (Bundle) state;
super.onRestoreInstanceState(savedState.getParcelable(STATE_KEY_SUPER));
setCategory(savedState.getInt(STATE_KEY_CATEGORY));
}
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (C) 2015 Hippo Seven
* Copyright (C) 2022 tarsin norbin
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -13,391 +13,393 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.ehviewer.widget
package com.hippo.ehviewer.widget;
import com.hippo.easyrecyclerview.EasyRecyclerView
import com.google.android.material.tabs.TabLayout.OnTabSelectedListener
import android.view.LayoutInflater
import com.google.android.material.chip.ChipGroup
import com.hippo.widget.RadioGridGroup
import com.google.android.material.tabs.TabLayout
import androidx.recyclerview.widget.LinearLayoutManager
import android.annotation.SuppressLint
import android.content.Context
import android.content.SharedPreferences
import android.net.Uri
import android.os.Bundle
import androidx.recyclerview.widget.DefaultItemAnimator
import com.hippo.ehviewer.R
import com.hippo.easyrecyclerview.MarginItemDecoration
import android.view.ViewGroup
import android.util.SparseArray
import android.os.Parcelable
import android.util.AttributeSet
import android.view.View
import android.widget.*
import kotlin.Throws
import com.hippo.ehviewer.client.exception.EhException
import com.hippo.ehviewer.client.data.ListUrlBuilder
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import androidx.annotation.IntDef
import androidx.core.content.edit
import androidx.preference.PreferenceManager
import com.google.android.material.chip.Chip
import com.hippo.easyrecyclerview.SimpleHolder
import com.hippo.ehviewer.client.EhConfig
import com.hippo.yorozuya.NumberUtils
import com.hippo.yorozuya.ViewUtils
import java.lang.IndexOutOfBoundsException
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CompoundButton;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.Switch;
import android.widget.TextView;
class SearchLayout : EasyRecyclerView, CompoundButton.OnCheckedChangeListener, View.OnClickListener,
ImageSearchLayout.Helper, OnTabSelectedListener {
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
private val mInflater : LayoutInflater
private val mSharePref : SharedPreferences
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.tabs.TabLayout;
import com.hippo.easyrecyclerview.EasyRecyclerView;
import com.hippo.easyrecyclerview.MarginItemDecoration;
import com.hippo.easyrecyclerview.SimpleHolder;
import com.hippo.ehviewer.R;
import com.hippo.ehviewer.client.data.ListUrlBuilder;
import com.hippo.ehviewer.client.exception.EhException;
import com.hippo.widget.RadioGridGroup;
import com.hippo.yorozuya.ViewUtils;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
public class SearchLayout extends EasyRecyclerView implements CompoundButton.OnCheckedChangeListener,
View.OnClickListener, ImageSearchLayout.Helper, TabLayout.OnTabSelectedListener {
public static final int SEARCH_MODE_NORMAL = 0;
public static final int SEARCH_MODE_IMAGE = 1;
private static final String STATE_KEY_SUPER = "super";
private static final String STATE_KEY_SEARCH_MODE = "search_mode";
private static final String STATE_KEY_ENABLE_ADVANCE = "enable_advance";
private static final int ITEM_TYPE_NORMAL = 0;
private static final int ITEM_TYPE_NORMAL_ADVANCE = 1;
private static final int ITEM_TYPE_IMAGE = 2;
private static final int ITEM_TYPE_ACTION = 3;
private static final int[] SEARCH_ITEM_COUNT_ARRAY = {
3, 2
};
private static final int[][] SEARCH_ITEM_TYPE = {
{ITEM_TYPE_NORMAL, ITEM_TYPE_NORMAL_ADVANCE, ITEM_TYPE_ACTION}, // SEARCH_MODE_NORMAL
{ITEM_TYPE_IMAGE, ITEM_TYPE_ACTION}, // SEARCH_MODE_IMAGE
};
private LayoutInflater mInflater;
@SearchMode
private int mSearchMode = SEARCH_MODE_NORMAL;
private boolean mEnableAdvance = false;
private View mNormalView;
private CategoryTable mCategoryTable;
private RadioGridGroup mNormalSearchMode;
private ImageView mNormalSearchModeHelp;
private Switch mEnableAdvanceSwitch;
private View mAdvanceView;
private AdvanceSearchTable mTableAdvanceSearch;
private ImageSearchLayout mImageView;
private View mActionView;
private TabLayout mAction;
private LinearLayoutManager mLayoutManager;
private SearchAdapter mAdapter;
private Helper mHelper;
private var mSearchMode = SEARCH_MODE_NORMAL
private var mEnableAdvance = false
private var mNormalView: View? = null
private var mNormalSearchMode: RadioGridGroup? = null
private var mNormalSearchModeHelp: ImageView? = null
private var mEnableAdvanceSwitch: Switch? = null
private var mAdvanceView: View? = null
private var mTableAdvanceSearch: AdvanceSearchTable? = null
private var mImageView: ImageSearchLayout? = null
private var mActionView: View? = null
private var mAction: TabLayout? = null
private var mLayoutManager: LinearLayoutManager? = null
private var mAdapter: SearchAdapter? = null
private var mHelper: Helper? = null
public SearchLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
private val mCategoryTable : ArrayList<Pair<Int, Int>> = arrayListOf(
Pair(EhConfig.DOUJINSHI, R.string.doujinshi),
Pair(EhConfig.MANGA, R.string.manga),
Pair(EhConfig.ARTIST_CG, R.string.artist_cg),
Pair(EhConfig.GAME_CG, R.string.game_cg),
Pair(EhConfig.WESTERN, R.string.western),
Pair(EhConfig.NON_H, R.string.non_h),
Pair(EhConfig.IMAGE_SET, R.string.image_set),
Pair(EhConfig.COSPLAY, R.string.cosplay),
Pair(EhConfig.ASIAN_PORN, R.string.asian_porn),
Pair(EhConfig.MISC, R.string.misc)
)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
mSharePref = PreferenceManager.getDefaultSharedPreferences(context)
mInflater = LayoutInflater.from(context)
init(context)
}
public SearchLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(
context,
attrs,
defStyle
) {
mSharePref = PreferenceManager.getDefaultSharedPreferences(context)
mInflater = LayoutInflater.from(context)
init(context)
}
@SuppressLint("InflateParams")
private void init(Context context) {
Resources resources = context.getResources();
mInflater = LayoutInflater.from(context);
mLayoutManager = new SearchLayoutManager(context);
mAdapter = new SearchAdapter();
mAdapter.setHasStableIds(true);
setLayoutManager(mLayoutManager);
setAdapter(mAdapter);
setHasFixedSize(true);
setClipToPadding(false);
((DefaultItemAnimator) getItemAnimator()).setSupportsChangeAnimations(false);
int interval = resources.getDimensionPixelOffset(R.dimen.search_layout_interval);
int paddingH = resources.getDimensionPixelOffset(R.dimen.search_layout_margin_h);
int paddingV = resources.getDimensionPixelOffset(R.dimen.search_layout_margin_v);
MarginItemDecoration decoration = new MarginItemDecoration(
interval, paddingH, paddingV, paddingH, paddingV);
addItemDecoration(decoration);
decoration.applyPaddings(this);
private fun init(context: Context) {
val resources = context.resources
mLayoutManager = SearchLayoutManager(context)
mAdapter = SearchAdapter()
mAdapter!!.setHasStableIds(true)
layoutManager = mLayoutManager
adapter = mAdapter
setHasFixedSize(true)
clipToPadding = false
(itemAnimator as DefaultItemAnimator?)!!.supportsChangeAnimations = false
val interval = resources.getDimensionPixelOffset(R.dimen.search_layout_interval)
val paddingH = resources.getDimensionPixelOffset(R.dimen.search_layout_margin_h)
val paddingV = resources.getDimensionPixelOffset(R.dimen.search_layout_margin_v)
val decoration = MarginItemDecoration(
interval, paddingH, paddingV, paddingH, paddingV
)
addItemDecoration(decoration)
decoration.applyPaddings(this)
// Create normal view
View normalView = mInflater.inflate(R.layout.search_normal, null);
mNormalView = normalView;
mCategoryTable = normalView.findViewById(R.id.search_category_table);
mNormalSearchMode = normalView.findViewById(R.id.normal_search_mode);
mNormalSearchModeHelp = normalView.findViewById(R.id.normal_search_mode_help);
mEnableAdvanceSwitch = normalView.findViewById(R.id.search_enable_advance);
mNormalSearchModeHelp.setOnClickListener(this);
mEnableAdvanceSwitch.setOnCheckedChangeListener(this);
mEnableAdvanceSwitch.setSwitchPadding(resources.getDimensionPixelSize(R.dimen.switch_padding));
val normalView = mInflater.inflate(R.layout.search_normal, null)
mNormalView = normalView
val mCategoryStored = mSharePref.getInt(SEARCH_CATEGORY_PREF, EhConfig.ALL_CATEGORY)
val mCategoryGroup = normalView.findViewById(R.id.search_category_chipgroup) as ChipGroup
for (mPair in mCategoryTable) {
val mChip = Chip(context)
mChip.isCheckable = true
mChip.setText(mPair.second)
mChip.isChecked = NumberUtils.int2boolean(mPair.first and mCategoryStored)
mCategoryGroup.addView(mChip)
}
mCategoryGroup.setOnCheckedStateChangeListener { group, checkedIds ->
var mCategory = 0
for (index in checkedIds) {
mCategory = mCategory or mCategoryTable[index - 1].first
}
mSharePref.edit { putInt(SEARCH_CATEGORY_PREF, mCategory) }
}
mNormalSearchMode = normalView.findViewById(R.id.normal_search_mode)
mNormalSearchModeHelp = normalView.findViewById(R.id.normal_search_mode_help)
mEnableAdvanceSwitch = normalView.findViewById(R.id.search_enable_advance)
mNormalSearchModeHelp!!.setOnClickListener(this)
mEnableAdvanceSwitch!!.setOnCheckedChangeListener(this)
mEnableAdvanceSwitch!!.switchPadding = resources.getDimensionPixelSize(R.dimen.switch_padding)
// Create advance view
mAdvanceView = mInflater.inflate(R.layout.search_advance, null);
mTableAdvanceSearch = mAdvanceView.findViewById(R.id.search_advance_search_table);
mAdvanceView = mInflater.inflate(R.layout.search_advance, null)
mTableAdvanceSearch = mAdvanceView!!.findViewById(R.id.search_advance_search_table)
// Create image view
mImageView = (ImageSearchLayout) mInflater.inflate(R.layout.search_image, null);
mImageView.setHelper(this);
mImageView = mInflater.inflate(R.layout.search_image, null) as ImageSearchLayout
mImageView!!.setHelper(this)
// Create action view
mActionView = mInflater.inflate(R.layout.search_action, null);
mActionView.setLayoutParams(new RecyclerView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
mAction = mActionView.findViewById(R.id.action);
mAction.addOnTabSelectedListener(this);
mActionView = mInflater.inflate(R.layout.search_action, null)
mActionView!!.layoutParams = LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
mAction = mActionView!!.findViewById(R.id.action)
mAction!!.addOnTabSelectedListener(this)
}
public void setHelper(Helper helper) {
mHelper = helper;
fun setHelper(helper: Helper?) {
mHelper = helper
}
public void scrollSearchContainerToTop() {
mLayoutManager.scrollToPositionWithOffset(0, 0);
fun scrollSearchContainerToTop() {
mLayoutManager!!.scrollToPositionWithOffset(0, 0)
}
public void setImageUri(Uri imageUri) {
mImageView.setImageUri(imageUri);
fun setImageUri(imageUri: Uri?) {
mImageView!!.setImageUri(imageUri)
}
public void setNormalSearchMode(int id) {
mNormalSearchMode.check(id);
fun setNormalSearchMode(id: Int) {
mNormalSearchMode!!.check(id)
}
@Override
public void onSelectImage() {
override fun onSelectImage() {
if (mHelper != null) {
mHelper.onSelectImage();
mHelper!!.onSelectImage()
}
}
@Override
protected void dispatchSaveInstanceState(@NonNull SparseArray<Parcelable> container) {
super.dispatchSaveInstanceState(container);
mNormalView.saveHierarchyState(container);
mAdvanceView.saveHierarchyState(container);
mImageView.saveHierarchyState(container);
mActionView.saveHierarchyState(container);
override fun dispatchSaveInstanceState(container: SparseArray<Parcelable>) {
super.dispatchSaveInstanceState(container)
mNormalView!!.saveHierarchyState(container)
mAdvanceView!!.saveHierarchyState(container)
mImageView!!.saveHierarchyState(container)
mActionView!!.saveHierarchyState(container)
}
@Override
protected void dispatchRestoreInstanceState(@NonNull SparseArray<Parcelable> container) {
super.dispatchRestoreInstanceState(container);
mNormalView.restoreHierarchyState(container);
mAdvanceView.restoreHierarchyState(container);
mImageView.restoreHierarchyState(container);
mActionView.restoreHierarchyState(container);
override fun dispatchRestoreInstanceState(container: SparseArray<Parcelable>) {
super.dispatchRestoreInstanceState(container)
mNormalView!!.restoreHierarchyState(container)
mAdvanceView!!.restoreHierarchyState(container)
mImageView!!.restoreHierarchyState(container)
mActionView!!.restoreHierarchyState(container)
}
@Override
public Parcelable onSaveInstanceState() {
final Bundle state = new Bundle();
state.putParcelable(STATE_KEY_SUPER, super.onSaveInstanceState());
state.putInt(STATE_KEY_SEARCH_MODE, mSearchMode);
state.putBoolean(STATE_KEY_ENABLE_ADVANCE, mEnableAdvance);
return state;
override fun onSaveInstanceState(): Parcelable {
val state = Bundle()
state.putParcelable(STATE_KEY_SUPER, super.onSaveInstanceState())
state.putInt(STATE_KEY_SEARCH_MODE, mSearchMode)
state.putBoolean(STATE_KEY_ENABLE_ADVANCE, mEnableAdvance)
return state
}
@Override
public void onRestoreInstanceState(Parcelable state) {
if (state instanceof Bundle) {
final Bundle savedState = (Bundle) state;
super.onRestoreInstanceState(savedState.getParcelable(STATE_KEY_SUPER));
mSearchMode = savedState.getInt(STATE_KEY_SEARCH_MODE);
mEnableAdvance = savedState.getBoolean(STATE_KEY_ENABLE_ADVANCE);
override fun onRestoreInstanceState(state: Parcelable) {
if (state is Bundle) {
super.onRestoreInstanceState(state.getParcelable(STATE_KEY_SUPER))
mSearchMode = state.getInt(STATE_KEY_SEARCH_MODE)
mEnableAdvance = state.getBoolean(STATE_KEY_ENABLE_ADVANCE)
}
}
@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (buttonView == mEnableAdvanceSwitch) {
post(() -> {
mEnableAdvance = isChecked;
override fun onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) {
if (buttonView === mEnableAdvanceSwitch) {
post {
mEnableAdvance = isChecked
if (mSearchMode == SEARCH_MODE_NORMAL) {
if (mEnableAdvance) {
mAdapter.notifyItemInserted(1);
mAdapter!!.notifyItemInserted(1)
} else {
mAdapter.notifyItemRemoved(1);
mAdapter!!.notifyItemRemoved(1)
}
if (mHelper != null) {
mHelper.onChangeSearchMode();
mHelper!!.onChangeSearchMode()
}
}
});
}
}
}
@SuppressLint("NonConstantResourceId")
public void formatListUrlBuilder(ListUrlBuilder urlBuilder, String query) throws EhException {
urlBuilder.reset();
switch (mSearchMode) {
case SEARCH_MODE_NORMAL:
int nsMode = mNormalSearchMode.getCheckedRadioButtonId();
if (nsMode == R.id.search_subscription_search) {
urlBuilder.setMode(ListUrlBuilder.MODE_SUBSCRIPTION);
} else if (nsMode == R.id.search_specify_uploader) {
urlBuilder.setMode(ListUrlBuilder.MODE_UPLOADER);
} else if (nsMode == R.id.search_specify_tag) {
urlBuilder.setMode(ListUrlBuilder.MODE_TAG);
} else {
urlBuilder.setMode(ListUrlBuilder.MODE_NORMAL);
@Throws(EhException::class)
fun formatListUrlBuilder(urlBuilder: ListUrlBuilder, query: String?) {
urlBuilder.reset()
when (mSearchMode) {
SEARCH_MODE_NORMAL -> {
when (mNormalSearchMode!!.checkedRadioButtonId) {
R.id.search_subscription_search -> {
urlBuilder.mode = ListUrlBuilder.MODE_SUBSCRIPTION
}
R.id.search_specify_uploader -> {
urlBuilder.mode = ListUrlBuilder.MODE_UPLOADER
}
R.id.search_specify_tag -> {
urlBuilder.mode = ListUrlBuilder.MODE_TAG
}
else -> {
urlBuilder.mode = ListUrlBuilder.MODE_NORMAL
}
}
urlBuilder.setKeyword(query);
urlBuilder.setCategory(mCategoryTable.getCategory());
urlBuilder.keyword = query
urlBuilder.category = PreferenceManager.getDefaultSharedPreferences(context).getInt(
SEARCH_CATEGORY_PREF, 0)
if (mEnableAdvance) {
urlBuilder.setAdvanceSearch(mTableAdvanceSearch.getAdvanceSearch());
urlBuilder.setMinRating(mTableAdvanceSearch.getMinRating());
urlBuilder.setPageFrom(mTableAdvanceSearch.getPageFrom());
urlBuilder.setPageTo(mTableAdvanceSearch.getPageTo());
urlBuilder.advanceSearch = mTableAdvanceSearch!!.advanceSearch
urlBuilder.minRating = mTableAdvanceSearch!!.minRating
urlBuilder.pageFrom = mTableAdvanceSearch!!.pageFrom
urlBuilder.pageTo = mTableAdvanceSearch!!.pageTo
}
break;
case SEARCH_MODE_IMAGE:
urlBuilder.setMode(ListUrlBuilder.MODE_IMAGE_SEARCH);
mImageView.formatListUrlBuilder(urlBuilder);
break;
}
SEARCH_MODE_IMAGE -> {
urlBuilder.mode = ListUrlBuilder.MODE_IMAGE_SEARCH
mImageView!!.formatListUrlBuilder(urlBuilder)
}
}
}
@Override
public void onClick(View v) {
if (mNormalSearchModeHelp == v) {
new MaterialAlertDialogBuilder(getContext())
.setMessage(R.string.search_tip)
.show();
override fun onClick(v: View) {
if (mNormalSearchModeHelp === v) {
MaterialAlertDialogBuilder(context)
.setMessage(R.string.search_tip)
.show()
}
}
@Override
public void onTabSelected(TabLayout.Tab tab) {
post(() -> setSearchMode(tab.getPosition()));
override fun onTabSelected(tab: TabLayout.Tab) {
post { setSearchMode(tab.position) }
}
public void setSearchMode(@SearchMode int mode) {
int oldItemCount = mAdapter.getItemCount();
mSearchMode = mode;
int newItemCount = mAdapter.getItemCount();
mAdapter.notifyItemRangeRemoved(0, oldItemCount - 1);
mAdapter.notifyItemRangeInserted(0, newItemCount - 1);
fun setSearchMode(@SearchMode mode: Int) {
val oldItemCount = mAdapter!!.itemCount
mSearchMode = mode
val newItemCount = mAdapter!!.itemCount
mAdapter!!.notifyItemRangeRemoved(0, oldItemCount - 1)
mAdapter!!.notifyItemRangeInserted(0, newItemCount - 1)
if (mHelper != null) {
mHelper.onChangeSearchMode();
mHelper!!.onChangeSearchMode()
}
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
override fun onTabUnselected(tab: TabLayout.Tab) {}
override fun onTabReselected(tab: TabLayout.Tab) {}
@IntDef(SEARCH_MODE_NORMAL, SEARCH_MODE_IMAGE)
@kotlin.annotation.Retention(AnnotationRetention.SOURCE)
private annotation class SearchMode
interface Helper {
fun onChangeSearchMode()
fun onSelectImage()
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
@IntDef({SEARCH_MODE_NORMAL, SEARCH_MODE_IMAGE})
@Retention(RetentionPolicy.SOURCE)
private @interface SearchMode {
}
public interface Helper {
void onChangeSearchMode();
void onSelectImage();
}
static class SearchLayoutManager extends LinearLayoutManager {
public SearchLayoutManager(Context context) {
super(context);
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
internal class SearchLayoutManager(context: Context?) : LinearLayoutManager(context) {
override fun onLayoutChildren(recycler: Recycler, state: State) {
try {
super.onLayoutChildren(recycler, state);
} catch (IndexOutOfBoundsException e) {
e.printStackTrace();
super.onLayoutChildren(recycler, state)
} catch (e: IndexOutOfBoundsException) {
e.printStackTrace()
}
}
}
private class SearchAdapter extends EasyRecyclerView.Adapter<SimpleHolder> {
@Override
public int getItemCount() {
int count = SEARCH_ITEM_COUNT_ARRAY[mSearchMode];
private inner class SearchAdapter : Adapter<SimpleHolder>() {
override fun getItemCount(): Int {
var count = SEARCH_ITEM_COUNT_ARRAY[mSearchMode]
if (mSearchMode == SEARCH_MODE_NORMAL && !mEnableAdvance) {
count--;
count--
}
return count;
return count
}
@Override
public int getItemViewType(int position) {
int type = SEARCH_ITEM_TYPE[mSearchMode][position];
override fun getItemViewType(position: Int): Int {
var type = SEARCH_ITEM_TYPE[mSearchMode][position]
if (mSearchMode == SEARCH_MODE_NORMAL && position == 1 && !mEnableAdvance) {
type = ITEM_TYPE_ACTION;
type = ITEM_TYPE_ACTION
}
return type;
return type
}
@NonNull
@Override
public SimpleHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view;
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SimpleHolder {
val view: View?
if (viewType == ITEM_TYPE_ACTION) {
ViewUtils.removeFromParent(mActionView);
view = mActionView;
ViewUtils.removeFromParent(mActionView)
view = mActionView
} else {
view = mInflater.inflate(R.layout.search_category, parent, false);
TextView title = view.findViewById(R.id.category_title);
FrameLayout content = view.findViewById(R.id.category_content);
switch (viewType) {
case ITEM_TYPE_NORMAL:
title.setText(R.string.search_normal);
ViewUtils.removeFromParent(mNormalView);
content.addView(mNormalView);
break;
case ITEM_TYPE_NORMAL_ADVANCE:
title.setText(R.string.search_advance);
ViewUtils.removeFromParent(mAdvanceView);
content.addView(mAdvanceView);
break;
case ITEM_TYPE_IMAGE:
title.setText(R.string.search_image);
ViewUtils.removeFromParent(mImageView);
content.addView(mImageView);
break;
view = mInflater.inflate(R.layout.search_category, parent, false)
val title = view.findViewById<TextView>(R.id.category_title)
val content = view.findViewById<FrameLayout>(R.id.category_content)
when (viewType) {
ITEM_TYPE_NORMAL -> {
title.setText(R.string.search_normal)
ViewUtils.removeFromParent(mNormalView)
content.addView(mNormalView)
}
ITEM_TYPE_NORMAL_ADVANCE -> {
title.setText(R.string.search_advance)
ViewUtils.removeFromParent(mAdvanceView)
content.addView(mAdvanceView)
}
ITEM_TYPE_IMAGE -> {
title.setText(R.string.search_image)
ViewUtils.removeFromParent(mImageView)
content.addView(mImageView)
}
}
}
return new SimpleHolder(view);
return SimpleHolder(view)
}
@Override
public void onBindViewHolder(SimpleHolder holder, int position) {
if (holder.getItemViewType() == ITEM_TYPE_ACTION) {
mAction.selectTab(mAction.getTabAt(mSearchMode));
override fun onBindViewHolder(holder: SimpleHolder, position: Int) {
if (holder.itemViewType == ITEM_TYPE_ACTION) {
mAction!!.selectTab(mAction!!.getTabAt(mSearchMode))
}
}
@Override
public long getItemId(int position) {
int type = SEARCH_ITEM_TYPE[mSearchMode][position];
override fun getItemId(position: Int): Long {
var type = SEARCH_ITEM_TYPE[mSearchMode][position]
if (mSearchMode == SEARCH_MODE_NORMAL && position == 1 && !mEnableAdvance) {
type = ITEM_TYPE_ACTION;
type = ITEM_TYPE_ACTION
}
return type;
return type.toLong()
}
}
}
companion object {
const val SEARCH_MODE_NORMAL = 0
const val SEARCH_MODE_IMAGE = 1
private const val STATE_KEY_SUPER = "super"
private const val STATE_KEY_SEARCH_MODE = "search_mode"
private const val STATE_KEY_ENABLE_ADVANCE = "enable_advance"
const val SEARCH_CATEGORY_PREF = "search_pref"
private const val ITEM_TYPE_NORMAL = 0
private const val ITEM_TYPE_NORMAL_ADVANCE = 1
private const val ITEM_TYPE_IMAGE = 2
private const val ITEM_TYPE_ACTION = 3
private val SEARCH_ITEM_COUNT_ARRAY = intArrayOf(
3, 2
)
private val SEARCH_ITEM_TYPE = arrayOf(
intArrayOf(ITEM_TYPE_NORMAL, ITEM_TYPE_NORMAL_ADVANCE, ITEM_TYPE_ACTION), intArrayOf(
ITEM_TYPE_IMAGE, ITEM_TYPE_ACTION
)
)
}
}
@@ -1,236 +0,0 @@
/*
* Copyright (C) 2015 Hippo Seven
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.hippo.widget;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.AppCompatCheckedTextView;
import com.hippo.ehviewer.R;
public class CheckTextView extends AppCompatCheckedTextView implements View.OnClickListener {
private final Rect mSelfBounds = new Rect();
private final Rect mOverlayBounds = new Rect();
protected boolean mForegroundInPadding = true;
boolean mForegroundBoundsChanged = false;
private Drawable mForeground;
private int mForegroundGravity = Gravity.FILL;
public CheckTextView(Context context) {
this(context, null);
}
public CheckTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CheckTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs, defStyleAttr);
}
private void init(Context context, AttributeSet attrs, int defStyleAttr) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CheckTextView,
defStyleAttr, 0);
mForegroundGravity = a.getInt(
R.styleable.CheckTextView_android_foregroundGravity, mForegroundGravity);
Drawable d = a.getDrawable(R.styleable.CheckTextView_android_foreground);
if (d != null) {
setForeground(d);
}
mForegroundInPadding = a.getBoolean(
R.styleable.CheckTextView_foregroundInsidePadding, true);
a.recycle();
setOnClickListener(this);
}
/**
* Describes how the foreground is positioned.
*
* @return foreground gravity.
* @see #setForegroundGravity(int)
*/
public int getForegroundGravity() {
return mForegroundGravity;
}
/**
* Describes how the foreground is positioned. Defaults to START and TOP.
*
* @param foregroundGravity See {@link android.view.Gravity}
* @see #getForegroundGravity()
*/
public void setForegroundGravity(int foregroundGravity) {
if (mForegroundGravity != foregroundGravity) {
if ((foregroundGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) {
foregroundGravity |= Gravity.START;
}
if ((foregroundGravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) {
foregroundGravity |= Gravity.TOP;
}
mForegroundGravity = foregroundGravity;
if (mForegroundGravity == Gravity.FILL && mForeground != null) {
Rect padding = new Rect();
mForeground.getPadding(padding);
}
requestLayout();
}
}
@Override
protected boolean verifyDrawable(@NonNull Drawable who) {
return super.verifyDrawable(who) || (who == mForeground);
}
@Override
public void jumpDrawablesToCurrentState() {
super.jumpDrawablesToCurrentState();
if (mForeground != null) {
mForeground.jumpToCurrentState();
}
}
@Override
protected void drawableStateChanged() {
super.drawableStateChanged();
if (mForeground != null && mForeground.isStateful()) {
mForeground.setState(getDrawableState());
}
}
/**
* Returns the drawable used as the foreground of this FrameLayout. The
* foreground drawable, if non-null, is always drawn on top of the children.
*
* @return A Drawable or null if no foreground was set.
*/
public Drawable getForeground() {
return mForeground;
}
/**
* Supply a Drawable that is to be rendered on top of all of the child
* views in the frame layout. Any padding in the Drawable will be taken
* into account by ensuring that the children are inset to be placed
* inside of the padding area.
*
* @param drawable The Drawable to be drawn on top of the children.
*/
public void setForeground(Drawable drawable) {
if (mForeground != drawable) {
if (mForeground != null) {
mForeground.setCallback(null);
unscheduleDrawable(mForeground);
}
mForeground = drawable;
if (drawable != null) {
setWillNotDraw(false);
drawable.setCallback(this);
if (drawable.isStateful()) {
drawable.setState(getDrawableState());
}
if (mForegroundGravity == Gravity.FILL) {
Rect padding = new Rect();
drawable.getPadding(padding);
}
} else {
setWillNotDraw(true);
}
requestLayout();
invalidate();
}
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mForegroundBoundsChanged |= changed;
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mForegroundBoundsChanged = true;
}
@Override
public void draw(@NonNull Canvas canvas) {
super.draw(canvas);
if (mForeground != null) {
final Drawable foreground = mForeground;
if (mForegroundBoundsChanged) {
mForegroundBoundsChanged = false;
final Rect selfBounds = mSelfBounds;
final Rect overlayBounds = mOverlayBounds;
final int w = getRight() - getLeft();
final int h = getBottom() - getTop();
if (mForegroundInPadding) {
selfBounds.set(0, 0, w, h);
} else {
selfBounds.set(getPaddingLeft(), getPaddingTop(),
w - getPaddingRight(), h - getPaddingBottom());
}
Gravity.apply(mForegroundGravity, foreground.getIntrinsicWidth(),
foreground.getIntrinsicHeight(), selfBounds, overlayBounds);
foreground.setBounds(overlayBounds);
}
foreground.draw(canvas);
}
}
@Override
public void drawableHotspotChanged(float x, float y) {
super.drawableHotspotChanged(x, y);
if (mForeground != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
mForeground.setHotspot(x, y);
}
}
}
@Override
public void onClick(View v) {
setChecked(!isChecked());
}
}