优化搜索界面,新增本地书籍搜索

master
fengyuecanzhu 3 years ago
parent d5c95e47b5
commit e82030a0bc
  1. 3
      .idea/gradle.xml
  2. 2
      .idea/misc.xml
  3. 251
      app/src/main/java/xyz/fycz/myreader/ui/activity/SearchBookActivity.java
  4. 47
      app/src/main/java/xyz/fycz/myreader/widget/TagGroup.java
  5. 168
      app/src/main/res/layout/activity_search_book.xml
  6. 3
      app/src/main/res/values/colors.xml
  7. 5
      app/src/main/res/values/strings.xml
  8. 1
      app/src/main/res/values/styles.xml

@ -4,7 +4,7 @@
<component name="GradleSettings"> <component name="GradleSettings">
<option name="linkedExternalProjectsSettings"> <option name="linkedExternalProjectsSettings">
<GradleProjectSettings> <GradleProjectSettings>
<option name="testRunner" value="PLATFORM" /> <option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" /> <option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" /> <option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules"> <option name="modules">
@ -15,7 +15,6 @@
</set> </set>
</option> </option>
<option name="resolveModulePerSourceSet" value="false" /> <option name="resolveModulePerSourceSet" value="false" />
<option name="useQualifiedModuleNames" value="true" />
</GradleProjectSettings> </GradleProjectSettings>
</option> </option>
</component> </component>

@ -21,7 +21,7 @@
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_more_setting.xml" value="0.264" /> <entry key="..\:/android/FYReader/app/src/main/res/layout/activity_more_setting.xml" value="0.264" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_read.xml" value="0.17028985507246377" /> <entry key="..\:/android/FYReader/app/src/main/res/layout/activity_read.xml" value="0.17028985507246377" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_register.xml" value="0.2796934865900383" /> <entry key="..\:/android/FYReader/app/src/main/res/layout/activity_register.xml" value="0.2796934865900383" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_search_book.xml" value="0.12132725430597771" /> <entry key="..\:/android/FYReader/app/src/main/res/layout/activity_search_book.xml" value="0.26904376012965964" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/activity_search_word.xml" value="0.144" /> <entry key="..\:/android/FYReader/app/src/main/res/layout/activity_search_word.xml" value="0.144" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/dialog_loading.xml" value="0.1" /> <entry key="..\:/android/FYReader/app/src/main/res/layout/dialog_loading.xml" value="0.1" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/dialog_textview.xml" value="0.1947463768115942" /> <entry key="..\:/android/FYReader/app/src/main/res/layout/dialog_textview.xml" value="0.1947463768115942" />

@ -49,6 +49,7 @@ import xyz.fycz.myreader.entity.Setting;
import xyz.fycz.myreader.greendao.entity.Book; import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.SearchHistory; import xyz.fycz.myreader.greendao.entity.SearchHistory;
import xyz.fycz.myreader.greendao.entity.rule.BookSource; import xyz.fycz.myreader.greendao.entity.rule.BookSource;
import xyz.fycz.myreader.greendao.service.BookService;
import xyz.fycz.myreader.greendao.service.SearchHistoryService; import xyz.fycz.myreader.greendao.service.SearchHistoryService;
import xyz.fycz.myreader.model.SearchEngine; import xyz.fycz.myreader.model.SearchEngine;
import xyz.fycz.myreader.model.mulvalmap.ConMVMap; import xyz.fycz.myreader.model.mulvalmap.ConMVMap;
@ -65,6 +66,7 @@ import xyz.fycz.myreader.util.utils.OkHttpUtils;
import xyz.fycz.myreader.util.utils.RxUtils; import xyz.fycz.myreader.util.utils.RxUtils;
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil; import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler; import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
import xyz.fycz.myreader.widget.TagGroup;
/** /**
* @author fengyue * @author fengyue
@ -76,14 +78,17 @@ public class SearchBookActivity extends BaseActivity {
private SearchAdapter mSearchBookAdapter; private SearchAdapter mSearchBookAdapter;
private String searchKey;//搜索关键字 private String searchKey;//搜索关键字
private List<SearchHistory> mSearchHistories = new ArrayList<>(); private List<SearchHistory> mSearchHistories;
private List<CharSequence> mSuggestions = new ArrayList<>(); private List<SearchHistory> mCurHistories = new ArrayList<>();
private List<CharSequence> mHotKeys = new ArrayList<>(); private final List<Book> mBookcase = new ArrayList<>();
private List<Book> mBooks;
private final List<CharSequence> mSuggestions = new ArrayList<>();
private final List<CharSequence> mHotKeys = new ArrayList<>();
private final List<CharSequence> mBookcaseNames = new ArrayList<>();
private final List<CharSequence> mHistoryNames = new ArrayList<>();
private SearchHistoryService mSearchHistoryService; private SearchHistoryService mSearchHistoryService;
private SearchHistoryAdapter mSearchHistoryAdapter;
private int allThreadCount; private int allThreadCount;
private SearchEngine searchEngine; private SearchEngine searchEngine;
@ -96,13 +101,19 @@ public class SearchBookActivity extends BaseActivity {
private Disposable sugDis; private Disposable sugDis;
private boolean showBooks; private Disposable hisDis;
private Disposable caseDis;
private boolean showBooks;
private static String[] suggestion = {"第一序列", "大道朝天", "伏天氏", "终极斗罗", "我师兄实在太稳健了", "烂柯棋缘", "诡秘之主", "不朽凡人", "圣墟", "我是至尊", "龙王传说", "太古神王", "一念永恒", "雪鹰领主", "大主宰"}; private static String[] suggestion = {"第一序列", "大道朝天", "伏天氏", "终极斗罗", "我师兄实在太稳健了", "烂柯棋缘", "诡秘之主", "不朽凡人", "圣墟", "我是至尊", "龙王传说", "太古神王", "一念永恒", "雪鹰领主", "大主宰"};
private boolean showHot; private boolean showHot;
private boolean foldBookcase;
private boolean foldSuggest;
private boolean foldHistory;
@Override @Override
protected void bindView() { protected void bindView() {
@ -134,7 +145,11 @@ public class SearchBookActivity extends BaseActivity {
super.initData(savedInstanceState); super.initData(savedInstanceState);
mSetting = SysManager.getSetting(); mSetting = SysManager.getSetting();
mSearchHistoryService = SearchHistoryService.getInstance(); mSearchHistoryService = SearchHistoryService.getInstance();
mBooks = BookService.getInstance().getAllBooksNoHide();
showHot = !App.isDebug(); showHot = !App.isDebug();
foldBookcase = SharedPreUtils.getInstance().getBoolean("foldBookcase");
foldSuggest = SharedPreUtils.getInstance().getBoolean("foldSuggest");
foldHistory = SharedPreUtils.getInstance().getBoolean("foldHistory");
searchEngine = new SearchEngine(); searchEngine = new SearchEngine();
searchEngine.setOnSearchListener(new SearchEngine.OnSearchListener() { searchEngine.setOnSearchListener(new SearchEngine.OnSearchListener() {
@Override @Override
@ -189,18 +204,13 @@ public class SearchBookActivity extends BaseActivity {
} }
binding.rgSearchFilter.setOnCheckedChangeListener((group, checkedId) -> { binding.rgSearchFilter.setOnCheckedChangeListener((group, checkedId) -> {
int searchFilter; int searchFilter = 0;
switch (checkedId) { if (checkedId == R.id.rb_all_search) {
case R.id.rb_all_search:
default:
searchFilter = 0; searchFilter = 0;
break; } else if (checkedId == R.id.rb_fuzzy_search) {
case R.id.rb_fuzzy_search:
searchFilter = 1; searchFilter = 1;
break; } else if (checkedId == R.id.rb_precise_search) {
case R.id.rb_precise_search:
searchFilter = 2; searchFilter = 2;
break;
} }
mSetting.setSearchFilter(searchFilter); mSetting.setSearchFilter(searchFilter);
SysManager.saveSetting(mSetting); SysManager.saveSetting(mSetting);
@ -225,6 +235,8 @@ public class SearchBookActivity extends BaseActivity {
if (StringHelper.isEmpty(searchKey)) { if (StringHelper.isEmpty(searchKey)) {
search(); search();
} }
searchBookcase();
initHistoryList();
initSuggestionList(); initSuggestionList();
} }
@ -237,6 +249,32 @@ public class SearchBookActivity extends BaseActivity {
stopSearch(); stopSearch();
search(); search();
}); });
binding.tgBookcase.setVisibility(foldBookcase ? View.GONE : View.VISIBLE);
binding.tvFlattenBookcase.setText(foldBookcase ? R.string.unfold : R.string.fold);
binding.tgSuggestBook.setVisibility(foldSuggest ? View.GONE : View.VISIBLE);
binding.tvFlattenSuggest.setText(foldSuggest ? R.string.unfold : R.string.fold);
binding.tgHistoryBooks.setVisibility(foldHistory ? View.GONE : View.VISIBLE);
binding.tvFlattenHistory.setText(foldHistory ? R.string.unfold : R.string.fold);
binding.rlBookcaseBar.setOnClickListener(v -> {
foldBookcase = !foldBookcase;
binding.tgBookcase.setVisibility(foldBookcase ? View.GONE : View.VISIBLE);
binding.tvFlattenBookcase.setText(foldBookcase ? R.string.unfold : R.string.fold);
SharedPreUtils.getInstance().putBoolean("foldBookcase", foldBookcase);
});
binding.rlSuggestBar.setOnClickListener(v -> {
foldSuggest = !foldSuggest;
binding.tgSuggestBook.setVisibility(foldSuggest ? View.GONE : View.VISIBLE);
binding.tvFlattenSuggest.setText(foldSuggest ? R.string.unfold : R.string.fold);
SharedPreUtils.getInstance().putBoolean("foldSuggest", foldSuggest);
});
binding.rlHistoryBar.setOnClickListener(v -> {
foldHistory = !foldHistory;
binding.tgHistoryBooks.setVisibility(foldHistory ? View.GONE : View.VISIBLE);
binding.tvFlattenHistory.setText(foldHistory ? R.string.unfold : R.string.fold);
SharedPreUtils.getInstance().putBoolean("foldHistory", foldHistory);
});
initHistoryList(); initHistoryList();
} }
@ -244,35 +282,43 @@ public class SearchBookActivity extends BaseActivity {
protected void initClick() { protected void initClick() {
super.initClick(); super.initClick();
//换一批点击事件
binding.llRefreshSuggestBooks.setOnClickListener(new RenewSuggestionBook());
//搜索按钮点击事件 //搜索按钮点击事件
binding.tvSearchConform.setOnClickListener(view -> search()); binding.tvSearchConform.setOnClickListener(view -> search());
//suggestion搜索事件 //suggestion搜索事件
binding.tgSuggestBook.setOnTagClickListener(tag -> { binding.tgSuggestBook.setOnTagClickListener((tag, pos) -> {
binding.etSearchKey.setText(tag); binding.etSearchKey.setText(tag);
binding.etSearchKey.setSelection(tag.length()); binding.etSearchKey.setSelection(tag.length());
search(); search();
}); });
//历史记录搜索事件 //历史记录搜索事件
binding.lvHistoryList.setOnItemClickListener((parent, view, position, id) -> { binding.tgHistoryBooks.setOnTagClickListener((tag, pos) -> {
binding.etSearchKey.setText(mSearchHistories.get(position).getContent()); binding.etSearchKey.setText(tag);
binding.etSearchKey.setSelection(mSearchHistories.get(position).getContent().length()); binding.etSearchKey.setSelection(tag.length());
search(); search();
}); });
//清空历史记录 //清空历史记录
binding.llClearHistory.setOnClickListener(v -> { binding.tvClearHistory.setOnClickListener(v -> {
DialogCreator.createCommonDialog(this, "清除搜索记录", "确定要清除全部搜索记录吗?",
true, (dialog, which) -> {
mSearchHistoryService.clearHistory(); mSearchHistoryService.clearHistory();
initHistoryList(); initHistoryList();
}, null);
}); });
//清除单个历史记录 //清除单个历史记录
binding.lvHistoryList.setOnItemLongClickListener((parent, view, position, id) -> { binding.tgHistoryBooks.setLongClickDelete(true);
if (mSearchHistories.get(position) != null) { binding.tgHistoryBooks.setOnTagChangeListener(new TagGroup.OnTagChangeListener() {
mSearchHistoryService.deleteHistory(mSearchHistories.get(position)); @Override
public void onAppend(TagGroup tagGroup, String tag) {
}
@Override
public void onDelete(TagGroup tagGroup, String tag, int pos) {
if (mCurHistories.get(pos) != null) {
mSearchHistoryService.deleteHistory(mCurHistories.get(pos));
}
initHistoryList(); initHistoryList();
} }
return true;
}); });
binding.fabSearchStop.setOnClickListener(v -> { binding.fabSearchStop.setOnClickListener(v -> {
@ -445,7 +491,6 @@ public class SearchBookActivity extends BaseActivity {
initSuggestionList(); initSuggestionList();
} }
}); });
;
} }
} }
@ -460,11 +505,10 @@ public class SearchBookActivity extends BaseActivity {
mSuggestions.clear(); mSuggestions.clear();
if (StringHelper.isEmpty(searchKey)) { if (StringHelper.isEmpty(searchKey)) {
if (mHotKeys.isEmpty()) { if (mHotKeys.isEmpty()) {
binding.llSuggestBooksView.setVisibility(View.GONE); binding.llSuggestBook.setVisibility(View.GONE);
} else { } else {
binding.llSuggestBooksView.setVisibility(View.VISIBLE); binding.llSuggestBook.setVisibility(View.VISIBLE);
binding.llRefreshSuggestBooks.setVisibility(View.VISIBLE); binding.tgSuggestBook.setTags2(mHotKeys);
binding.tgSuggestBook.setTags2(mHotKeys.subList(0, mHotKeys.size() / 2));
} }
} else { } else {
String url = "https://newzxautocmp.reader.qq.com/BookSuggAll?key=" + searchKey; String url = "https://newzxautocmp.reader.qq.com/BookSuggAll?key=" + searchKey;
@ -480,13 +524,18 @@ public class SearchBookActivity extends BaseActivity {
@Override @Override
public void onSuccess(@NotNull String s) { public void onSuccess(@NotNull String s) {
parseSuggListByKey(s); parseSuggListByKey(s);
binding.llRefreshSuggestBooks.setVisibility(View.GONE); if (mSuggestions.isEmpty()) {
binding.llSuggestBook.setVisibility(View.GONE);
return;
} else {
binding.llSuggestBook.setVisibility(View.VISIBLE);
}
binding.tgSuggestBook.setTags2(mSuggestions); binding.tgSuggestBook.setTags2(mSuggestions);
} }
@Override @Override
public void onError(Throwable e) { public void onError(Throwable e) {
binding.llSuggestBooksView.setVisibility(View.GONE); binding.llSuggestBook.setVisibility(View.GONE);
} }
}); });
} }
@ -527,32 +576,65 @@ public class SearchBookActivity extends BaseActivity {
} }
} }
private class RenewSuggestionBook implements View.OnClickListener {
@Override
public void onClick(View v) {
if (mHotKeys.size() > 0) {
String[] s = binding.tgSuggestBook.getTags();
if (s[0].equals(mHotKeys.get(0))) {
binding.tgSuggestBook.setTags2(mHotKeys.subList(mHotKeys.size() / 2, mHotKeys.size()));
} else {
binding.tgSuggestBook.setTags2(mHotKeys.subList(0, mHotKeys.size() / 2));
}
}
}
}
/** /**
* 初始化历史列表 * 初始化历史列表
*/ */
private void initHistoryList() { private void initHistoryList() {
if (hisDis != null) {
hisDis.dispose();
}
Single.create((SingleOnSubscribe<Boolean>) emitter -> {
mSearchHistories = mSearchHistoryService.findAllSearchHistory(); mSearchHistories = mSearchHistoryService.findAllSearchHistory();
mHistoryNames.clear();
mCurHistories.clear();
if (mSearchHistories == null || mSearchHistories.size() == 0) { if (mSearchHistories == null || mSearchHistories.size() == 0) {
binding.llHistoryView.setVisibility(View.GONE); emitter.onSuccess(false);
} else { } else {
mSearchHistoryAdapter = new SearchHistoryAdapter(this, R.layout.listview_search_history_item, mSearchHistories); if (StringHelper.isEmpty(searchKey)) {
binding.lvHistoryList.setAdapter(mSearchHistoryAdapter); mCurHistories.addAll(mSearchHistories);
binding.llHistoryView.setVisibility(View.VISIBLE); for (SearchHistory history : mSearchHistories) {
mHistoryNames.add(history.getContent());
} }
} else {
for (SearchHistory history : mSearchHistories) {
String title = history.getContent();
int start = title.indexOf(searchKey);
if (start != -1) {
SpannableString spannableString = new SpannableString(title);
spannableString.setSpan(new ForegroundColorSpan(Color.RED),
start, start + searchKey.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
mHistoryNames.add(spannableString);
mCurHistories.add(history);
}
}
}
emitter.onSuccess(!mHistoryNames.isEmpty());
}
}).compose(RxUtils::toSimpleSingle).subscribe(new MySingleObserver<Boolean>() {
@Override
public void onSubscribe(Disposable d) {
addDisposable(d);
hisDis = d;
}
@Override
public void onSuccess(@NonNull Boolean aBoolean) {
if (aBoolean) {
binding.llHistoryBooks.setVisibility(View.VISIBLE);
binding.tgHistoryBooks.setTags2(mHistoryNames);
} else {
binding.llHistoryBooks.setVisibility(View.GONE);
}
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
binding.llHistoryBooks.setVisibility(View.GONE);
}
});
} }
/** /**
@ -561,9 +643,67 @@ public class SearchBookActivity extends BaseActivity {
private void initSearchList() { private void initSearchList() {
//initmBooksBean(); //initmBooksBean();
binding.rvSearchBooksList.setVisibility(View.VISIBLE); binding.rvSearchBooksList.setVisibility(View.VISIBLE);
binding.llSuggestBooksView.setVisibility(View.GONE); binding.llPreKeys.setVisibility(View.GONE);
}
/**
* 搜索书架
*/
private void searchBookcase() {
if (caseDis != null) {
caseDis.dispose();
}
if (StringHelper.isEmpty(searchKey)) {
binding.llBookcase.setVisibility(View.GONE);
} else {
Single.create((SingleOnSubscribe<Boolean>) emitter -> {
mBookcase.clear();
mBookcaseNames.clear();
for (Book book : mBooks) {
String title = book.getName() + "-" + book.getAuthor();
if ("本地书籍".equals(book.getType())) {
title += "[本地]";
}
int start = title.indexOf(searchKey);
if (start != -1) {
SpannableString spannableString = new SpannableString(title);
spannableString.setSpan(new ForegroundColorSpan(Color.RED),
start, start + searchKey.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
mBookcaseNames.add(spannableString);
mBookcase.add(book);
}
}
emitter.onSuccess(!mBookcase.isEmpty());
}).compose(RxUtils::toSimpleSingle).subscribe(new MySingleObserver<Boolean>() {
@Override
public void onSubscribe(Disposable d) {
addDisposable(d);
caseDis = d;
} }
@Override
public void onSuccess(@NonNull Boolean aBoolean) {
if (aBoolean) {
binding.llBookcase.setVisibility(View.VISIBLE);
binding.tgBookcase.setTags2(mBookcaseNames);
binding.tgBookcase.setOnTagClickListener((tag, pos) -> {
Intent intent = new Intent(SearchBookActivity.this, BookDetailedActivity.class);
BitIntentDataManager.getInstance().putData(intent, mBookcase.get(pos));
startActivity(intent);
});
} else {
binding.llBookcase.setVisibility(View.GONE);
}
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
binding.llBookcase.setVisibility(View.GONE);
}
});
}
}
/** /**
* 获取搜索数据 * 获取搜索数据
@ -595,7 +735,7 @@ public class SearchBookActivity extends BaseActivity {
stopSearch(); stopSearch();
binding.rpb.setIsAutoLoading(false); binding.rpb.setIsAutoLoading(false);
binding.rvSearchBooksList.setVisibility(View.GONE); binding.rvSearchBooksList.setVisibility(View.GONE);
binding.llSuggestBooksView.setVisibility(View.VISIBLE); binding.llPreKeys.setVisibility(View.VISIBLE);
binding.fabSearchStop.setVisibility(View.GONE); binding.fabSearchStop.setVisibility(View.GONE);
initHistoryList(); initHistoryList();
binding.rvSearchBooksList.setAdapter(null); binding.rvSearchBooksList.setAdapter(null);
@ -606,8 +746,7 @@ public class SearchBookActivity extends BaseActivity {
binding.rvSearchBooksList.setAdapter(mSearchBookAdapter); binding.rvSearchBooksList.setAdapter(mSearchBookAdapter);
binding.srlSearchBookList.setEnableRefresh(true); binding.srlSearchBookList.setEnableRefresh(true);
binding.rvSearchBooksList.setVisibility(View.VISIBLE); binding.rvSearchBooksList.setVisibility(View.VISIBLE);
binding.llSuggestBooksView.setVisibility(View.GONE); binding.llPreKeys.setVisibility(View.GONE);
binding.llHistoryView.setVisibility(View.GONE);
binding.fabSearchStop.setVisibility(View.VISIBLE); binding.fabSearchStop.setVisibility(View.VISIBLE);
getData(); getData();
mSearchHistoryService.addOrUpadteHistory(searchKey); mSearchHistoryService.addOrUpadteHistory(searchKey);

@ -70,6 +70,9 @@ public class TagGroup extends ViewGroup {
private final float default_horizontal_padding; private final float default_horizontal_padding;
private final float default_vertical_padding; private final float default_vertical_padding;
/** Indicate whether the tags are deleted by holding down. Default is false. */
private boolean isLongClickDelete;
/** Indicates whether this TagGroup is set up to APPEND mode or DISPLAY mode. Default is false. */ /** Indicates whether this TagGroup is set up to APPEND mode or DISPLAY mode. Default is false. */
private boolean isAppendMode; private boolean isAppendMode;
@ -156,6 +159,7 @@ public class TagGroup extends ViewGroup {
// Load styled attributes. // Load styled attributes.
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TagGroup, defStyleAttr, R.style.TagGroup); final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TagGroup, defStyleAttr, R.style.TagGroup);
try { try {
isLongClickDelete = a.getBoolean(R.styleable.TagGroup_atg_isLongClickDelete, false);
isAppendMode = a.getBoolean(R.styleable.TagGroup_atg_isAppendMode, false); isAppendMode = a.getBoolean(R.styleable.TagGroup_atg_isAppendMode, false);
inputHint = a.getText(R.styleable.TagGroup_atg_inputHint); inputHint = a.getText(R.styleable.TagGroup_atg_inputHint);
borderColor = a.getColor(R.styleable.TagGroup_atg_borderColor, default_border_color); borderColor = a.getColor(R.styleable.TagGroup_atg_borderColor, default_border_color);
@ -492,8 +496,15 @@ public class TagGroup extends ViewGroup {
throw new IllegalStateException("Already has a INPUT tag in group."); throw new IllegalStateException("Already has a INPUT tag in group.");
} }
final TagView newInputTag = new TagView(getContext(), TagView.STATE_INPUT, tag); final TagView newInputTag = new TagView(getContext(), TagView.STATE_INPUT, tag, getChildCount());
newInputTag.setOnClickListener(mInternalTagClickListener); newInputTag.setOnClickListener(mInternalTagClickListener);
newInputTag.setOnLongClickListener(v -> {
if (isLongClickDelete) {
deleteTag(newInputTag);
return true;
}
return false;
});
addView(newInputTag); addView(newInputTag);
} }
@ -503,8 +514,15 @@ public class TagGroup extends ViewGroup {
* @param tag the tag to append. * @param tag the tag to append.
*/ */
protected void appendTag(CharSequence tag) { protected void appendTag(CharSequence tag) {
final TagView newTag = new TagView(getContext(), TagView.STATE_NORMAL, tag); final TagView newTag = new TagView(getContext(), TagView.STATE_NORMAL, tag, getChildCount());
newTag.setOnClickListener(mInternalTagClickListener); newTag.setOnClickListener(mInternalTagClickListener);
newTag.setOnLongClickListener(v -> {
if (isLongClickDelete) {
deleteTag(newTag);
return true;
}
return false;
});
addView(newTag); addView(newTag);
} }
@ -532,10 +550,18 @@ public class TagGroup extends ViewGroup {
mOnTagClickListener = l; mOnTagClickListener = l;
} }
/**
* Set up whether the tags are deleted by holding down.
* @param longClickDelete
*/
public void setLongClickDelete(boolean longClickDelete) {
isLongClickDelete = longClickDelete;
}
protected void deleteTag(TagView tagView) { protected void deleteTag(TagView tagView) {
removeView(tagView); removeView(tagView);
if (mOnTagChangeListener != null) { if (mOnTagChangeListener != null) {
mOnTagChangeListener.onDelete(TagGroup.this, tagView.getText().toString()); mOnTagChangeListener.onDelete(TagGroup.this, tagView.getText().toString(), tagView.pos);
} }
} }
@ -555,7 +581,7 @@ public class TagGroup extends ViewGroup {
* *
* @param tag the deleted tag. * @param tag the deleted tag.
*/ */
void onDelete(TagGroup tagGroup, String tag); void onDelete(TagGroup tagGroup, String tag, int pos);
} }
/** /**
@ -567,7 +593,7 @@ public class TagGroup extends ViewGroup {
* *
* @param tag The tag text of the tag that was clicked. * @param tag The tag text of the tag that was clicked.
*/ */
void onTagClick(String tag); void onTagClick(String tag, int pos);
} }
/** /**
@ -630,6 +656,7 @@ public class TagGroup extends ViewGroup {
* The tag view click listener for internal use. * The tag view click listener for internal use.
*/ */
class InternalTagClickListener implements OnClickListener { class InternalTagClickListener implements OnClickListener {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
final TagView tag = (TagView) v; final TagView tag = (TagView) v;
@ -656,7 +683,7 @@ public class TagGroup extends ViewGroup {
} }
} else { } else {
if (mOnTagClickListener != null) { if (mOnTagClickListener != null) {
mOnTagClickListener.onTagClick(tag.getText().toString()); mOnTagClickListener.onTagClick(tag.getText().toString(), tag.pos);
} }
} }
} }
@ -669,6 +696,9 @@ public class TagGroup extends ViewGroup {
public static final int STATE_NORMAL = 1; public static final int STATE_NORMAL = 1;
public static final int STATE_INPUT = 2; public static final int STATE_INPUT = 2;
/** The position in the group. */
private int pos = -1;
/** The offset to the text. */ /** The offset to the text. */
private static final int CHECKED_MARKER_OFFSET = 3; private static final int CHECKED_MARKER_OFFSET = 3;
@ -724,8 +754,9 @@ public class TagGroup extends ViewGroup {
} }
public TagView(Context context, final int state, CharSequence text) { public TagView(Context context, final int state, CharSequence text, int pos) {
super(context); super(context);
this.pos = pos;
setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding); setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding);
setLayoutParams(new LayoutParams( setLayoutParams(new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT,
@ -788,7 +819,7 @@ public class TagGroup extends ViewGroup {
if (lastNormalTagView.isChecked) { if (lastNormalTagView.isChecked) {
removeView(lastNormalTagView); removeView(lastNormalTagView);
if (mOnTagChangeListener != null) { if (mOnTagChangeListener != null) {
mOnTagChangeListener.onDelete(TagGroup.this, lastNormalTagView.getText().toString()); mOnTagChangeListener.onDelete(TagGroup.this, lastNormalTagView.getText().toString(), pos);
} }
} else { } else {
final TagView checkedTagView = getCheckedTag(); final TagView checkedTagView = getCheckedTag();

@ -87,8 +87,12 @@
android:layout_height="3dp" android:layout_height="3dp"
android:visibility="visible" /> android:visibility="visible" />
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout <LinearLayout
android:id="@+id/ll_suggest_books_view" android:id="@+id/ll_pre_keys"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@color/colorForeground" android:background="@color/colorForeground"
@ -96,94 +100,156 @@
android:orientation="vertical" android:orientation="vertical"
android:padding="5dp"> android:padding="5dp">
<LinearLayout
android:id="@+id/ll_bookcase"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingHorizontal="5dp"
android:visibility="gone">
<RelativeLayout
android:id="@+id/rl_bookcase_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingVertical="5dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:paddingVertical="2dp"
android:text="@string/bookcase"
android:textColor="@color/blue_bar"
android:textSize="@dimen/text_default_size" />
<TextView
android:id="@+id/tv_flatten_bookcase"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentEnd="true"
android:layout_marginStart="10dp"
android:text="@string/fold"
android:textColor="@color/blue_bar"
android:textSize="@dimen/text_default_size" />
</RelativeLayout>
<xyz.fycz.myreader.widget.TagGroup <xyz.fycz.myreader.widget.TagGroup
android:id="@+id/tg_suggest_book" android:id="@+id/tg_bookcase"
style="@style/TagGroup" style="@style/TagGroup"
android:layout_marginTop="5dp"
android:paddingStart="5dp"
android:paddingEnd="5dp"
app:atg_backgroundColor="@color/colorBackground" app:atg_backgroundColor="@color/colorBackground"
app:atg_borderColor="@color/colorForeground" app:atg_borderColor="@color/colorForeground"
app:atg_horizontalPadding="5dp" app:atg_horizontalPadding="5dp"
app:atg_textColor="@color/textPrimary" app:atg_textColor="@color/textPrimary"
app:atg_textSize="14sp" app:atg_textSize="14sp"
app:atg_verticalSpacing="5dp" /> app:atg_verticalSpacing="5dp" />
</LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/ll_refresh_suggest_books" android:id="@+id/ll_suggest_book"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="8dp" android:orientation="vertical"
android:gravity="center" android:paddingHorizontal="5dp"
android:orientation="horizontal"> android:visibility="visible">
<ImageView <RelativeLayout
android:id="@+id/renew_image" android:id="@+id/rl_suggest_bar"
android:layout_width="wrap_content" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:srcCompat="@drawable/ic_refresh" android:paddingVertical="5dp">
app:tint="@color/textPrimary" />
<TextView <TextView
android:id="@+id/renew_text"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:text="换一批" android:paddingVertical="2dp"
android:textColor="@color/textPrimary" android:text="@string/recommend"
android:textSize="14sp" /> android:textColor="@color/blue_bar"
android:textSize="@dimen/text_default_size" />
<TextView
android:id="@+id/tv_flatten_suggest"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentEnd="true"
android:layout_marginStart="10dp"
android:text="@string/fold"
android:textColor="@color/blue_bar"
android:textSize="@dimen/text_default_size" />
</RelativeLayout>
</LinearLayout>
<xyz.fycz.myreader.widget.TagGroup
android:id="@+id/tg_suggest_book"
style="@style/TagGroup"
app:atg_backgroundColor="@color/colorBackground"
app:atg_borderColor="@color/colorForeground"
app:atg_horizontalPadding="5dp"
app:atg_textColor="@color/textPrimary"
app:atg_textSize="14sp"
app:atg_verticalSpacing="5dp" />
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/ll_history_view" android:id="@+id/ll_history_books"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@color/colorForeground"
android:gravity="center"
android:orientation="vertical" android:orientation="vertical"
android:padding="5dp"> android:paddingHorizontal="5dp"
android:visibility="visible">
<ListView <RelativeLayout
android:id="@+id/lv_history_list" android:id="@+id/rl_history_bar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="wrap_content"
android:layout_weight="1" android:paddingVertical="5dp">
android:divider="@color/nothing"
android:fadingEdge="none"
android:overScrollMode="never"
android:scrollbars="none">
</ListView>
<LinearLayout <TextView
android:id="@+id/ll_clear_history"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:gravity="center" android:layout_alignParentStart="true"
android:orientation="horizontal"> android:text="@string/history_record"
android:textColor="@color/blue_bar"
android:textSize="@dimen/text_default_size" />
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
app:srcCompat="@drawable/ic_clear"
app:tint="@color/textPrimary" />
<TextView <TextView
android:id="@+id/tv_clear_history"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="match_parent"
android:text="清空历史记录" android:layout_toStartOf="@+id/tv_flatten_history"
android:textColor="@color/textPrimary" android:text="@string/clear_search"
android:textSize="14sp" /> android:textColor="@color/blue_bar"
android:textSize="@dimen/text_default_size" />
<TextView
android:id="@+id/tv_flatten_history"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentEnd="true"
android:layout_marginStart="10dp"
android:text="@string/fold"
android:textColor="@color/blue_bar"
android:textSize="@dimen/text_default_size" />
</LinearLayout>
</RelativeLayout>
<xyz.fycz.myreader.widget.TagGroup
android:id="@+id/tg_history_books"
style="@style/TagGroup"
app:atg_backgroundColor="@color/colorBackground"
app:atg_borderColor="@color/colorForeground"
app:atg_horizontalPadding="5dp"
app:atg_textColor="@color/textPrimary"
app:atg_textSize="14sp"
app:atg_verticalSpacing="5dp" />
</LinearLayout> </LinearLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
@ -231,12 +297,12 @@
android:layout_alignParentBottom="true" android:layout_alignParentBottom="true"
android:layout_marginEnd="30dp" android:layout_marginEnd="30dp"
android:layout_marginBottom="30dp" android:layout_marginBottom="30dp"
android:contentDescription="@string/stop"
android:src="@drawable/ic_stop_black_24dp" android:src="@drawable/ic_stop_black_24dp"
android:visibility="gone" android:visibility="gone"
app:elevation="5dp" app:elevation="5dp"
app:fabSize="mini" app:fabSize="mini"
app:layout_anchorGravity="right|bottom" app:layout_anchorGravity="right|bottom" />
android:contentDescription="@string/stop" />
</RelativeLayout> </RelativeLayout>
</LinearLayout> </LinearLayout>

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<color name="colorPrimary">#FF2196F3</color> <color name="colorPrimary">@color/blue_bar</color>
<color name="colorPrimaryDark">#3F51B5</color> <color name="colorPrimaryDark">#3F51B5</color>
<color name="colorAccent">#90cbf6</color> <color name="colorAccent">#90cbf6</color>
@ -102,6 +102,7 @@
<color name="deep_blue">#18188a</color> <color name="deep_blue">#18188a</color>
<color name="blue_bar">#FF2196F3</color>
<!-- 浅蓝色 --> <!-- 浅蓝色 -->

@ -518,6 +518,11 @@
<string name="clear_result">清除搜索结果</string> <string name="clear_result">清除搜索结果</string>
<string name="get_email_code">发送验证码</string> <string name="get_email_code">发送验证码</string>
<string name="re_get_email_code">重新发送%s</string> <string name="re_get_email_code">重新发送%s</string>
<string name="recommend">推荐</string>
<string name="history_record">搜索记录(长按删除)</string>
<string name="clear_search">清除搜索记录</string>
<string name="fold">收起</string>
<string name="unfold">展开</string>
<string-array name="reset_screen_time"> <string-array name="reset_screen_time">

@ -273,6 +273,7 @@
<!-- TagGroup --> <!-- TagGroup -->
<declare-styleable name="TagGroup"> <declare-styleable name="TagGroup">
<attr name="atg_isLongClickDelete" format="boolean" />
<attr name="atg_isAppendMode" format="boolean" /> <attr name="atg_isAppendMode" format="boolean" />
<attr name="atg_inputHint" format="string" /> <attr name="atg_inputHint" format="string" />
<attr name="atg_borderColor" format="color" /> <attr name="atg_borderColor" format="color" />

Loading…
Cancel
Save