优化搜索、修复bug

pull/5/head v1.9.1
fengyuecanzhu 4 years ago
parent 9654badccd
commit 2846daff3d
  1. BIN
      .idea/caches/build_file_checksums.ser
  2. 2
      LICENSE
  3. 4
      README.md
  4. 4
      app/build.gradle
  5. 16
      app/src/main/assets/updatelog.fy
  6. 68
      app/src/main/java/xyz/fycz/myreader/entity/SearchBookBean.java
  7. 1
      app/src/main/java/xyz/fycz/myreader/greendao/entity/Book.java
  8. 5
      app/src/main/java/xyz/fycz/myreader/model/source/BookSourceManager.java
  9. 1
      app/src/main/java/xyz/fycz/myreader/model/source/MatcherAnalyzer.java
  10. 51
      app/src/main/java/xyz/fycz/myreader/ui/activity/BookDetailedActivity.java
  11. 46
      app/src/main/java/xyz/fycz/myreader/ui/activity/SearchBookActivity.java
  12. 50
      app/src/main/java/xyz/fycz/myreader/ui/adapter/BookTagAdapter.java
  13. 8
      app/src/main/java/xyz/fycz/myreader/ui/adapter/BookcaseDetailedAdapter.java
  14. 8
      app/src/main/java/xyz/fycz/myreader/ui/adapter/BookcaseDragAdapter.java
  15. 55
      app/src/main/java/xyz/fycz/myreader/ui/adapter/SearchBookAdapter.java
  16. 10
      app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/BookStoreBookHolder.java
  17. 4
      app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/LocalSourceHolder.java
  18. 177
      app/src/main/java/xyz/fycz/myreader/ui/adapter/holder/SearchBookHolder.java
  19. 2
      app/src/main/java/xyz/fycz/myreader/ui/fragment/DIYSourceFragment.java
  20. 11
      app/src/main/java/xyz/fycz/myreader/webapi/CommonApi.java
  21. 40
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/ReadCrawlerUtil.java
  22. 13
      app/src/main/java/xyz/fycz/myreader/webapi/crawler/base/BaseSourceCrawler.java
  23. 5
      app/src/main/java/xyz/fycz/myreader/widget/page/NetPageLoader.java
  24. 8
      app/src/main/res/drawable/tag_blue_shape.xml
  25. 8
      app/src/main/res/drawable/tag_green_shape.xml
  26. 8
      app/src/main/res/drawable/tag_red_shape.xml
  27. 11
      app/src/main/res/layout/item_book_tag.xml
  28. 31
      app/src/main/res/layout/layout_book_detail_header.xml
  29. 87
      app/src/main/res/layout/listview_search_book_item.xml
  30. 6
      app/src/main/res/menu/menu_search.xml
  31. 39
      app/src/test/java/Test.java
  32. 4
      app/version_code.properties

@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier same "printed page" as the copyright notice for easier
identification within third-party archives. identification within third-party archives.
Copyright 2020 fengyuecanzhu Copyright 2020~2021 fengyuecanzhu
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

@ -2,7 +2,7 @@
风月读书,一款开源、无广告的小说阅读软件。 风月读书,一款开源、无广告的小说阅读软件。
成品下载(v1.9.0-beta 支持自定义书源):[https://fycz.lanzous.com/ixI19lqnscf](https://fycz.lanzous.com/ixI19lqnscf) 成品下载(v1.9.1 支持自定义书源):[https://fycz.lanzous.com/ijJsnmcfwja](https://fycz.lanzous.com/ijJsnmcfwja)
[更新日志](./app/src/main/assets/updatelog.fy) [更新日志](./app/src/main/assets/updatelog.fy)
@ -39,7 +39,7 @@
## LICENSE ## LICENSE
``` ```
Copyright 2020 fengyuecanzhu Copyright 2020~2021 fengyuecanzhu
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

@ -44,7 +44,7 @@ def getVersionName(){
def hun = (version / 100).toInteger() def hun = (version / 100).toInteger()
def ten = (version / 10).toInteger() % 10 def ten = (version / 10).toInteger() % 10
def one = version % 10 def one = version % 10
return hun + "." + ten + "." + one + "-beta" return hun + "." + ten + "." + one
} }
def versionN = getVersionName() def versionN = getVersionName()
@ -188,6 +188,8 @@ dependencies {
// //
implementation 'com.github.albfernandez:juniversalchardet:2.4.0' implementation 'com.github.albfernandez:juniversalchardet:2.4.0'
// https://github.com/hongyangAndroid/FlowLayout
implementation 'com.hyman:flowlayout-lib:1.1.2'
} }
greendao { greendao {

@ -1,3 +1,9 @@
2021.03.01
风月读书v1.9.1
更新内容:
1、优化搜索
2、修复已知bug
2020.02.16 2020.02.16
风月读书v1.9.0-beta 风月读书v1.9.0-beta
更新内容: 更新内容:
@ -17,16 +23,6 @@
4、修复已知bug 4、修复已知bug
5、支持分享本地书籍(txt) 5、支持分享本地书籍(txt)
公告:
2021.02.06:
昨天应该是某站打击盗版导致许多小说网站被墙,书籍无法更新或加载,
您可通过科学上网或换源来获取书籍内容,或者等待网站恢复后更新软件。
被墙的书源网站:天籁小说、笔趣阁44、全本小说、米趣小说、九桃小说、
云中书库、小说旗、老幺小说、传奇小说、星星小说
当前已恢复的网站:天籁小说、小说旗(需要更新软件)
2020.02.01 2020.02.01
风月读书v1.8.1 风月读书v1.8.1
1、新增书源:笔尖小说、言情楼、卧龙小说 1、新增书源:笔尖小说、言情楼、卧龙小说

@ -7,9 +7,15 @@ import java.util.Objects;
* @date 2020/5/19 9:19 * @date 2020/5/19 9:19
*/ */
public class SearchBookBean { public class SearchBookBean {
private String name;//书名 private String name;
private String author;//作者 private String author;
private int sourceCount;//书源数量 private String type;
private String desc;
private String status;
private String wordCount;
private String lastChapter;
private String updateTime;
private String imgUrl;
public SearchBookBean() { public SearchBookBean() {
} }
@ -35,12 +41,60 @@ public class SearchBookBean {
this.author = author; this.author = author;
} }
public int getSourceCount() { public String getType() {
return sourceCount; return type;
} }
public void setSourceCount(int sourceCount) { public void setType(String type) {
this.sourceCount = sourceCount; this.type = type;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getWordCount() {
return wordCount;
}
public void setWordCount(String wordCount) {
this.wordCount = wordCount;
}
public String getLastChapter() {
return lastChapter;
}
public void setLastChapter(String lastChapter) {
this.lastChapter = lastChapter;
}
public String getUpdateTime() {
return updateTime;
}
public void setUpdateTime(String updateTime) {
this.updateTime = updateTime;
}
public String getImgUrl() {
return imgUrl;
}
public void setImgUrl(String imgUrl) {
this.imgUrl = imgUrl;
} }
@Override @Override

@ -341,5 +341,4 @@ public class Book implements Serializable {
this.status = status; this.status = status;
} }
} }

@ -109,12 +109,13 @@ public class BookSourceManager {
*/ */
@Nullable @Nullable
public static BookSource getBookSourceByEName(String ename) { public static BookSource getBookSourceByEName(String ename) {
if (ename == null) return getDefaultSource();
if ("local".equals(ename)) return getLocalSource(); if ("local".equals(ename)) return getLocalSource();
return GreenDaoManager.getDaoSession().getBookSourceDao(). BookSource source = GreenDaoManager.getDaoSession().getBookSourceDao().
queryBuilder() queryBuilder()
.where(BookSourceDao.Properties.SourceEName.eq(ename)) .where(BookSourceDao.Properties.SourceEName.eq(ename))
.unique(); .unique();
if (source == null) return getDefaultSource();
return source;
} }
/** /**

@ -104,6 +104,7 @@ public class MatcherAnalyzer extends BaseAnalyzer{
rules[1] = rules[1].replace("(*)", ".*"); rules[1] = rules[1].replace("(*)", ".*");
rMatcher = Pattern.compile(rules[1]).matcher(html); rMatcher = Pattern.compile(rules[1]).matcher(html);
while ((lIndex = html.indexOf(rules[0], lIndex)) != -1) { while ((lIndex = html.indexOf(rules[0], lIndex)) != -1) {
lIndex += rules[0].length();
while (rIndex < lIndex && rMatcher.find()) { while (rIndex < lIndex && rMatcher.find()) {
rIndex = rMatcher.start(); rIndex = rMatcher.start();
} }

@ -45,6 +45,7 @@ import xyz.fycz.myreader.base.observer.MySingleObserver;
import xyz.fycz.myreader.common.APPCONST; import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.common.URLCONST; import xyz.fycz.myreader.common.URLCONST;
import xyz.fycz.myreader.databinding.ActivityBookDetailBinding; import xyz.fycz.myreader.databinding.ActivityBookDetailBinding;
import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.entity.SharedBook; import xyz.fycz.myreader.entity.SharedBook;
import xyz.fycz.myreader.greendao.entity.Book; import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.Chapter; import xyz.fycz.myreader.greendao.entity.Chapter;
@ -52,6 +53,7 @@ import xyz.fycz.myreader.greendao.entity.rule.BookSource;
import xyz.fycz.myreader.greendao.service.BookService; import xyz.fycz.myreader.greendao.service.BookService;
import xyz.fycz.myreader.model.source.BookSourceManager; import xyz.fycz.myreader.model.source.BookSourceManager;
import xyz.fycz.myreader.greendao.service.ChapterService; import xyz.fycz.myreader.greendao.service.ChapterService;
import xyz.fycz.myreader.ui.adapter.BookTagAdapter;
import xyz.fycz.myreader.ui.adapter.DetailCatalogAdapter; import xyz.fycz.myreader.ui.adapter.DetailCatalogAdapter;
import xyz.fycz.myreader.ui.dialog.BookGroupDialog; import xyz.fycz.myreader.ui.dialog.BookGroupDialog;
import xyz.fycz.myreader.ui.dialog.DialogCreator; import xyz.fycz.myreader.ui.dialog.DialogCreator;
@ -94,6 +96,7 @@ public class BookDetailedActivity extends BaseActivity {
private SourceExchangeDialog mSourceDialog; private SourceExchangeDialog mSourceDialog;
private int sourceIndex; private int sourceIndex;
private BookGroupDialog mBookGroupDia; private BookGroupDialog mBookGroupDia;
private List<String> tagList = new ArrayList<>();
@SuppressLint("HandlerLeak") @SuppressLint("HandlerLeak")
private Handler mHandler = new Handler() { private Handler mHandler = new Handler() {
@ -146,10 +149,32 @@ public class BookDetailedActivity extends BaseActivity {
if (isCollected) { if (isCollected) {
mChapters = (ArrayList<Chapter>) mChapterService.findBookAllChapterByBookId(mBook.getId()); mChapters = (ArrayList<Chapter>) mChapterService.findBookAllChapterByBookId(mBook.getId());
} }
//Dialog
mSourceDialog = new SourceExchangeDialog(this, mBook);
if (isBookSourceNotExist()){
DialogCreator.createCommonDialog(this, "未知书源",
"当前书籍的书源不存在,是否搜索以切换书源?", false, (dialog, which) -> {
mSourceDialog.show();
}, null);
}
mBookGroupDia = new BookGroupDialog(this); mBookGroupDia = new BookGroupDialog(this);
mReadCrawler = ReadCrawlerUtil.getReadCrawler(mBook.getSource()); mReadCrawler = ReadCrawlerUtil.getReadCrawler(mBook.getSource());
} }
private void initTagList() {
tagList.clear();
String type = mBook.getType();
if (!StringHelper.isEmpty(type))
tagList.add("0:" + type);
String wordCount = mBook.getWordCount();
if (!StringHelper.isEmpty(wordCount))
tagList.add("1:" + wordCount);
String status = mBook.getStatus();
if (!StringHelper.isEmpty(status))
tagList.add("2:" + status);
binding.ih.tflBookTag.setAdapter(new BookTagAdapter(this, tagList, 13));
}
@Override @Override
protected void setUpToolbar(Toolbar toolbar) { protected void setUpToolbar(Toolbar toolbar) {
super.setUpToolbar(toolbar); super.setUpToolbar(toolbar);
@ -182,8 +207,6 @@ public class BookDetailedActivity extends BaseActivity {
binding.ib.bookDetailTvOpen.setText("继续阅读"); binding.ib.bookDetailTvOpen.setText("继续阅读");
} }
//Dialog
mSourceDialog = new SourceExchangeDialog(this, mBook);
if (aBooks != null && aBooks.size() > 0) { if (aBooks != null && aBooks.size() > 0) {
if (isCollected) { if (isCollected) {
for (int i = 0; i < aBooks.size(); i++) { for (int i = 0; i < aBooks.size(); i++) {
@ -304,6 +327,11 @@ public class BookDetailedActivity extends BaseActivity {
} }
} }
private boolean isBookSourceNotExist(){
BookSource source = BookSourceManager.getBookSourceByStr(mBook.getSource());
return source.getSourceEName() != null && "fynovel".equals(source.getSourceEName());
}
/** /**
* 初始化书籍信息 * 初始化书籍信息
*/ */
@ -312,12 +340,8 @@ public class BookDetailedActivity extends BaseActivity {
if (StringHelper.isEmpty(mBook.getImgUrl())) { if (StringHelper.isEmpty(mBook.getImgUrl())) {
mBook.setImgUrl(""); mBook.setImgUrl("");
} }
initTagList();
binding.ic.bookDetailTvDesc.setText(""); binding.ic.bookDetailTvDesc.setText("");
if (mBook.getType() != null) {
binding.ih.bookDetailTvType.setText(mBook.getType());
} else {
binding.ih.bookDetailTvType.setText("");
}
BookSource source = BookSourceManager.getBookSourceByStr(mBook.getSource()); BookSource source = BookSourceManager.getBookSourceByStr(mBook.getSource());
binding.ih.bookDetailSource.setText(String.format("书源:%s", source.getSourceName())); binding.ih.bookDetailSource.setText(String.format("书源:%s", source.getSourceName()));
ReadCrawler rc = ReadCrawlerUtil.getReadCrawler(source); ReadCrawler rc = ReadCrawlerUtil.getReadCrawler(source);
@ -346,17 +370,10 @@ public class BookDetailedActivity extends BaseActivity {
* 初始化其他书籍信息 * 初始化其他书籍信息
*/ */
private void initOtherInfo() { private void initOtherInfo() {
binding.ic.bookDetailTvDesc.setText("\t\t\t\t" + mBook.getDesc()); binding.ic.bookDetailTvDesc.setText(String.format("\t\t\t\t%s", mBook.getDesc()));
binding.ih.bookDetailTvType.setText(mBook.getType()); initTagList();
if (!App.isDestroy(this)) { if (!App.isDestroy(this)) {
binding.ih.bookDetailIvCover.load(mBook.getImgUrl(), mBook.getName(), mBook.getAuthor()); binding.ih.bookDetailIvCover.load(NetworkUtils.getAbsoluteURL(mReadCrawler.getNameSpace(), mBook.getImgUrl()), mBook.getName(), mBook.getAuthor());
/*Glide.with(this)
.load(mBook.getImgUrl())
.transition(DrawableTransitionOptions.withCrossFade(1500))
.thumbnail(defaultCover())
.centerCrop()
.apply(RequestOptions.bitmapTransform(new BlurTransformation(this, 25)))
.into(mIvBlurCover);*/
} }
} }

@ -90,6 +90,8 @@ public class SearchBookActivity extends BaseActivity {
private Menu menu; private Menu menu;
private AlertDialog mDisableSourceDia;
private static String[] suggestion = {"第一序列", "大道朝天", "伏天氏", "终极斗罗", "我师兄实在太稳健了", "烂柯棋缘", "诡秘之主"}; private static String[] suggestion = {"第一序列", "大道朝天", "伏天氏", "终极斗罗", "我师兄实在太稳健了", "烂柯棋缘", "诡秘之主"};
private static String[] suggestion2 = {"不朽凡人", "圣墟", "我是至尊", "龙王传说", "太古神王", "一念永恒", "雪鹰领主", "大主宰"}; private static String[] suggestion2 = {"不朽凡人", "圣墟", "我是至尊", "龙王传说", "太古神王", "一念永恒", "雪鹰领主", "大主宰"};
@ -295,7 +297,10 @@ public class SearchBookActivity extends BaseActivity {
@Override @Override
public boolean onPrepareOptionsMenu(Menu menu) { public boolean onPrepareOptionsMenu(Menu menu) {
if (!showHot) menu.findItem(R.id.action_hot).setVisible(true); if (!showHot) {
menu.findItem(R.id.action_hot).setVisible(true);
menu.findItem(R.id.action_disable_source).setVisible(true);
}
return super.onPrepareOptionsMenu(menu); return super.onPrepareOptionsMenu(menu);
} }
@ -304,7 +309,9 @@ public class SearchBookActivity extends BaseActivity {
if (item.getItemId() == R.id.action_hot) { if (item.getItemId() == R.id.action_hot) {
showHot = !showHot; showHot = !showHot;
initSuggestionList(); initSuggestionList();
} else if (item.getItemId() == R.id.action_source_man) { }else if (item.getItemId() == R.id.action_disable_source) {
showDisableSourceDia();
}else if (item.getItemId() == R.id.action_source_man) {
startActivityForResult(new Intent(this, BookSourceActivity.class), startActivityForResult(new Intent(this, BookSourceActivity.class),
APPCONST.REQUEST_BOOK_SOURCE); APPCONST.REQUEST_BOOK_SOURCE);
} else { } else {
@ -342,7 +349,7 @@ public class SearchBookActivity extends BaseActivity {
MenuItem localItem = menu.add(R.id.source_group, Menu.NONE, Menu.NONE, R.string.local_source); MenuItem localItem = menu.add(R.id.source_group, Menu.NONE, Menu.NONE, R.string.local_source);
if ("".equals(searchGroup)) { if ("".equals(searchGroup)) {
item.setChecked(true); item.setChecked(true);
}else if (getString(R.string.local_source).equals(searchGroup)){ } else if (getString(R.string.local_source).equals(searchGroup)) {
localItem.setChecked(true); localItem.setChecked(true);
} }
List<String> groupList = BookSourceManager.getEnableNoLocalGroupList(); List<String> groupList = BookSourceManager.getEnableNoLocalGroupList();
@ -353,7 +360,7 @@ public class SearchBookActivity extends BaseActivity {
menu.setGroupCheckable(R.id.source_group, true, true); menu.setGroupCheckable(R.id.source_group, true, true);
} }
/*private void showDisableSourceDia() { private void showDisableSourceDia() {
if (mDisableSourceDia != null) { if (mDisableSourceDia != null) {
mDisableSourceDia.show(); mDisableSourceDia.show();
return; return;
@ -394,7 +401,7 @@ public class SearchBookActivity extends BaseActivity {
} }
} }
}); });
}*/ }
/** /**
* 初始化建议书目 * 初始化建议书目
@ -517,28 +524,32 @@ public class SearchBookActivity extends BaseActivity {
*/ */
private void search() { private void search() {
binding.rpb.setIsAutoLoading(true); binding.rpb.setIsAutoLoading(true);
binding.fabSearchStop.setVisibility(View.VISIBLE);
if (StringHelper.isEmpty(searchKey)) { if (StringHelper.isEmpty(searchKey)) {
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.llSuggestBooksView.setVisibility(View.VISIBLE);
binding.fabSearchStop.setVisibility(View.GONE);
initHistoryList(); initHistoryList();
binding.rvSearchBooksList.setAdapter(null); binding.rvSearchBooksList.setAdapter(null);
binding.srlSearchBookList.setEnableRefresh(false); binding.srlSearchBookList.setEnableRefresh(false);
} else { } else {
mSearchBookAdapter = new SearchBookAdapter(mBooks, searchEngine, searchKey); mSearchBookAdapter = new SearchBookAdapter(this, mBooks, searchEngine, searchKey);
binding.rvSearchBooksList.setAdapter(mSearchBookAdapter); binding.rvSearchBooksList.setAdapter(mSearchBookAdapter);
//进入书籍详情页 //进入书籍详情页
mSearchBookAdapter.setOnItemClickListener((view, pos) -> { mSearchBookAdapter.setOnItemClickListener((view, pos) -> {
SearchBookBean data = mSearchBookAdapter.getItem(pos);
ArrayList<Book> books = (ArrayList<Book>) mBooks.getValues(data);
searchBookBean2Book(data, books.get(0));
Intent intent = new Intent(this, BookDetailedActivity.class); Intent intent = new Intent(this, BookDetailedActivity.class);
intent.putExtra(APPCONST.SEARCH_BOOK_BEAN, new ArrayList<>(mBooks.getValues(mSearchBookAdapter.getItem(pos)))); intent.putExtra(APPCONST.SEARCH_BOOK_BEAN, books);
startActivity(intent); startActivity(intent);
}); });
binding.srlSearchBookList.setEnableRefresh(true); binding.srlSearchBookList.setEnableRefresh(true);
binding.rvSearchBooksList.setVisibility(View.VISIBLE); binding.rvSearchBooksList.setVisibility(View.VISIBLE);
binding.llSuggestBooksView.setVisibility(View.GONE); binding.llSuggestBooksView.setVisibility(View.GONE);
binding.llHistoryView.setVisibility(View.GONE); binding.llHistoryView.setVisibility(View.GONE);
binding.fabSearchStop.setVisibility(View.VISIBLE);
getData(); getData();
mSearchHistoryService.addOrUpadteHistory(searchKey); mSearchHistoryService.addOrUpadteHistory(searchKey);
//收起软键盘 //收起软键盘
@ -570,4 +581,23 @@ public class SearchBookActivity extends BaseActivity {
} }
super.onDestroy(); super.onDestroy();
} }
private void searchBookBean2Book(SearchBookBean bean, Book book) {
if (StringHelper.isEmpty(book.getType()) && !StringHelper.isEmpty(bean.getType()))
book.setType(bean.getType());
if (StringHelper.isEmpty(book.getType()) && !StringHelper.isEmpty(bean.getType()))
book.setType(bean.getType());
if (StringHelper.isEmpty(book.getDesc()) && !StringHelper.isEmpty(bean.getDesc()))
book.setDesc(bean.getDesc());
if (StringHelper.isEmpty(book.getStatus()) && !StringHelper.isEmpty(bean.getStatus()))
book.setStatus(bean.getStatus());
if (StringHelper.isEmpty(book.getWordCount()) && !StringHelper.isEmpty(bean.getWordCount()))
book.setWordCount(bean.getWordCount());
if (StringHelper.isEmpty(book.getNewestChapterTitle()) && !StringHelper.isEmpty(bean.getLastChapter()))
book.setNewestChapterTitle(bean.getLastChapter());
if (StringHelper.isEmpty(book.getUpdateDate()) && !StringHelper.isEmpty(bean.getUpdateTime()))
book.setUpdateDate(bean.getUpdateTime());
if (StringHelper.isEmpty(book.getImgUrl()) && !StringHelper.isEmpty(bean.getImgUrl()))
book.setImgUrl(bean.getImgUrl());
}
} }

@ -0,0 +1,50 @@
package xyz.fycz.myreader.ui.adapter;
import android.content.Context;
import android.view.View;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import com.zhy.view.flowlayout.FlowLayout;
import com.zhy.view.flowlayout.TagAdapter;
import java.util.List;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.util.ToastUtils;
/**
* @author fengyue
* @date 2021/2/17 12:55
*/
public class BookTagAdapter extends TagAdapter<String> {
private TextView tvTagName;
private final Context context;
private final int textSize;
public BookTagAdapter(Context context, List<String> datas, int textSize) {
super(datas);
this.context = context;
this.textSize = textSize;
}
@Override
public View getView(FlowLayout parent, int position, String tagName) {
try {
tvTagName = (TextView) View.inflate(context, R.layout.item_book_tag, null);
tvTagName.setTextSize(textSize);
//默认为分类
if (tagName.startsWith("1:")) { //字数
tvTagName.setBackground(ContextCompat.getDrawable(context, R.drawable.tag_green_shape));
} else if (tagName.startsWith("2:")) {//连载状态
tvTagName.setBackground(ContextCompat.getDrawable(context, R.drawable.tag_red_shape));
}
tvTagName.setText(tagName.substring(2));
} catch (Exception e) {
e.printStackTrace();
ToastUtils.showError("" + e.getLocalizedMessage());
}
return tvTagName;
}
}

@ -16,6 +16,8 @@ import java.util.ArrayList;
import xyz.fycz.myreader.R; import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.App; import xyz.fycz.myreader.application.App;
import xyz.fycz.myreader.common.APPCONST; import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.greendao.entity.rule.BookSource;
import xyz.fycz.myreader.model.source.BookSourceManager;
import xyz.fycz.myreader.ui.activity.ReadActivity; import xyz.fycz.myreader.ui.activity.ReadActivity;
import xyz.fycz.myreader.ui.dialog.DialogCreator; import xyz.fycz.myreader.ui.dialog.DialogCreator;
import xyz.fycz.myreader.ui.dialog.MyAlertDialog; import xyz.fycz.myreader.ui.dialog.MyAlertDialog;
@ -24,6 +26,9 @@ import xyz.fycz.myreader.ui.activity.BookDetailedActivity;
import xyz.fycz.myreader.ui.presenter.BookcasePresenter; import xyz.fycz.myreader.ui.presenter.BookcasePresenter;
import xyz.fycz.myreader.util.StringHelper; import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.util.ToastUtils; import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.NetworkUtils;
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
/** /**
@ -66,7 +71,8 @@ public class BookcaseDetailedAdapter extends BookcaseAdapter {
if (StringHelper.isEmpty(book.getImgUrl())) { if (StringHelper.isEmpty(book.getImgUrl())) {
book.setImgUrl(""); book.setImgUrl("");
} }
viewHolder.ivBookImg.load(book.getImgUrl(), book.getName(),book.getAuthor()); ReadCrawler rc = ReadCrawlerUtil.getReadCrawler(book.getSource());
viewHolder.ivBookImg.load(NetworkUtils.getAbsoluteURL(rc.getNameSpace(), book.getImgUrl()), book.getName(),book.getAuthor());
viewHolder.tvBookName.setText(book.getName()); viewHolder.tvBookName.setText(book.getName());

@ -14,6 +14,8 @@ import java.util.ArrayList;
import xyz.fycz.myreader.R; import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.App; import xyz.fycz.myreader.application.App;
import xyz.fycz.myreader.common.APPCONST; import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.greendao.entity.rule.BookSource;
import xyz.fycz.myreader.model.source.BookSourceManager;
import xyz.fycz.myreader.ui.activity.ReadActivity; import xyz.fycz.myreader.ui.activity.ReadActivity;
import xyz.fycz.myreader.ui.dialog.DialogCreator; import xyz.fycz.myreader.ui.dialog.DialogCreator;
import xyz.fycz.myreader.ui.dialog.MyAlertDialog; import xyz.fycz.myreader.ui.dialog.MyAlertDialog;
@ -22,6 +24,9 @@ import xyz.fycz.myreader.ui.activity.BookDetailedActivity;
import xyz.fycz.myreader.ui.presenter.BookcasePresenter; import xyz.fycz.myreader.ui.presenter.BookcasePresenter;
import xyz.fycz.myreader.util.StringHelper; import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.util.ToastUtils; import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.NetworkUtils;
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
public class BookcaseDragAdapter extends BookcaseAdapter { public class BookcaseDragAdapter extends BookcaseAdapter {
@ -63,7 +68,8 @@ public class BookcaseDragAdapter extends BookcaseAdapter {
book.setImgUrl(""); book.setImgUrl("");
} }
viewHolder.ivBookImg.load(book.getImgUrl(), book.getName(),book.getAuthor()); ReadCrawler rc = ReadCrawlerUtil.getReadCrawler(book.getSource());
viewHolder.ivBookImg.load(NetworkUtils.getAbsoluteURL(rc.getNameSpace(), book.getImgUrl()), book.getName(),book.getAuthor());
viewHolder.tvBookName.setText(book.getName()); viewHolder.tvBookName.setText(book.getName());

@ -1,5 +1,6 @@
package xyz.fycz.myreader.ui.adapter; package xyz.fycz.myreader.ui.adapter;
import android.app.Activity;
import android.text.TextUtils; import android.text.TextUtils;
import xyz.fycz.myreader.application.App; import xyz.fycz.myreader.application.App;
@ -14,6 +15,7 @@ import xyz.fycz.myreader.ui.adapter.holder.SearchBookHolder;
import xyz.fycz.myreader.util.utils.StringUtils; import xyz.fycz.myreader.util.utils.StringUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
/** /**
@ -21,11 +23,13 @@ import java.util.List;
* @date 2020/10/2 10:08 * @date 2020/10/2 10:08
*/ */
public class SearchBookAdapter extends BaseListAdapter<SearchBookBean> { public class SearchBookAdapter extends BaseListAdapter<SearchBookBean> {
private Activity activity;
private ConcurrentMultiValueMap<SearchBookBean, Book> mBooks; private ConcurrentMultiValueMap<SearchBookBean, Book> mBooks;
private SearchEngine searchEngine; private SearchEngine searchEngine;
private String keyWord; private String keyWord;
public SearchBookAdapter(ConcurrentMultiValueMap<SearchBookBean, Book> mBooks, SearchEngine searchEngine, String keyWord) { public SearchBookAdapter(Activity activity, ConcurrentMultiValueMap<SearchBookBean, Book> mBooks, SearchEngine searchEngine, String keyWord) {
this.activity = activity;
this.mBooks = mBooks; this.mBooks = mBooks;
this.searchEngine = searchEngine; this.searchEngine = searchEngine;
this.keyWord = keyWord; this.keyWord = keyWord;
@ -33,7 +37,7 @@ public class SearchBookAdapter extends BaseListAdapter<SearchBookBean> {
@Override @Override
protected IViewHolder<SearchBookBean> createViewHolder(int viewType) { protected IViewHolder<SearchBookBean> createViewHolder(int viewType) {
return new SearchBookHolder(mBooks, searchEngine, keyWord); return new SearchBookHolder(activity, mBooks, searchEngine, keyWord);
} }
public void addAll(List<SearchBookBean> newDataS, String keyWord) { public void addAll(List<SearchBookBean> newDataS, String keyWord) {
@ -63,7 +67,7 @@ public class SearchBookAdapter extends BaseListAdapter<SearchBookBean> {
break; break;
} }
if (filterDataS != null && filterDataS.size() > 0) { if (filterDataS.size() > 0) {
List<SearchBookBean> searchBookBeansAdd = new ArrayList<>(); List<SearchBookBean> searchBookBeansAdd = new ArrayList<>();
if (copyDataS.size() == 0) { if (copyDataS.size() == 0) {
copyDataS.addAll(filterDataS); copyDataS.addAll(filterDataS);
@ -79,7 +83,6 @@ public class SearchBookAdapter extends BaseListAdapter<SearchBookBean> {
break; break;
} }
} }
if (!hasSame) { if (!hasSame) {
searchBookBeansAdd.add(temp); searchBookBeansAdd.add(temp);
} }
@ -107,6 +110,7 @@ public class SearchBookAdapter extends BaseListAdapter<SearchBookBean> {
} }
} }
} }
synchronized (this) { synchronized (this) {
App.runOnUiThread(() -> { App.runOnUiThread(() -> {
mList = copyDataS; mList = copyDataS;
@ -115,4 +119,47 @@ public class SearchBookAdapter extends BaseListAdapter<SearchBookBean> {
} }
} }
} }
private void sort(List<SearchBookBean> bookBeans) {
//排序,基于最符合关键字的搜书结果应该是最短的
//TODO ;这里只做了简单的比较排序,还需要继续完善
Collections.sort(bookBeans, (o1, o2) -> {
if (o1.getName().equals(keyWord))
return -1;
if (o2.getName().equals(keyWord))
return 1;
if (o1.getAuthor() != null && o1.getAuthor().equals(keyWord))
return -1;
if (o2.getAuthor() != null && o2.getAuthor().equals(keyWord))
return 1;
return Integer.compare(o1.getName().length(), o2.getName().length());
});
}
private int getAddIndex(List<SearchBookBean> beans, SearchBookBean bean) {
int maxWeight = 0;
int index = -1;
if (TextUtils.equals(keyWord, bean.getName())) {
maxWeight = 5;
}else if (TextUtils.equals(keyWord, bean.getAuthor())) {
maxWeight = 3;
}
for (int i = 0; i < beans.size(); i++) {
SearchBookBean searchBook = beans.get(i);
int weight = 0;
if (TextUtils.equals(bean.getName(), searchBook.getName())) {
weight = 4;
} else if (TextUtils.equals(bean.getAuthor(), searchBook.getAuthor())) {
weight = 2;
} else if (bean.getName().length() <= searchBook.getName().length()) {
weight = 1;
}
if (weight > maxWeight) {
index = i;
maxWeight = weight;
}
}
if (maxWeight == 5 || maxWeight == 3) index = 0;
return index;
}
} }

@ -8,8 +8,12 @@ import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.App; import xyz.fycz.myreader.application.App;
import xyz.fycz.myreader.base.adapter.ViewHolderImpl; import xyz.fycz.myreader.base.adapter.ViewHolderImpl;
import xyz.fycz.myreader.greendao.entity.Book; import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.rule.BookSource;
import xyz.fycz.myreader.model.source.BookSourceManager; import xyz.fycz.myreader.model.source.BookSourceManager;
import xyz.fycz.myreader.util.StringHelper; import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.util.utils.NetworkUtils;
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
import xyz.fycz.myreader.widget.CoverImageView; import xyz.fycz.myreader.widget.CoverImageView;
/** /**
@ -56,14 +60,16 @@ public class BookStoreBookHolder extends ViewHolderImpl<Book> {
tvBookNewestChapter.setText(StringHelper.isEmpty(data.getNewestChapterTitle()) ? tvBookNewestChapter.setText(StringHelper.isEmpty(data.getNewestChapterTitle()) ?
data.getDesc() : data.getNewestChapterTitle()); data.getDesc() : data.getNewestChapterTitle());
tvBookTime.setText(data.getUpdateDate()); tvBookTime.setText(data.getUpdateDate());
BookSource source = BookSourceManager.getBookSourceByStr(data.getSource());
ReadCrawler rc = ReadCrawlerUtil.getReadCrawler(source);
if (hasImg){ if (hasImg){
tvBookImg.setVisibility(View.VISIBLE); tvBookImg.setVisibility(View.VISIBLE);
if (!App.isDestroy(mActivity)) { if (!App.isDestroy(mActivity)) {
tvBookImg.load(data.getImgUrl(), data.getName(), data.getAuthor()); tvBookImg.load(NetworkUtils.getAbsoluteURL(rc.getNameSpace(), data.getImgUrl()), data.getName(), data.getAuthor());
} }
} }
if (data.getSource() != null) { if (data.getSource() != null) {
tvBookSource.setText(String.format("书源:%s", BookSourceManager.getSourceNameByStr(data.getSource()))); tvBookSource.setText(String.format("书源:%s", source.getSourceName()));
}else { }else {
tvBookSource.setText(data.getNewestChapterId()); tvBookSource.setText(data.getNewestChapterId());
} }

@ -8,7 +8,9 @@ import java.util.HashMap;
import xyz.fycz.myreader.R; import xyz.fycz.myreader.R;
import xyz.fycz.myreader.base.adapter.ViewHolderImpl; import xyz.fycz.myreader.base.adapter.ViewHolderImpl;
import xyz.fycz.myreader.greendao.GreenDaoManager;
import xyz.fycz.myreader.greendao.entity.rule.BookSource; import xyz.fycz.myreader.greendao.entity.rule.BookSource;
import xyz.fycz.myreader.model.source.BookSourceManager;
import xyz.fycz.myreader.util.StringHelper; import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.util.ToastUtils; import xyz.fycz.myreader.util.ToastUtils;
@ -47,10 +49,12 @@ public class LocalSourceHolder extends ViewHolderImpl<BookSource> {
tvEnable.setOnClickListener(v -> { tvEnable.setOnClickListener(v -> {
data.setEnable(true); data.setEnable(true);
banOrUse(data); banOrUse(data);
GreenDaoManager.getDaoSession().getBookSourceDao().insertOrReplace(data);
}); });
tvDisable.setOnClickListener(v -> { tvDisable.setOnClickListener(v -> {
data.setEnable(false); data.setEnable(false);
banOrUse(data); banOrUse(data);
GreenDaoManager.getDaoSession().getBookSourceDao().insertOrReplace(data);
}); });
tvCheck.setOnClickListener(v -> ToastUtils.showInfo("校验功能即将上线")); tvCheck.setOnClickListener(v -> ToastUtils.showInfo("校验功能即将上线"));
} }

@ -2,48 +2,66 @@ package xyz.fycz.myreader.ui.adapter.holder;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Activity; import android.app.Activity;
import android.os.Handler; import android.content.Intent;
import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.view.View;
import android.widget.TextView; import android.widget.TextView;
import androidx.core.content.ContextCompat;
import com.zhy.view.flowlayout.FlowLayout;
import com.zhy.view.flowlayout.TagAdapter;
import com.zhy.view.flowlayout.TagFlowLayout;
import java.util.ArrayList;
import java.util.List;
import xyz.fycz.myreader.R; import xyz.fycz.myreader.R;
import xyz.fycz.myreader.application.App; import xyz.fycz.myreader.application.App;
import xyz.fycz.myreader.base.adapter.ViewHolderImpl; import xyz.fycz.myreader.base.adapter.ViewHolderImpl;
import xyz.fycz.myreader.greendao.entity.rule.BookSource; import xyz.fycz.myreader.common.APPCONST;
import xyz.fycz.myreader.model.source.BookSourceManager;
import xyz.fycz.myreader.model.SearchEngine;
import xyz.fycz.myreader.entity.SearchBookBean; import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.greendao.entity.Book; import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.rule.BookSource;
import xyz.fycz.myreader.model.SearchEngine;
import xyz.fycz.myreader.model.mulvalmap.ConcurrentMultiValueMap; import xyz.fycz.myreader.model.mulvalmap.ConcurrentMultiValueMap;
import xyz.fycz.myreader.model.source.BookSourceManager;
import xyz.fycz.myreader.ui.activity.BookDetailedActivity;
import xyz.fycz.myreader.ui.adapter.BookTagAdapter;
import xyz.fycz.myreader.util.StringHelper; import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.util.ToastUtils;
import xyz.fycz.myreader.util.utils.KeyWordUtils; import xyz.fycz.myreader.util.utils.KeyWordUtils;
import xyz.fycz.myreader.util.utils.NetworkUtils;
import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil; import xyz.fycz.myreader.webapi.crawler.ReadCrawlerUtil;
import xyz.fycz.myreader.webapi.crawler.base.BookInfoCrawler; import xyz.fycz.myreader.webapi.crawler.base.BookInfoCrawler;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler; import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
import xyz.fycz.myreader.widget.CoverImageView; import xyz.fycz.myreader.widget.CoverImageView;
import java.util.List;
/** /**
* @author fengyue * @author fengyue
* @date 2020/10/2 10:10 * @date 2020/10/2 10:10
*/ */
public class SearchBookHolder extends ViewHolderImpl<SearchBookBean> { public class SearchBookHolder extends ViewHolderImpl<SearchBookBean> {
private Activity activity;
private ConcurrentMultiValueMap<SearchBookBean, Book> mBooks; private ConcurrentMultiValueMap<SearchBookBean, Book> mBooks;
private SearchEngine searchEngine; private SearchEngine searchEngine;
private String keyWord; private String keyWord;
private List<String> tagList = new ArrayList<>();
public SearchBookHolder(ConcurrentMultiValueMap<SearchBookBean, Book> mBooks, SearchEngine searchEngine, String keyWord) { public SearchBookHolder(Activity activity, ConcurrentMultiValueMap<SearchBookBean, Book> mBooks, SearchEngine searchEngine, String keyWord) {
this.activity = activity;
this.mBooks = mBooks; this.mBooks = mBooks;
this.searchEngine = searchEngine; this.searchEngine = searchEngine;
this.keyWord = keyWord; this.keyWord = keyWord;
} }
private CoverImageView ivBookImg; private CoverImageView ivBookImg;
private TextView tvBookName; private TextView tvBookName;
private TagFlowLayout tflBookTag;
private TextView tvDesc; private TextView tvDesc;
private TextView tvAuthor; private TextView tvAuthor;
private TextView tvType;
private TextView tvSource; private TextView tvSource;
private TextView tvNewestChapter; private TextView tvNewestChapter;
@ -56,9 +74,9 @@ public class SearchBookHolder extends ViewHolderImpl<SearchBookBean> {
public void initView() { public void initView() {
ivBookImg = findById(R.id.iv_book_img); ivBookImg = findById(R.id.iv_book_img);
tvBookName = findById(R.id.tv_book_name); tvBookName = findById(R.id.tv_book_name);
tflBookTag = findById(R.id.tfl_book_tag);
tvAuthor = findById(R.id.tv_book_author); tvAuthor = findById(R.id.tv_book_author);
tvDesc = findById(R.id.tv_book_desc); tvDesc = findById(R.id.tv_book_desc);
tvType = findById(R.id.tv_book_type);
tvSource = findById(R.id.tv_book_source); tvSource = findById(R.id.tv_book_source);
tvNewestChapter = findById(R.id.tv_book_newest_chapter); tvNewestChapter = findById(R.id.tv_book_newest_chapter);
} }
@ -70,64 +88,153 @@ public class SearchBookHolder extends ViewHolderImpl<SearchBookBean> {
List<Book> aBooks = mBooks.getValues(data); List<Book> aBooks = mBooks.getValues(data);
int bookCount = aBooks.size(); int bookCount = aBooks.size();
Book book = aBooks.get(0); Book book = aBooks.get(0);
if (StringHelper.isEmpty(book.getImgUrl())) { BookSource source = BookSourceManager.getBookSourceByStr(book.getSource());
book.setImgUrl(""); ReadCrawler rc = ReadCrawlerUtil.getReadCrawler(source);
books2SearchBookBean(data, aBooks);
if (!StringHelper.isEmpty(data.getImgUrl())) {
if (!App.isDestroy((Activity) getContext())) {
ivBookImg.load(NetworkUtils.getAbsoluteURL(rc.getNameSpace(), data.getImgUrl()), data.getName(), data.getAuthor());
} }
if (!StringHelper.isEmpty(book.getDesc())) {
tvDesc.setText("简介:" + book.getDesc());
} }
if (!StringHelper.isEmpty(book.getType())) { KeyWordUtils.setKeyWord(tvBookName, data.getName(), keyWord);
tvType.setText(book.getType()); if (!StringHelper.isEmpty(data.getAuthor())) {
KeyWordUtils.setKeyWord(tvAuthor, data.getAuthor(), keyWord);
} }
if (!StringHelper.isEmpty(book.getNewestChapterTitle())) { initTagList(data);
tvNewestChapter.setText(getContext().getString(R.string.newest_chapter, book.getNewestChapterTitle())); if (!StringHelper.isEmpty(data.getLastChapter())) {
tvNewestChapter.setText(getContext().getString(R.string.newest_chapter, data.getLastChapter()));
} }
if (!StringHelper.isEmpty(book.getAuthor())) { if (!StringHelper.isEmpty(data.getDesc())) {
KeyWordUtils.setKeyWord(tvAuthor, book.getAuthor(), keyWord); tvDesc.setText(String.format("简介:%s", data.getDesc()));
} }
KeyWordUtils.setKeyWord(tvBookName, book.getName(), keyWord);
BookSource source = BookSourceManager.getBookSourceByStr(book.getSource());
tvSource.setText(getContext().getString(R.string.source_title_num, source.getSourceName(), bookCount)); tvSource.setText(getContext().getString(R.string.source_title_num, source.getSourceName(), bookCount));
ReadCrawler rc = ReadCrawlerUtil.getReadCrawler(source); App.getHandler().postDelayed(() -> {
if (rc instanceof BookInfoCrawler) { if (needGetInfo(data) && rc instanceof BookInfoCrawler) {
if (tvBookName.getTag() == null || !(Boolean) tvBookName.getTag()) { if (tvBookName.getTag() == null || !(Boolean) tvBookName.getTag()) {
tvBookName.setTag(true); tvBookName.setTag(true);
} else { } else {
initOtherInfo(book); initOtherInfo(data, rc);
return; return;
} }
Log.i(book.getName(), "initOtherInfo"); Log.i(book.getName(), "initOtherInfo");
BookInfoCrawler bic = (BookInfoCrawler) rc; BookInfoCrawler bic = (BookInfoCrawler) rc;
searchEngine.getBookInfo(book, bic, isSuccess -> { searchEngine.getBookInfo(book, bic, isSuccess -> {
if (isSuccess) if (isSuccess) {
App.runOnUiThread(() -> initOtherInfo(book)); List<Book> books = new ArrayList<>();
else books.add(book);
books2SearchBookBean(data, books);
initOtherInfo(data, rc);
} else {
tvBookName.setTag(false); tvBookName.setTag(false);
}
}); });
} else {
initOtherInfo(book);
} }
}, 1000);
} }
private void initOtherInfo(Book book) { private void initOtherInfo(SearchBookBean book, ReadCrawler rc) {
//简介 //简介
if (StringHelper.isEmpty(tvDesc.getText().toString())) { if (StringHelper.isEmpty(tvDesc.getText().toString())) {
tvDesc.setText(String.format("简介:%s", book.getDesc())); tvDesc.setText(String.format("简介:%s", book.getDesc()));
} }
if (StringHelper.isEmpty(tvType.getText().toString())) {
tvType.setText(book.getType());
}
if (StringHelper.isEmpty(tvNewestChapter.getText().toString())) { if (StringHelper.isEmpty(tvNewestChapter.getText().toString())) {
tvNewestChapter.setText(getContext().getString(R.string.newest_chapter, book.getNewestChapterTitle())); tvNewestChapter.setText(getContext().getString(R.string.newest_chapter, book.getLastChapter()));
} }
if (StringHelper.isEmpty(tvAuthor.getText().toString())) { if (StringHelper.isEmpty(tvAuthor.getText().toString())) {
KeyWordUtils.setKeyWord(tvAuthor, book.getAuthor(), keyWord); KeyWordUtils.setKeyWord(tvAuthor, book.getAuthor(), keyWord);
} }
//图片 //图片
if (!App.isDestroy((Activity) getContext())) { if (!App.isDestroy((Activity) getContext())) {
ivBookImg.load(book.getImgUrl(), book.getName(), book.getAuthor()); ivBookImg.load(NetworkUtils.getAbsoluteURL(rc.getNameSpace(), book.getImgUrl()), book.getName(), book.getAuthor());
}
} }
private void initTagList(SearchBookBean data) {
tagList.clear();
String type = data.getType();
if (!StringHelper.isEmpty(type))
tagList.add("0:" + type);
String wordCount = data.getWordCount();
if (!StringHelper.isEmpty(wordCount))
tagList.add("1:" + wordCount);
String status = data.getStatus();
if (!StringHelper.isEmpty(status))
tagList.add("2:" + status);
tflBookTag.setAdapter(new BookTagAdapter(activity, tagList, 11));
} }
private void books2SearchBookBean(SearchBookBean bookBean, List<Book> books) {
for (Book book : books) {
if (!StringHelper.isEmpty(bookBean.getAuthor())) break;
String author = book.getAuthor();
if (!StringHelper.isEmpty(author)) {
bookBean.setAuthor(author);
break;
}
}
for (Book book : books) {
if (!StringHelper.isEmpty(bookBean.getType())) break;
String type = book.getType();
if (!StringHelper.isEmpty(type)) {
bookBean.setType(type);
break;
}
}
for (Book book : books) {
if (!StringHelper.isEmpty(bookBean.getDesc())) break;
String desc = book.getDesc();
if (!StringHelper.isEmpty(desc)) {
bookBean.setDesc(desc);
break;
}
}
for (Book book : books) {
if (!StringHelper.isEmpty(bookBean.getStatus())) break;
String status = book.getStatus();
if (!StringHelper.isEmpty(status)) {
bookBean.setStatus(status);
break;
}
}
for (Book book : books) {
if (!StringHelper.isEmpty(bookBean.getWordCount())) break;
String wordCount = book.getWordCount();
if (!StringHelper.isEmpty(wordCount)) {
bookBean.setWordCount(wordCount);
break;
}
}
for (Book book : books) {
if (!StringHelper.isEmpty(bookBean.getLastChapter())) break;
String lastChapter = book.getNewestChapterTitle();
if (!StringHelper.isEmpty(lastChapter)) {
bookBean.setLastChapter(lastChapter);
break;
}
}
for (Book book : books) {
if (!StringHelper.isEmpty(bookBean.getUpdateTime())) break;
String updateTime = book.getUpdateDate();
if (!StringHelper.isEmpty(updateTime)) {
bookBean.setUpdateTime(updateTime);
break;
}
}
for (Book book : books) {
if (!StringHelper.isEmpty(bookBean.getImgUrl())) break;
String imgUrl = book.getImgUrl();
if (!StringHelper.isEmpty(imgUrl)) {
bookBean.setImgUrl(imgUrl);
break;
}
}
}
private boolean needGetInfo(SearchBookBean bookBean) {
if (StringHelper.isEmpty(bookBean.getAuthor())) return true;
if (StringHelper.isEmpty(bookBean.getType())) return true;
if (StringHelper.isEmpty(bookBean.getDesc())) return true;
if (StringHelper.isEmpty(bookBean.getLastChapter())) return true;
return StringHelper.isEmpty(bookBean.getImgUrl());
}
} }

@ -392,7 +392,7 @@ public class DIYSourceFragment extends BaseFragment {
for (BookSource source : mBookSources) { for (BookSource source : mBookSources) {
source.setEnable(!source.getEnable()); source.setEnable(!source.getEnable());
} }
BookSourceManager.saveDatas(mBookSources); GreenDaoManager.getDaoSession().getBookSourceDao().insertOrReplaceInTx(mBookSources);
mAdapter.notifyDataSetChanged(); mAdapter.notifyDataSetChanged();
} }

@ -1,30 +1,23 @@
package xyz.fycz.myreader.webapi; package xyz.fycz.myreader.webapi;
import android.util.Log; import java.util.List;
import io.reactivex.Observable; import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.annotations.NonNull;
import okhttp3.MediaType; import okhttp3.MediaType;
import okhttp3.RequestBody; import okhttp3.RequestBody;
import xyz.fycz.myreader.common.URLCONST; import xyz.fycz.myreader.common.URLCONST;
import xyz.fycz.myreader.entity.SearchBookBean; import xyz.fycz.myreader.entity.SearchBookBean;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.Chapter; import xyz.fycz.myreader.greendao.entity.Chapter;
import xyz.fycz.myreader.model.mulvalmap.ConcurrentMultiValueMap; import xyz.fycz.myreader.model.mulvalmap.ConcurrentMultiValueMap;
import xyz.fycz.myreader.util.StringHelper; import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.util.utils.NetworkUtils; import xyz.fycz.myreader.util.utils.NetworkUtils;
import xyz.fycz.myreader.util.utils.OkHttpUtils; import xyz.fycz.myreader.util.utils.OkHttpUtils;
import xyz.fycz.myreader.webapi.callback.ResultCallback; import xyz.fycz.myreader.webapi.callback.ResultCallback;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.webapi.crawler.base.BookInfoCrawler; import xyz.fycz.myreader.webapi.crawler.base.BookInfoCrawler;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler; import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
import xyz.fycz.myreader.webapi.crawler.read.FYReadCrawler; import xyz.fycz.myreader.webapi.crawler.read.FYReadCrawler;
import xyz.fycz.myreader.webapi.crawler.read.TianLaiReadCrawler; import xyz.fycz.myreader.webapi.crawler.read.TianLaiReadCrawler;
import xyz.fycz.myreader.webapi.crawler.read.YanQingLouReadCrawler;
import java.io.IOException;
import java.util.List;
public class CommonApi extends BaseApi { public class CommonApi extends BaseApi {

@ -52,7 +52,7 @@ public class ReadCrawlerUtil {
sb.deleteCharAt(sb.lastIndexOf(",")); sb.deleteCharAt(sb.lastIndexOf(","));
searchSource = sb.toString(); searchSource = sb.toString();
spu.putString(App.getmContext().getString(R.string.searchSource), searchSource); spu.putString(App.getmContext().getString(R.string.searchSource), searchSource);
} else if (!"".equals(searchSource)){ } else if (!"".equals(searchSource)) {
String[] sources = searchSource.split(","); String[] sources = searchSource.split(",");
for (String source : sources) { for (String source : sources) {
readCrawlers.add(getReadCrawler(source)); readCrawlers.add(getReadCrawler(source));
@ -61,7 +61,7 @@ public class ReadCrawlerUtil {
return readCrawlers; return readCrawlers;
} }
public static List<String> getAllSources(){ public static List<String> getAllSources() {
List<String> sources = new ArrayList<>(); List<String> sources = new ArrayList<>();
for (LocalBookSource bookSource : LocalBookSource.values()) { for (LocalBookSource bookSource : LocalBookSource.values()) {
if (bookSource.equals(LocalBookSource.fynovel)) if (bookSource.equals(LocalBookSource.fynovel))
@ -77,14 +77,16 @@ public class ReadCrawlerUtil {
HashMap<CharSequence, Boolean> mSources = new LinkedHashMap<>(); HashMap<CharSequence, Boolean> mSources = new LinkedHashMap<>();
if (searchSource == null) { if (searchSource == null) {
for (LocalBookSource bookSource : LocalBookSource.values()) { for (LocalBookSource bookSource : LocalBookSource.values()) {
if (bookSource.equals(LocalBookSource.fynovel) || bookSource.equals(LocalBookSource.local)) continue; if (bookSource.equals(LocalBookSource.fynovel) || bookSource.equals(LocalBookSource.local))
continue;
mSources.put(bookSource.text, false); mSources.put(bookSource.text, false);
} }
} else { } else {
String[] ableSources = searchSource.split(","); String[] ableSources = searchSource.split(",");
bookSourceFor: bookSourceFor:
for (LocalBookSource bookSource : LocalBookSource.values()) { for (LocalBookSource bookSource : LocalBookSource.values()) {
if (bookSource.equals(LocalBookSource.fynovel) || bookSource.equals(LocalBookSource.local)) continue; if (bookSource.equals(LocalBookSource.fynovel) || bookSource.equals(LocalBookSource.local))
continue;
for (String ableSource : ableSources) { for (String ableSource : ableSources) {
if (ableSource.equals(bookSource.toString())) { if (ableSource.equals(bookSource.toString())) {
mSources.put(bookSource.text, false); mSources.put(bookSource.text, false);
@ -97,7 +99,7 @@ public class ReadCrawlerUtil {
return mSources; return mSources;
} }
public static void resetReadCrawlers(){ public static void resetReadCrawlers() {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (LocalBookSource bookSource : LocalBookSource.values()) { for (LocalBookSource bookSource : LocalBookSource.values()) {
if (bookSource.equals(LocalBookSource.fynovel) || bookSource.equals(LocalBookSource.local)) if (bookSource.equals(LocalBookSource.fynovel) || bookSource.equals(LocalBookSource.local))
@ -109,22 +111,22 @@ public class ReadCrawlerUtil {
SharedPreUtils.getInstance().putString(App.getmContext().getString(R.string.searchSource), sb.toString()); SharedPreUtils.getInstance().putString(App.getmContext().getString(R.string.searchSource), sb.toString());
} }
public synchronized static void addReadCrawler(LocalBookSource... bookSources){ public synchronized static void addReadCrawler(LocalBookSource... bookSources) {
SharedPreUtils spu = SharedPreUtils.getInstance(); SharedPreUtils spu = SharedPreUtils.getInstance();
String searchSource = spu.getString(App.getmContext().getString(R.string.searchSource)); String searchSource = spu.getString(App.getmContext().getString(R.string.searchSource));
if ("".equals(searchSource)){ if ("".equals(searchSource)) {
resetReadCrawlers(); resetReadCrawlers();
return; return;
} }
StringBuilder sb = new StringBuilder(searchSource); StringBuilder sb = new StringBuilder(searchSource);
for (LocalBookSource bookSource : bookSources){ for (LocalBookSource bookSource : bookSources) {
sb.append(","); sb.append(",");
sb.append(bookSource.toString()); sb.append(bookSource.toString());
} }
SharedPreUtils.getInstance().putString(App.getmContext().getString(R.string.searchSource), sb.toString()); SharedPreUtils.getInstance().putString(App.getmContext().getString(R.string.searchSource), sb.toString());
} }
public synchronized static void removeReadCrawler(String... bookSources){ public synchronized static void removeReadCrawler(String... bookSources) {
SharedPreUtils spu = SharedPreUtils.getInstance(); SharedPreUtils spu = SharedPreUtils.getInstance();
String searchSource = spu.getString(App.getmContext().getString(R.string.searchSource), null); String searchSource = spu.getString(App.getmContext().getString(R.string.searchSource), null);
if (searchSource == null) { if (searchSource == null) {
@ -141,7 +143,7 @@ public class ReadCrawlerUtil {
} }
} }
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (String ableSource : ableSources){ for (String ableSource : ableSources) {
if ("".equals(ableSource)) continue; if ("".equals(ableSource)) continue;
sb.append(ableSource); sb.append(ableSource);
sb.append(","); sb.append(",");
@ -172,11 +174,13 @@ public class ReadCrawlerUtil {
} }
public static ReadCrawler getReadCrawler(BookSource source) { public static ReadCrawler getReadCrawler(BookSource source) {
try {
if (StringHelper.isEmpty(source.getSourceEName())) { if (StringHelper.isEmpty(source.getSourceEName())) {
BaseSourceCrawler crawler; BaseSourceCrawler crawler;
if (source.getSourceType() == null) source.setSourceType(MATCHER); if (source.getSourceType() == null) source.setSourceType(MATCHER);
switch (source.getSourceType()){ switch (source.getSourceType()) {
case MATCHER: default: case MATCHER:
default:
crawler = new MatcherCrawler(source); crawler = new MatcherCrawler(source);
break; break;
case XPATH: case XPATH:
@ -191,27 +195,27 @@ public class ReadCrawlerUtil {
} else { } else {
return new BaseSourceCrawlerNoInfo(crawler); return new BaseSourceCrawlerNoInfo(crawler);
} }
}else { } else {
try {
Class clz = Class.forName(source.getSourceUrl()); Class clz = Class.forName(source.getSourceUrl());
return (ReadCrawler) clz.newInstance(); return (ReadCrawler) clz.newInstance();
}
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
return new FYReadCrawler(); return new FYReadCrawler();
} }
} }
}
public static List<ReadCrawler> getEnableReadCrawlers(){ public static List<ReadCrawler> getEnableReadCrawlers() {
return getEnableReadCrawlers(""); return getEnableReadCrawlers("");
} }
public static List<ReadCrawler> getEnableReadCrawlers(String group){ public static List<ReadCrawler> getEnableReadCrawlers(String group) {
List<ReadCrawler> crawlers = new ArrayList<>(); List<ReadCrawler> crawlers = new ArrayList<>();
List<BookSource> sources = TextUtils.isEmpty(group) ? List<BookSource> sources = TextUtils.isEmpty(group) ?
BookSourceManager.getEnabledBookSource() : BookSourceManager.getEnabledBookSource() :
BookSourceManager.getEnableSourceByGroup(group); BookSourceManager.getEnableSourceByGroup(group);
for (BookSource source : sources){ for (BookSource source : sources) {
crawlers.add(getReadCrawler(source)); crawlers.add(getReadCrawler(source));
} }
return crawlers; return crawlers;

@ -97,7 +97,6 @@ public abstract class BaseSourceCrawler implements ReadCrawler, BookInfoCrawler
List<String> imgs = analyzer.getStringList(searchRule.getImgUrl(), obj); List<String> imgs = analyzer.getStringList(searchRule.getImgUrl(), obj);
List<String> chapterUrls = analyzer.getStringList(searchRule.getTocUrl(), obj); List<String> chapterUrls = analyzer.getStringList(searchRule.getTocUrl(), obj);
List<String> infoUrls = analyzer.getStringList(searchRule.getInfoUrl(), obj); List<String> infoUrls = analyzer.getStringList(searchRule.getInfoUrl(), obj);
String baseUrl = getNameSpace();
for (int i = 0; i < names.size(); i++) { for (int i = 0; i < names.size(); i++) {
Book book = new Book(); Book book = new Book();
book.setName(names.get(i)); book.setName(names.get(i));
@ -110,11 +109,11 @@ public abstract class BaseSourceCrawler implements ReadCrawler, BookInfoCrawler
if (lastChapters.size() > i) book.setNewestChapterTitle(lastChapters.get(i)); if (lastChapters.size() > i) book.setNewestChapterTitle(lastChapters.get(i));
if (updateTimes.size() > i) book.setUpdateDate(updateTimes.get(i)); if (updateTimes.size() > i) book.setUpdateDate(updateTimes.get(i));
if (imgs.size() > i) if (imgs.size() > i)
book.setImgUrl(NetworkUtils.getAbsoluteURL(baseUrl, imgs.get(i))); book.setImgUrl(imgs.get(i));
if (chapterUrls.size() > i) if (chapterUrls.size() > i)
book.setChapterUrl(NetworkUtils.getAbsoluteURL(baseUrl, chapterUrls.get(i))); book.setChapterUrl(chapterUrls.get(i));
if (infoUrls.size() > i) if (infoUrls.size() > i)
book.setInfoUrl(NetworkUtils.getAbsoluteURL(baseUrl, infoUrls.get(i))); book.setInfoUrl(infoUrls.get(i));
SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor()); SearchBookBean sbb = new SearchBookBean(book.getName(), book.getAuthor());
books.add(sbb, book); books.add(sbb, book);
} }
@ -161,7 +160,7 @@ public abstract class BaseSourceCrawler implements ReadCrawler, BookInfoCrawler
book.setStatus(status); book.setStatus(status);
book.setNewestChapterTitle(lastChapter); book.setNewestChapterTitle(lastChapter);
book.setUpdateDate(updateTime); book.setUpdateDate(updateTime);
book.setImgUrl(NetworkUtils.getAbsoluteURL(getNameSpace(), imgUrl)); book.setImgUrl(imgUrl);
book.setChapterUrl(tocUrl); book.setChapterUrl(tocUrl);
book.setInfoUrl(infoUrl); book.setInfoUrl(infoUrl);
book.setSource(source.getSourceUrl()); book.setSource(source.getSourceUrl());
@ -171,6 +170,8 @@ public abstract class BaseSourceCrawler implements ReadCrawler, BookInfoCrawler
} }
} }
/** /**
* 获取章节列表 * 获取章节列表
* *
@ -332,7 +333,7 @@ public abstract class BaseSourceCrawler implements ReadCrawler, BookInfoCrawler
if (StringHelper.isEmpty(book.getUpdateDate())) if (StringHelper.isEmpty(book.getUpdateDate()))
book.setUpdateDate(analyzer.getString(infoRule.getUpdateTime(), obj)); book.setUpdateDate(analyzer.getString(infoRule.getUpdateTime(), obj));
if (StringHelper.isEmpty(book.getImgUrl())) if (StringHelper.isEmpty(book.getImgUrl()))
book.setImgUrl(NetworkUtils.getAbsoluteURL(getNameSpace(), analyzer.getString(infoRule.getImgUrl(), obj))); book.setImgUrl(analyzer.getString(infoRule.getImgUrl(), obj));
if (StringHelper.isEmpty(book.getChapterUrl())) if (StringHelper.isEmpty(book.getChapterUrl()))
book.setChapterUrl(analyzer.getString(infoRule.getTocUrl(), obj)); book.setChapterUrl(analyzer.getString(infoRule.getTocUrl(), obj));
return book; return book;

@ -15,6 +15,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.Chapter; import xyz.fycz.myreader.greendao.entity.Chapter;
import xyz.fycz.myreader.greendao.service.ChapterService; import xyz.fycz.myreader.greendao.service.ChapterService;
import xyz.fycz.myreader.util.StringHelper;
import xyz.fycz.myreader.util.utils.FileUtils; import xyz.fycz.myreader.util.utils.FileUtils;
import xyz.fycz.myreader.webapi.CommonApi; import xyz.fycz.myreader.webapi.CommonApi;
import xyz.fycz.myreader.webapi.callback.ResultCallback; import xyz.fycz.myreader.webapi.callback.ResultCallback;
@ -225,7 +226,9 @@ public class NetPageLoader extends PageLoader {
@Override @Override
public void onFinish(final Object o, int code) { public void onFinish(final Object o, int code) {
loadingChapters.remove(chapter); loadingChapters.remove(chapter);
mChapterService.saveOrUpdateChapter(chapter, (String) o); String content = (String) o;
if (StringHelper.isEmpty(content)) content = "章节内容为空";
mChapterService.saveOrUpdateChapter(chapter, content);
if (isClose()) return; if (isClose()) return;
if (getPageStatus() == PageLoader.STATUS_LOADING && mCurChapterPos == chapter.getNumber()) { if (getPageStatus() == PageLoader.STATUS_LOADING && mCurChapterPos == chapter.getNumber()) {
App.runOnUiThread(() -> { App.runOnUiThread(() -> {

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="3dp"/>
<solid android:color="@color/toast_blue"/>
<padding android:left="2dp"
android:right="2dp"/>
</shape>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="3dp"/>
<solid android:color="@color/toast_green"/>
<padding android:left="2dp"
android:right="2dp"/>
</shape>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="3dp"/>
<solid android:color="@color/toast_red"/>
<padding android:left="2dp"
android:right="2dp"/>
</shape>

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:text="@string/rule_book_type"
android:background="@drawable/tag_blue_shape"
tools:ignore="RtlSymmetry,SmallSp">
</TextView>

@ -35,34 +35,33 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignTop="@+id/cover" android:layout_alignTop="@+id/cover"
android:layout_marginLeft="14dp" android:layout_marginStart="14dp"
android:layout_marginTop="30dp" android:layout_marginTop="30dp"
android:layout_toRightOf="@+id/cover" android:layout_toEndOf="@+id/cover"
android:ellipsize="end" android:ellipsize="end"
android:maxLines="1" android:maxLines="1"
android:textColor="@color/origin" android:textColor="@color/origin"
tools:text=" 茶叶蛋" /> tools:text=" 茶叶蛋" />
<TextView
android:id="@+id/book_detail_tv_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/book_detail_tv_author"
android:layout_alignLeft="@id/book_detail_tv_author"
android:layout_marginTop="6dp"
android:ellipsize="end"
android:maxLines="1"
android:textColor="@color/textSecondaryInverted"
tools:text="仙侠" />
<com.zhy.view.flowlayout.TagFlowLayout
android:id="@+id/tfl_book_tag"
android:layout_below="@+id/book_detail_tv_author"
android:layout_alignStart="@id/book_detail_tv_author"
android:layout_marginTop="2dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:max_select="0"
app:tag_gravity="left" />
<TextView <TextView
android:id="@+id/book_detail_source" android:id="@+id/book_detail_source"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_below="@id/book_detail_tv_type" android:layout_below="@id/tfl_book_tag"
android:layout_alignLeft="@id/book_detail_tv_type" android:layout_alignStart="@id/tfl_book_tag"
android:layout_marginTop="6dp" android:layout_marginTop="2dp"
android:textColor="@color/textSecondaryInverted" android:textColor="@color/textSecondaryInverted"
tools:text="书源" /> tools:text="书源" />

@ -1,97 +1,92 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" xmlns:tools="http://schemas.android.com/tools" android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="@color/colorBackground" android:background="@color/colorBackground"
android:orientation="horizontal"
android:padding="5dp"> android:padding="5dp">
<xyz.fycz.myreader.widget.CoverImageView <xyz.fycz.myreader.widget.CoverImageView
android:id="@+id/iv_book_img" android:id="@+id/iv_book_img"
android:layout_width="64dp" android:layout_width="76dp"
android:layout_height="88dp" android:layout_height="104dp"
android:scaleType="fitXY" android:scaleType="fitXY"
app:srcCompat="@mipmap/default_cover" /> app:srcCompat="@mipmap/default_cover" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="5dp"
android:padding="3dp">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical"> android:layout_marginStart="5dp"
android:orientation="vertical"
android:paddingStart="3dp"
android:paddingEnd="3dp">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="horizontal"> android:orientation="horizontal">
<TextView <TextView
android:id="@+id/tv_book_name" android:id="@+id/tv_book_name"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="24dp" android:layout_height="24dp"
android:layout_marginTop="5dp"
tools:text="bookname"
android:maxLength="12" android:maxLength="12"
android:textSize="16sp" android:textColor="@color/textPrimary"
android:textColor="@color/textPrimary"/> android:textSize="@dimen/text_normal_size"
tools:text="bookname" />
<TextView <TextView
android:id="@+id/tv_book_author" android:id="@+id/tv_book_author"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingStart="5dp"
android:layout_marginTop="6dp"
tools:text="author"
android:maxLines="1" android:maxLines="1"
android:textSize="13sp" android:paddingStart="5dp"
android:textColor="@color/textSecondary"/> android:textColor="@color/textSecondary"
android:textSize="@dimen/text_default_size"
tools:text="author" />
</LinearLayout> </LinearLayout>
<com.zhy.view.flowlayout.TagFlowLayout
android:id="@+id/tfl_book_tag"
android:layout_width="match_parent"
android:layout_height="20dp"
android:layout_marginTop="-6dp"
app:max_select="0"
app:tag_gravity="left" />
<TextView <TextView
android:id="@+id/tv_book_newest_chapter" android:id="@+id/tv_book_newest_chapter"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingBottom="1dp"
tools:text="newest_chapter"
android:maxLines="1" android:maxLines="1"
android:textSize="13sp" android:paddingTop="2dp"
android:textColor="@color/textSecondary"/> android:textColor="@color/textSecondary"
android:textSize="@dimen/text_default_size"
tools:text="newest_chapter" />
<TextView <TextView
android:id="@+id/tv_book_desc" android:id="@+id/tv_book_desc"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingBottom="2dp"
tools:text="book desc"
android:ellipsize="end" android:ellipsize="end"
android:maxLines="1" android:maxLines="2"
android:textSize="13sp" android:textColor="@color/textSecondary"
android:textColor="@color/textSecondary"/> android:textSize="@dimen/text_default_size"
</LinearLayout> tools:text="book desc" />
<TextView
android:id="@+id/tv_book_type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
tools:text="type"
android:maxLines="1"
android:textSize="13sp"
android:textColor="@color/textSecondary"/>
<TextView <TextView
android:id="@+id/tv_book_source" android:id="@+id/tv_book_source"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:paddingTop="3dp"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
tools:text="book source"
android:maxLines="1" android:maxLines="1"
android:textSize="13sp" android:textColor="@color/textSecondary"
android:textColor="@color/textSecondary"/> android:textSize="@dimen/text_default_size"
</RelativeLayout> tools:text="book source" />
</LinearLayout>
</LinearLayout> </LinearLayout>

@ -5,8 +5,12 @@
android:id="@+id/action_hot" android:id="@+id/action_hot"
android:title="@string/hot_search" android:title="@string/hot_search"
android:visible="false" android:visible="false"
app:showAsAction="always" />
<item
android:id="@+id/action_disable_source"
android:title="@string/disable_source"
android:visible="false"
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />
<item <item
android:id="@+id/action_source_man" android:id="@+id/action_source_man"
android:title="@string/book_source_man" android:title="@string/book_source_man"

@ -46,19 +46,6 @@ public class Test {
System.out.println(sb.toString()); System.out.println(sb.toString());
} }
@org.junit.Test
public void testRegex() throws UnsupportedEncodingException {
String str = new String(FileUtils.getBytes(new File("D:\\Java\\Project\\FYReader-master\\app\\src\\test\\resources\\html.html")), "GBK");
MatcherAnalyzer analyzer = new MatcherAnalyzer();
String ruleList = "<div id=\"content\"><text><div class=\"footer\">";
String list = analyzer.getInnerText(ruleList, str);
String rule = "(*)<td class=\"odd\"><a href=\".*\"><text></a></td>";
List<String> listStr = analyzer.matcherInnerText(rule, list);
for (String s : listStr) {
System.out.println(s);
}
}
@org.junit.Test @org.junit.Test
public void testUrl() { public void testUrl() {
@ -73,4 +60,30 @@ public class Test {
JXDocument jxDoc = JXDocument.create(str); JXDocument jxDoc = JXDocument.create(str);
System.out.println(jxDoc.selNOne("//*[@id=\"intro\"]/p[1]/text()")); System.out.println(jxDoc.selNOne("//*[@id=\"intro\"]/p[1]/text()"));
} }
@org.junit.Test
public void testBean() {
String[] strings = "type;desc;status;wordCount;lastChapter;updateTime;imgUrl".split(";");
String[] strings1 = new String[strings.length];
for (int i = 0, stringsLength = strings.length; i < stringsLength; i++) {
String s = strings[i];
strings1[i] = s.substring(0, 1).toUpperCase() + s.substring(1);
}
for (int i = 0; i < strings.length; i++) {
String s = strings[i];
/*String str =
" for (Book book : books){\n" +
" String "+ s + " = book.get" + strings1[i] + "();\n" +
" if (!StringHelper.isEmpty(bookBean.get" + strings1[i] + "())) break;\n" +
" if (!StringHelper.isEmpty("+ s + ")){\n" +
" bookBean.set" + strings1[i] + "("+ s + ");\n" +
" break;\n" +
" }\n" +
" }";*/
String str =
" if (StringHelper.isEmpty(book.get" + strings1[i] + "()) && !StringHelper.isEmpty(bean.get" + strings1[i] + "()))\n" +
" book.set" + strings1[i] + "(bean.get" + strings1[i] + "());";
System.out.println(str);
}
}
} }

@ -1,2 +1,2 @@
#Tue Feb 16 22:03:51 CST 2021 #Mon Mar 01 20:09:11 CST 2021
VERSION_CODE=190 VERSION_CODE=191

Loading…
Cancel
Save