Merge branch 'master' into dev

pull/21/head
fengyuecanzhu 3 years ago
commit cd3f548d1a
  1. 5
      .idea/misc.xml
  2. 4
      README.md
  3. 8
      app/release.md
  4. 8
      app/src/main/assets/updatelog.fy
  5. 4
      app/src/main/java/xyz/fycz/myreader/model/sourceAnalyzer/BookSourceManager.java
  6. 6
      app/src/main/java/xyz/fycz/myreader/ui/activity/AboutActivity.java
  7. 2
      app/src/main/java/xyz/fycz/myreader/ui/activity/ReadActivity.java
  8. 258
      app/src/main/java/xyz/fycz/myreader/ui/activity/SearchBookActivity.java
  9. 9
      app/src/main/java/xyz/fycz/myreader/ui/activity/SourceEditActivity.java
  10. 6
      app/src/main/java/xyz/fycz/myreader/ui/fragment/MineFragment.java
  11. 3
      app/src/main/java/xyz/fycz/myreader/ui/presenter/BookcasePresenter.java
  12. 65
      app/src/main/java/xyz/fycz/myreader/widget/TagGroup.java
  13. 150
      app/src/main/java/xyz/fycz/myreader/widget/explosion_field/ExplosionAnimator.java
  14. 200
      app/src/main/java/xyz/fycz/myreader/widget/explosion_field/ExplosionField.java
  15. 8
      app/src/main/java/xyz/fycz/myreader/widget/explosion_field/OnAnimatorListener.java
  16. 72
      app/src/main/java/xyz/fycz/myreader/widget/explosion_field/Utils.java
  17. 168
      app/src/main/res/layout/activity_search_book.xml
  18. 37
      app/src/main/res/layout/layout_about_content.xml
  19. 5
      app/src/main/res/menu/menu_source_edit.xml
  20. 3
      app/src/main/res/values/colors.xml
  21. 8
      app/src/main/res/values/strings.xml
  22. 1
      app/src/main/res/values/styles.xml
  23. 4
      app/version_code.properties

@ -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_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_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/dialog_loading.xml" value="0.1" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/dialog_textview.xml" value="0.1947463768115942" />
@ -41,7 +41,7 @@
<entry key="..\:/android/FYReader/app/src/main/res/layout/item_search_word1.xml" value="0.2889273356401384" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/item_search_word2.xml" value="0.1947463768115942" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/item_search_word_1.xml" value="0.1947463768115942" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/layout_about_content.xml" value="0.12132725430597771" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/layout_about_content.xml" value="0.176" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/layout_book_detail_header.xml" value="0.536" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/listview_search_book_item.xml" value="0.22010869565217392" />
<entry key="..\:/android/FYReader/app/src/main/res/layout/search_book_item.xml" value="0.1947463768115942" />
@ -52,6 +52,7 @@
<entry key="..\:/android/FYReader/app/src/main/res/menu/menu_read.xml" value="0.24947916666666667" />
<entry key="..\:/android/FYReader/app/src/main/res/menu/menu_rule.xml" value="0.24947916666666667" />
<entry key="..\:/android/FYReader/app/src/main/res/menu/menu_search_word.xml" value="0.1425925925925926" />
<entry key="..\:/android/FYReader/app/src/main/res/menu/menu_source_edit.xml" value="0.2815533980582524" />
</map>
</option>
</component>

@ -22,9 +22,9 @@
</table>
* 官网:[https://reader.fycz.tk](https://reader.fycz.tk)
* 反馈交流:
* 反馈交流:
* QQ群:[1085028304](https://jq.qq.com/?_wv=1027&k=6pcq8YBk)
* Telegram:[https://t.me/FYReader](https://t.me/FYReader)
* QQ频道:[点击加入](https://qun.qq.com/qqweb/qunpro/share?_wv=3&_wwv=128&inviteCode=2aP6ZQ&from=246610&biz=ka)
* [更新日志](./app/src/main/assets/updatelog.fy)
* [免责声明](./app/src/main/assets/disclaimer.fy)

@ -1,3 +1,5 @@
* 1、开放用户登录\注册入口及同步书架(在v1.9.3版本关闭),感谢[@黑白人生]提供的服务器
* 2、新增邮箱验证(用于找回密码),之前注册的帐号登录时需要绑定邮箱
* 3、webdav同步书架改为从webdav恢复
* 1、修复部分机型阅读界面切换日夜间闪退的问题
* 2、优化搜索界面
* 3、搜索界面新增书架书籍搜索
* 4、修复朗读到章节最后一页停止的问题
* 5、新增QQ频道,建议反馈请到QQ频道进行

@ -1,7 +1,11 @@
2022.01.07
2022.01.17
风月读书v2.3.2
更新内容:
1、修复MIUI13阅读界面切换日夜间闪退的问题
1、修复部分机型阅读界面切换日夜间闪退的问题
2、优化搜索界面
3、搜索界面新增书架书籍搜索
4、修复朗读到章节最后一页停止的问题
5、新增QQ频道,建议反馈请到QQ频道进行
2021.12.11
风月读书v2.2.8

@ -192,6 +192,10 @@ public class BookSourceManager {
DbManager.getDaoSession().getBookSourceDao().deleteInTx(sources);
}
public static boolean isBookSourceExist(BookSource source){
if (source == null) return false;
return DbManager.getDaoSession().getBookSourceDao().load(source.getSourceUrl()) != null;
}
public static String getBookSourceSort() {
switch (SharedPreUtils.getInstance().getInt("SourceSort", 0)) {

@ -96,6 +96,12 @@ public class AboutActivity extends BaseActivity {
mClipboardManager.setPrimaryClip(mClipData);
ToastUtils.showSuccess("邮箱\"fengyuecanzhu@gmail.com\"已复制到剪切板");
});
binding.il.rlJoinQqChannel.setOnClickListener(v -> {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://qun.qq.com/qqweb/qunpro/share?_wv=3&_wwv=128&inviteCode=2aP6ZQ&from=246610&biz=ka"));
startActivity(intent);
});
binding.il.rlShareLog.setOnClickListener(v -> DialogCreator.createCommonDialog(this, "分享崩溃日志",
"你是希望将日志上传到服务器,还是直接分享给他人?", true,
"上传服务器", "直接分享", (dialog, which) -> uploadCrashLog(), (dialog, which) -> shareCrashLog()));

@ -419,8 +419,10 @@ public class ReadActivity extends BaseActivity implements ColorPickerDialogListe
pagePos = pos;
saveLastChapterReadPosition();
}
mHandler.post(()->{
screenOffTimerStart();
initMenu();
});
recordReadTime();
if (ReadAloudService.running) {
if (mPageLoader.hasChapterData(mChapters.get(mPageLoader.getChapterPos()))) {

@ -49,6 +49,7 @@ import xyz.fycz.myreader.entity.Setting;
import xyz.fycz.myreader.greendao.entity.Book;
import xyz.fycz.myreader.greendao.entity.SearchHistory;
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.model.SearchEngine;
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.webapi.crawler.ReadCrawlerUtil;
import xyz.fycz.myreader.webapi.crawler.base.ReadCrawler;
import xyz.fycz.myreader.widget.TagGroup;
/**
* @author fengyue
@ -76,14 +78,17 @@ public class SearchBookActivity extends BaseActivity {
private SearchAdapter mSearchBookAdapter;
private String searchKey;//搜索关键字
private List<SearchHistory> mSearchHistories = new ArrayList<>();
private List<CharSequence> mSuggestions = new ArrayList<>();
private List<CharSequence> mHotKeys = new ArrayList<>();
private List<SearchHistory> mSearchHistories;
private List<SearchHistory> mCurHistories = 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 SearchHistoryAdapter mSearchHistoryAdapter;
private int allThreadCount;
private SearchEngine searchEngine;
@ -96,13 +101,20 @@ public class SearchBookActivity extends BaseActivity {
private Disposable sugDis;
private boolean showBooks;
private Disposable hisDis;
private Disposable caseDis;
private boolean showBooks;
private static String[] suggestion = {"第一序列", "大道朝天", "伏天氏", "终极斗罗", "我师兄实在太稳健了", "烂柯棋缘", "诡秘之主", "不朽凡人", "圣墟", "我是至尊", "龙王传说", "太古神王", "一念永恒", "雪鹰领主", "大主宰"};
private boolean showHot;
private boolean foldBookcase;
private boolean foldSuggest;
private boolean foldHistory;
private boolean needReGetHistory;
@Override
protected void bindView() {
@ -120,7 +132,7 @@ public class SearchBookActivity extends BaseActivity {
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
if (hasFocus && binding.etSearchKey.getText().length() == 0){
if (hasFocus && binding.etSearchKey.getText().length() == 0) {
App.getHandler().postDelayed(() -> {
binding.etSearchKey.requestFocus();
InputMethodManager imm = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE);
@ -134,7 +146,12 @@ public class SearchBookActivity extends BaseActivity {
super.initData(savedInstanceState);
mSetting = SysManager.getSetting();
mSearchHistoryService = SearchHistoryService.getInstance();
mBooks = BookService.getInstance().getAllBooksNoHide();
showHot = !App.isDebug();
foldBookcase = SharedPreUtils.getInstance().getBoolean("foldBookcase");
foldSuggest = SharedPreUtils.getInstance().getBoolean("foldSuggest");
foldHistory = SharedPreUtils.getInstance().getBoolean("foldHistory");
needReGetHistory = true;
searchEngine = new SearchEngine();
searchEngine.setOnSearchListener(new SearchEngine.OnSearchListener() {
@Override
@ -189,18 +206,13 @@ public class SearchBookActivity extends BaseActivity {
}
binding.rgSearchFilter.setOnCheckedChangeListener((group, checkedId) -> {
int searchFilter;
switch (checkedId) {
case R.id.rb_all_search:
default:
int searchFilter = 0;
if (checkedId == R.id.rb_all_search) {
searchFilter = 0;
break;
case R.id.rb_fuzzy_search:
} else if (checkedId == R.id.rb_fuzzy_search) {
searchFilter = 1;
break;
case R.id.rb_precise_search:
} else if (checkedId == R.id.rb_precise_search) {
searchFilter = 2;
break;
}
mSetting.setSearchFilter(searchFilter);
SysManager.saveSetting(mSetting);
@ -225,6 +237,8 @@ public class SearchBookActivity extends BaseActivity {
if (StringHelper.isEmpty(searchKey)) {
search();
}
searchBookcase();
initHistoryList();
initSuggestionList();
}
@ -237,6 +251,32 @@ public class SearchBookActivity extends BaseActivity {
stopSearch();
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();
}
@ -244,35 +284,43 @@ public class SearchBookActivity extends BaseActivity {
protected void initClick() {
super.initClick();
//换一批点击事件
binding.llRefreshSuggestBooks.setOnClickListener(new RenewSuggestionBook());
//搜索按钮点击事件
binding.tvSearchConform.setOnClickListener(view -> search());
//suggestion搜索事件
binding.tgSuggestBook.setOnTagClickListener(tag -> {
binding.tgSuggestBook.setOnTagClickListener((tag, pos) -> {
binding.etSearchKey.setText(tag);
binding.etSearchKey.setSelection(tag.length());
search();
});
//历史记录搜索事件
binding.lvHistoryList.setOnItemClickListener((parent, view, position, id) -> {
binding.etSearchKey.setText(mSearchHistories.get(position).getContent());
binding.etSearchKey.setSelection(mSearchHistories.get(position).getContent().length());
binding.tgHistoryBooks.setOnTagClickListener((tag, pos) -> {
binding.etSearchKey.setText(tag);
binding.etSearchKey.setSelection(tag.length());
search();
});
//清空历史记录
binding.llClearHistory.setOnClickListener(v -> {
binding.tvClearHistory.setOnClickListener(v -> {
DialogCreator.createCommonDialog(this, "清除搜索记录", "确定要清除全部搜索记录吗?",
true, (dialog, which) -> {
mSearchHistoryService.clearHistory();
initHistoryList();
}, null);
});
//清除单个历史记录
binding.lvHistoryList.setOnItemLongClickListener((parent, view, position, id) -> {
if (mSearchHistories.get(position) != null) {
mSearchHistoryService.deleteHistory(mSearchHistories.get(position));
initHistoryList();
binding.tgHistoryBooks.setLongClickDelete(true);
binding.tgHistoryBooks.setOnTagChangeListener(new TagGroup.OnTagChangeListener() {
@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));
mSearchHistories.remove(mCurHistories.get(pos));
}
}
return true;
});
binding.fabSearchStop.setOnClickListener(v -> {
@ -445,7 +493,6 @@ public class SearchBookActivity extends BaseActivity {
initSuggestionList();
}
});
;
}
}
@ -460,11 +507,10 @@ public class SearchBookActivity extends BaseActivity {
mSuggestions.clear();
if (StringHelper.isEmpty(searchKey)) {
if (mHotKeys.isEmpty()) {
binding.llSuggestBooksView.setVisibility(View.GONE);
binding.llSuggestBook.setVisibility(View.GONE);
} else {
binding.llSuggestBooksView.setVisibility(View.VISIBLE);
binding.llRefreshSuggestBooks.setVisibility(View.VISIBLE);
binding.tgSuggestBook.setTags2(mHotKeys.subList(0, mHotKeys.size() / 2));
binding.llSuggestBook.setVisibility(View.VISIBLE);
binding.tgSuggestBook.setTags2(mHotKeys);
}
} else {
String url = "https://newzxautocmp.reader.qq.com/BookSuggAll?key=" + searchKey;
@ -480,13 +526,18 @@ public class SearchBookActivity extends BaseActivity {
@Override
public void onSuccess(@NotNull String 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);
}
@Override
public void onError(Throwable e) {
binding.llSuggestBooksView.setVisibility(View.GONE);
binding.llSuggestBook.setVisibility(View.GONE);
}
});
}
@ -527,32 +578,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() {
if (hisDis != null) {
hisDis.dispose();
}
Single.create((SingleOnSubscribe<Boolean>) emitter -> {
mSearchHistories = mSearchHistoryService.findAllSearchHistory();
mHistoryNames.clear();
mCurHistories.clear();
if (mSearchHistories == null || mSearchHistories.size() == 0) {
binding.llHistoryView.setVisibility(View.GONE);
emitter.onSuccess(false);
} else {
if (StringHelper.isEmpty(searchKey)) {
mCurHistories.addAll(mSearchHistories);
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 {
mSearchHistoryAdapter = new SearchHistoryAdapter(this, R.layout.listview_search_history_item, mSearchHistories);
binding.lvHistoryList.setAdapter(mSearchHistoryAdapter);
binding.llHistoryView.setVisibility(View.VISIBLE);
binding.llHistoryBooks.setVisibility(View.GONE);
}
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
binding.llHistoryBooks.setVisibility(View.GONE);
}
});
}
/**
@ -561,9 +645,67 @@ public class SearchBookActivity extends BaseActivity {
private void initSearchList() {
//initmBooksBean();
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 +737,7 @@ public class SearchBookActivity extends BaseActivity {
stopSearch();
binding.rpb.setIsAutoLoading(false);
binding.rvSearchBooksList.setVisibility(View.GONE);
binding.llSuggestBooksView.setVisibility(View.VISIBLE);
binding.llPreKeys.setVisibility(View.VISIBLE);
binding.fabSearchStop.setVisibility(View.GONE);
initHistoryList();
binding.rvSearchBooksList.setAdapter(null);
@ -606,11 +748,11 @@ public class SearchBookActivity extends BaseActivity {
binding.rvSearchBooksList.setAdapter(mSearchBookAdapter);
binding.srlSearchBookList.setEnableRefresh(true);
binding.rvSearchBooksList.setVisibility(View.VISIBLE);
binding.llSuggestBooksView.setVisibility(View.GONE);
binding.llHistoryView.setVisibility(View.GONE);
binding.llPreKeys.setVisibility(View.GONE);
binding.fabSearchStop.setVisibility(View.VISIBLE);
getData();
mSearchHistoryService.addOrUpadteHistory(searchKey);
needReGetHistory = true;
//收起软键盘
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(binding.etSearchKey.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);

@ -185,6 +185,15 @@ public class SourceEditActivity extends BaseActivity {
} else if (item.getItemId() == R.id.action_clear_cookie) {
DbManager.getDaoSession().getCookieBeanDao().deleteByKey(getSource().getSourceUrl());
ToastUtils.showSuccess("Cookie清除成功");
} else if (item.getItemId() == R.id.action_delete) {
if (BookSourceManager.isBookSourceExist(source)) {
BookSourceManager.removeBookSource(source);
setResult(Activity.RESULT_OK);
ToastUtils.showSuccess("书源删除成功");
finish();
} else {
ToastUtils.showWarring("当前书源暂未保存,无法删除");
}
}
return super.onOptionsItemSelected(item);
}

@ -4,6 +4,7 @@ import static android.app.Activity.RESULT_OK;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@ -389,8 +390,9 @@ public class MineFragment extends BaseFragment {
});
binding.mineRlFeedback.setOnClickListener(v -> {
Intent intent = new Intent(getContext(), FeedbackActivity.class);
getActivity().startActivity(intent);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("https://qun.qq.com/qqweb/qunpro/share?_wv=3&_wwv=128&inviteCode=2aP6ZQ&from=246610&biz=ka"));
startActivity(intent);
});
binding.mineRlDonate.setOnClickListener(v -> startActivity(new Intent(getActivity(), DonateActivity.class)));

@ -999,12 +999,15 @@ public class BookcasePresenter implements BasePresenter {
if (!isAutoSyn) {
DialogCreator.createTipDialog(mMainActivity, "成功将书架同步至网络!");
}
} else if (result.getCode() == 216) {
ToastUtils.showWarring("当前应用版本过旧,同步书架失败,请更新应用后重试");
} else {
if (!isAutoSyn) {
DialogCreator.createTipDialog(mMainActivity, "同步失败,请重试!");
}
}
}
@Override
public void onError(Throwable e) {
if (!isAutoSyn) {

@ -1,5 +1,6 @@
package xyz.fycz.myreader.widget;
import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
@ -32,6 +33,7 @@ import java.util.ArrayList;
import java.util.List;
import xyz.fycz.myreader.R;
import xyz.fycz.myreader.widget.explosion_field.ExplosionField;
/**
* A <code>TagGroup</code> is a special layout with a set of tags.
@ -70,6 +72,9 @@ public class TagGroup extends ViewGroup {
private final float default_horizontal_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. */
private boolean isAppendMode;
@ -136,6 +141,8 @@ public class TagGroup extends ViewGroup {
/** Listener used to handle tag click event. */
private InternalTagClickListener mInternalTagClickListener = new InternalTagClickListener();
private ExplosionField mExplosionField;
public TagGroup(Context context) {
this(context, null);
}
@ -156,6 +163,7 @@ public class TagGroup extends ViewGroup {
// Load styled attributes.
final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TagGroup, defStyleAttr, R.style.TagGroup);
try {
isLongClickDelete = a.getBoolean(R.styleable.TagGroup_atg_isLongClickDelete, false);
isAppendMode = a.getBoolean(R.styleable.TagGroup_atg_isAppendMode, false);
inputHint = a.getText(R.styleable.TagGroup_atg_inputHint);
borderColor = a.getColor(R.styleable.TagGroup_atg_borderColor, default_border_color);
@ -193,6 +201,18 @@ public class TagGroup extends ViewGroup {
}
}
@Override
protected void onAttachedToWindow() {
mExplosionField = ExplosionField.attach2Window((Activity) getContext());
super.onAttachedToWindow();
}
@Override
protected void onDetachedFromWindow() {
mExplosionField.clear();
super.onDetachedFromWindow();
}
/**
* Call this to submit the INPUT tag.
*/
@ -492,8 +512,15 @@ public class TagGroup extends ViewGroup {
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.setOnLongClickListener(v -> {
if (isLongClickDelete) {
deleteTag(newInputTag);
return true;
}
return false;
});
addView(newInputTag);
}
@ -503,8 +530,15 @@ public class TagGroup extends ViewGroup {
* @param tag the tag to append.
*/
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.setOnLongClickListener(v -> {
if (isLongClickDelete) {
deleteTag(newTag);
return true;
}
return false;
});
addView(newTag);
}
@ -532,10 +566,19 @@ public class TagGroup extends ViewGroup {
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) {
mExplosionField.explode(tagView);
removeView(tagView);
if (mOnTagChangeListener != null) {
mOnTagChangeListener.onDelete(TagGroup.this, tagView.getText().toString());
mOnTagChangeListener.onDelete(TagGroup.this, tagView.getText().toString(), tagView.pos);
}
}
@ -555,7 +598,7 @@ public class TagGroup extends ViewGroup {
*
* @param tag the deleted tag.
*/
void onDelete(TagGroup tagGroup, String tag);
void onDelete(TagGroup tagGroup, String tag, int pos);
}
/**
@ -567,7 +610,7 @@ public class TagGroup extends ViewGroup {
*
* @param tag The tag text of the tag that was clicked.
*/
void onTagClick(String tag);
void onTagClick(String tag, int pos);
}
/**
@ -630,6 +673,7 @@ public class TagGroup extends ViewGroup {
* The tag view click listener for internal use.
*/
class InternalTagClickListener implements OnClickListener {
@Override
public void onClick(View v) {
final TagView tag = (TagView) v;
@ -656,7 +700,7 @@ public class TagGroup extends ViewGroup {
}
} else {
if (mOnTagClickListener != null) {
mOnTagClickListener.onTagClick(tag.getText().toString());
mOnTagClickListener.onTagClick(tag.getText().toString(), tag.pos);
}
}
}
@ -669,6 +713,9 @@ public class TagGroup extends ViewGroup {
public static final int STATE_NORMAL = 1;
public static final int STATE_INPUT = 2;
/** The position in the group. */
private int pos = -1;
/** The offset to the text. */
private static final int CHECKED_MARKER_OFFSET = 3;
@ -724,8 +771,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);
this.pos = pos;
setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding);
setLayoutParams(new LayoutParams(
LayoutParams.WRAP_CONTENT,
@ -788,7 +836,7 @@ public class TagGroup extends ViewGroup {
if (lastNormalTagView.isChecked) {
removeView(lastNormalTagView);
if (mOnTagChangeListener != null) {
mOnTagChangeListener.onDelete(TagGroup.this, lastNormalTagView.getText().toString());
mOnTagChangeListener.onDelete(TagGroup.this, lastNormalTagView.getText().toString(), pos);
}
} else {
final TagView checkedTagView = getCheckedTag();
@ -1003,6 +1051,7 @@ public class TagGroup extends ViewGroup {
}
break;
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP: {
isPressed = false;
invalidatePaint();

@ -0,0 +1,150 @@
/*
* Copyright (C) 2015 tyrantgit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package xyz.fycz.myreader.widget.explosion_field;
import android.animation.ValueAnimator;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Interpolator;
import java.util.Random;
public class ExplosionAnimator extends ValueAnimator {
static long DEFAULT_DURATION = 0x400;
private static final Interpolator DEFAULT_INTERPOLATOR = new AccelerateInterpolator(0.6f);
private static final float END_VALUE = 1.4f;
private static final float X = Utils.dp2Px(5);
private static final float Y = Utils.dp2Px(20);
private static final float V = Utils.dp2Px(2);
private static final float W = Utils.dp2Px(1);
private Paint mPaint;
private Particle[] mParticles;
private Rect mBound;
private View mContainer;
public ExplosionAnimator(View container, Bitmap bitmap, Rect bound) {
mPaint = new Paint();
mBound = new Rect(bound);
int partLen = 15;
mParticles = new Particle[partLen * partLen];
Random random = new Random(System.currentTimeMillis());
int w = bitmap.getWidth() / (partLen + 2);
int h = bitmap.getHeight() / (partLen + 2);
for (int i = 0; i < partLen; i++) {
for (int j = 0; j < partLen; j++) {
mParticles[(i * partLen) + j] = generateParticle(bitmap.getPixel((j + 1) * w, (i + 1) * h), random);
}
}
mContainer = container;
setFloatValues(0f, END_VALUE);
setInterpolator(DEFAULT_INTERPOLATOR);
setDuration(DEFAULT_DURATION);
}
private Particle generateParticle(int color, Random random) {
Particle particle = new Particle();
particle.color = color;
particle.radius = V;
if (random.nextFloat() < 0.2f) {
particle.baseRadius = V + ((X - V) * random.nextFloat());
} else {
particle.baseRadius = W + ((V - W) * random.nextFloat());
}
float nextFloat = random.nextFloat();
particle.top = mBound.height() * ((0.18f * random.nextFloat()) + 0.2f);
particle.top = nextFloat < 0.2f ? particle.top : particle.top + ((particle.top * 0.2f) * random.nextFloat());
particle.bottom = (mBound.height() * (random.nextFloat() - 0.5f)) * 1.8f;
float f = nextFloat < 0.2f ? particle.bottom : nextFloat < 0.8f ? particle.bottom * 0.6f : particle.bottom * 0.3f;
particle.bottom = f;
particle.mag = 4.0f * particle.top / particle.bottom;
particle.neg = (-particle.mag) / particle.bottom;
f = mBound.centerX() + (Y * (random.nextFloat() - 0.5f));
particle.baseCx = f;
particle.cx = f;
f = mBound.centerY() + (Y * (random.nextFloat() - 0.5f));
particle.baseCy = f;
particle.cy = f;
particle.life = END_VALUE / 10 * random.nextFloat();
particle.overflow = 0.4f * random.nextFloat();
particle.alpha = 1f;
return particle;
}
public boolean draw(Canvas canvas) {
if (!isStarted()) {
return false;
}
for (Particle particle : mParticles) {
particle.advance((float) getAnimatedValue());
if (particle.alpha > 0f) {
mPaint.setColor(particle.color);
mPaint.setAlpha((int) (Color.alpha(particle.color) * particle.alpha));
canvas.drawCircle(particle.cx, particle.cy, particle.radius, mPaint);
}
}
mContainer.invalidate();
return true;
}
@Override
public void start() {
super.start();
mContainer.invalidate(mBound);
}
private class Particle {
float alpha;
int color;
float cx;
float cy;
float radius;
float baseCx;
float baseCy;
float baseRadius;
float top;
float bottom;
float mag;
float neg;
float life;
float overflow;
public void advance(float factor) {
float f = 0f;
float normalization = factor / END_VALUE;
if (normalization < life || normalization > 1f - overflow) {
alpha = 0f;
return;
}
normalization = (normalization - life) / (1f - life - overflow);
float f2 = normalization * END_VALUE;
if (normalization >= 0.7f) {
f = (normalization - 0.7f) / 0.3f;
}
alpha = 1f - f;
f = bottom * f2;
cx = baseCx + f;
cy = (float) (baseCy - this.neg * Math.pow(f, 2.0)) - f * mag;
radius = V + (baseRadius - V) * f2;
}
}
}

@ -0,0 +1,200 @@
/*
* Copyright (C) 2015 tyrantgit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package xyz.fycz.myreader.widget.explosion_field;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.media.MediaPlayer;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
public class ExplosionField extends View {
private long customDuration = ExplosionAnimator.DEFAULT_DURATION;
private int idPlayAnimationEffect = 0;
private OnAnimatorListener mZAnimatorListener;
private OnClickListener mOnClickListener;
private List<ExplosionAnimator> mExplosions = new ArrayList<>();
private int[] mExpandInset = new int[2];
public ExplosionField(Context context) {
super(context);
init();
}
public ExplosionField(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ExplosionField(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
Arrays.fill(mExpandInset, Utils.dp2Px(32));
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (ExplosionAnimator explosion : mExplosions) {
explosion.draw(canvas);
}
}
public void playSoundAnimationEffect(int id) {
this.idPlayAnimationEffect = id;
}
public void setCustomDuration(long customDuration) {
this.customDuration = customDuration;
}
public void addActionEvent(OnAnimatorListener ievents) {
this.mZAnimatorListener = ievents;
}
public void expandExplosionBound(int dx, int dy) {
mExpandInset[0] = dx;
mExpandInset[1] = dy;
}
public void explode(Bitmap bitmap, Rect bound, long startDelay) {
explode(bitmap, bound, startDelay, null);
}
public void explode(Bitmap bitmap, Rect bound, long startDelay, final View view) {
long currentDuration = customDuration;
final ExplosionAnimator explosion = new ExplosionAnimator(this, bitmap, bound);
explosion.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mExplosions.remove(animation);
if (view != null) {
view.setScaleX(1);
view.setScaleY(1);
view.setAlpha(1);
view.setOnClickListener(mOnClickListener);//set event
}
}
});
explosion.setStartDelay(startDelay);
explosion.setDuration(currentDuration);
mExplosions.add(explosion);
explosion.start();
}
public void explode(View view) {
explode(view, false);
}
public void explode(final View view, Boolean restartState) {
Rect r = new Rect();
view.getGlobalVisibleRect(r);
int[] location = new int[2];
getLocationOnScreen(location);
// getLocationInWindow(location);
// view.getLocationInWindow(location);
r.offset(-location[0], -location[1]);
r.inset(-mExpandInset[0], -mExpandInset[1]);
int startDelay = 100;
ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f).setDuration(150);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
Random random = new Random();
@Override
public void onAnimationUpdate(ValueAnimator animation) {
view.setTranslationX((random.nextFloat() - 0.5f) * view.getWidth() * 0.05f);
view.setTranslationY((random.nextFloat() - 0.5f) * view.getHeight() * 0.05f);
}
});
animator.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animator) {
if (idPlayAnimationEffect != 0)
MediaPlayer.create(getContext(), idPlayAnimationEffect).start();
}
@Override
public void onAnimationEnd(Animator animator) {
if (mZAnimatorListener != null) {
mZAnimatorListener.onAnimationEnd(animator, ExplosionField.this);
}
}
@Override
public void onAnimationCancel(Animator animator) {
Log.i("PRUEBA", "CANCEL");
}
@Override
public void onAnimationRepeat(Animator animator) {
Log.i("PRUEBA", "REPEAT");
}
});
animator.start();
view.animate().setDuration(150).setStartDelay(startDelay).scaleX(0f).scaleY(0f).alpha(0f).start();
if (restartState)
explode(Utils.createBitmapFromView(view), r, startDelay, view);
else
explode(Utils.createBitmapFromView(view), r, startDelay);
}
public void clear() {
mExplosions.clear();
invalidate();
}
public static ExplosionField attach2Window(Activity activity) {
ViewGroup rootView = (ViewGroup) activity.findViewById(Window.ID_ANDROID_CONTENT);
ExplosionField explosionField = new ExplosionField(activity);
rootView.addView(explosionField, new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
return explosionField;
}
public void setOnClickListener(OnClickListener mOnClickListener) {
this.mOnClickListener = mOnClickListener;
}
}

@ -0,0 +1,8 @@
package xyz.fycz.myreader.widget.explosion_field;
import android.animation.Animator;
import android.view.View;
public interface OnAnimatorListener {
void onAnimationEnd(Animator animator, View view);
}

@ -0,0 +1,72 @@
/*
* Copyright (C) 2015 tyrantgit
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package xyz.fycz.myreader.widget.explosion_field;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.view.View;
import android.widget.ImageView;
public class Utils {
private Utils() {
}
private static final float DENSITY = Resources.getSystem().getDisplayMetrics().density;
private static final Canvas sCanvas = new Canvas();
public static int dp2Px(int dp) {
return Math.round(dp * DENSITY);
}
public static Bitmap createBitmapFromView(View view) {
if (view instanceof ImageView) {
Drawable drawable = ((ImageView) view).getDrawable();
if (drawable != null && drawable instanceof BitmapDrawable) {
return ((BitmapDrawable) drawable).getBitmap();
}
}
view.clearFocus();
Bitmap bitmap = createBitmapSafely(view.getWidth(),
view.getHeight(), Bitmap.Config.ARGB_8888, 1);
if (bitmap != null) {
synchronized (sCanvas) {
Canvas canvas = sCanvas;
canvas.setBitmap(bitmap);
view.draw(canvas);
canvas.setBitmap(null);
}
}
return bitmap;
}
public static Bitmap createBitmapSafely(int width, int height, Bitmap.Config config, int retryCount) {
try {
return Bitmap.createBitmap(width, height, config);
} catch (OutOfMemoryError e) {
e.printStackTrace();
if (retryCount > 0) {
System.gc();
return createBitmapSafely(width, height, config, retryCount - 1);
}
return null;
}
}
}

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

@ -15,8 +15,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorForeground"
android:orientation="vertical"
>
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
@ -200,6 +199,31 @@
app:tint="@color/textSecondary" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/rl_join_qq_channel"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@drawable/selector_common_bg"
android:gravity="center"
android:paddingStart="20dp"
android:paddingEnd="10dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:text="@string/join_qq_channel"
android:textColor="@color/textPrimary"
android:textSize="@dimen/text_normal_size" />
<androidx.appcompat.widget.AppCompatImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
app:srcCompat="@drawable/ic_right_arrow"
app:tint="@color/textSecondary" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/rl_contact_author"
@ -227,6 +251,11 @@
app:tint="@color/textSecondary" />
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="10dp" />
<RelativeLayout
android:id="@+id/rl_share_log"
android:layout_width="match_parent"
@ -253,10 +282,6 @@
app:tint="@color/textSecondary" />
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="10dp" />
<RelativeLayout
android:id="@+id/rl_privacy_policy"
android:layout_width="match_parent"

@ -38,4 +38,9 @@
android:title="@string/clear_cookie"
app:showAsAction="never" />
<item
android:id="@+id/action_delete"
android:title="@string/delete"
app:showAsAction="never" />
</menu>

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

@ -108,6 +108,7 @@
<string name="this_github_url">https://github.com/fengyuecanzhu/FYReader</string>
<string name="update">检查更新</string>
<string name="thanks">致谢名单</string>
<string name="join_qq_channel">加入QQ频道</string>
<!--file system-->
@ -150,7 +151,7 @@
<string name="common_search">搜索</string>
<string name="theme_mode">主题模式</string>
<string name="join_qq_group">加入QQ群</string>
<string name="mine_feedback">建议反馈</string>
<string name="mine_feedback">建议反馈(QQ频道)</string>
<string name="menu_change_group">分组切换</string>
<string name="menu_group_man">分组管理</string>
<string name="menu_group_setting">设置分组</string>
@ -519,6 +520,11 @@
<string name="clear_result">清除搜索结果</string>
<string name="get_email_code">发送验证码</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>
<!--error string start-->

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

@ -1,3 +1,3 @@
#Fri Jun 18 21:45:31 CST 2021
VERSION_CODE=231
NEED_CREATE_RELEASE=false
VERSION_CODE=232
NEED_CREATE_RELEASE=true

Loading…
Cancel
Save